Blame view

drivers/regulator/lp3971.c 11.6 KB
0cbdf7bce   Marek Szyprowski   LP3971 PMIC regul...
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
  /*
   * Regulator driver for National Semiconductors LP3971 PMIC chip
   *
   *  Copyright (C) 2009 Samsung Electronics
   *  Author: Marek Szyprowski <m.szyprowski@samsung.com>
   *
   * Based on wm8350.c
   *
   * This program is free software; you can redistribute it and/or modify
   * it under the terms of the GNU General Public License version 2 as
   * published by the Free Software Foundation.
   *
   */
  
  #include <linux/bug.h>
  #include <linux/err.h>
  #include <linux/i2c.h>
  #include <linux/kernel.h>
65602c32e   Paul Gortmaker   regulator: Add mo...
19
  #include <linux/module.h>
0cbdf7bce   Marek Szyprowski   LP3971 PMIC regul...
20
21
  #include <linux/regulator/driver.h>
  #include <linux/regulator/lp3971.h>
5a0e3ad6a   Tejun Heo   include cleanup: ...
22
  #include <linux/slab.h>
0cbdf7bce   Marek Szyprowski   LP3971 PMIC regul...
23
24
25
26
27
  
  struct lp3971 {
  	struct device *dev;
  	struct mutex io_lock;
  	struct i2c_client *i2c;
0cbdf7bce   Marek Szyprowski   LP3971 PMIC regul...
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
  };
  
  static u8 lp3971_reg_read(struct lp3971 *lp3971, u8 reg);
  static int lp3971_set_bits(struct lp3971 *lp3971, u8 reg, u16 mask, u16 val);
  
  #define LP3971_SYS_CONTROL1_REG 0x07
  
  /* System control register 1 initial value,
     bits 4 and 5 are EPROM programmable */
  #define SYS_CONTROL1_INIT_VAL 0x40
  #define SYS_CONTROL1_INIT_MASK 0xCF
  
  #define LP3971_BUCK_VOL_ENABLE_REG 0x10
  #define LP3971_BUCK_VOL_CHANGE_REG 0x20
  
  /*	Voltage control registers shift:
  	LP3971_BUCK1 -> 0
  	LP3971_BUCK2 -> 4
  	LP3971_BUCK3 -> 6
  */
451a73cd4   Axel Lin   lp3971: Fix BUCK_...
48
  #define BUCK_VOL_CHANGE_SHIFT(x) (((!!x) << 2) | (x & ~0x01))
0cbdf7bce   Marek Szyprowski   LP3971 PMIC regul...
49
50
51
52
53
54
55
  #define BUCK_VOL_CHANGE_FLAG_GO 0x01
  #define BUCK_VOL_CHANGE_FLAG_TARGET 0x02
  #define BUCK_VOL_CHANGE_FLAG_MASK 0x03
  
  #define LP3971_BUCK1_BASE 0x23
  #define LP3971_BUCK2_BASE 0x29
  #define LP3971_BUCK3_BASE 0x32
6faa7e0a4   Tobias Klauser   regulator/lp3971:...
56
  static const int buck_base_addr[] = {
0cbdf7bce   Marek Szyprowski   LP3971 PMIC regul...
57
58
59
60
61
62
63
  	LP3971_BUCK1_BASE,
  	LP3971_BUCK2_BASE,
  	LP3971_BUCK3_BASE,
  };
  
  #define LP3971_BUCK_TARGET_VOL1_REG(x) (buck_base_addr[x])
  #define LP3971_BUCK_TARGET_VOL2_REG(x) (buck_base_addr[x]+1)
cad8d76e2   Axel Lin   regulator: lp3971...
64
65
66
67
68
  static const unsigned int buck_voltage_map[] = {
  	      0,  800000,  850000,  900000,  950000, 1000000, 1050000, 1100000,
  	1150000, 1200000, 1250000, 1300000, 1350000, 1400000, 1450000, 1500000,
  	1550000, 1600000, 1650000, 1700000, 1800000, 1900000, 2500000, 2800000,
  	3000000, 3300000,
0cbdf7bce   Marek Szyprowski   LP3971 PMIC regul...
69
70
71
  };
  
  #define BUCK_TARGET_VOL_MASK 0x3f
0cbdf7bce   Marek Szyprowski   LP3971 PMIC regul...
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
  
  #define LP3971_BUCK_RAMP_REG(x)	(buck_base_addr[x]+2)
  
  #define LP3971_LDO_ENABLE_REG 0x12
  #define LP3971_LDO_VOL_CONTR_BASE 0x39
  
  /*	Voltage control registers:
  	LP3971_LDO1 -> LP3971_LDO_VOL_CONTR_BASE + 0
  	LP3971_LDO2 -> LP3971_LDO_VOL_CONTR_BASE + 0
  	LP3971_LDO3 -> LP3971_LDO_VOL_CONTR_BASE + 1
  	LP3971_LDO4 -> LP3971_LDO_VOL_CONTR_BASE + 1
  	LP3971_LDO5 -> LP3971_LDO_VOL_CONTR_BASE + 2
  */
  #define LP3971_LDO_VOL_CONTR_REG(x)	(LP3971_LDO_VOL_CONTR_BASE + (x >> 1))
  
  /*	Voltage control registers shift:
  	LP3971_LDO1 -> 0, LP3971_LDO2 -> 4
  	LP3971_LDO3 -> 0, LP3971_LDO4 -> 4
  	LP3971_LDO5 -> 0
  */
  #define LDO_VOL_CONTR_SHIFT(x) ((x & 1) << 2)
  #define LDO_VOL_CONTR_MASK 0x0f
cad8d76e2   Axel Lin   regulator: lp3971...
94
95
96
  static const unsigned int ldo45_voltage_map[] = {
  	1000000, 1050000, 1100000, 1150000, 1200000, 1250000, 1300000, 1350000,
  	1400000, 1500000, 1800000, 1900000, 2500000, 2800000, 3000000, 3300000,
0cbdf7bce   Marek Szyprowski   LP3971 PMIC regul...
97
  };
cad8d76e2   Axel Lin   regulator: lp3971...
98
99
100
  static const unsigned int ldo123_voltage_map[] = {
  	1800000, 1900000, 2000000, 2100000, 2200000, 2300000, 2400000, 2500000,
  	2600000, 2700000, 2800000, 2900000, 3000000, 3100000, 3200000, 3300000,
0cbdf7bce   Marek Szyprowski   LP3971 PMIC regul...
101
  };
0cbdf7bce   Marek Szyprowski   LP3971 PMIC regul...
102
103
  #define LDO_VOL_MIN_IDX 0x00
  #define LDO_VOL_MAX_IDX 0x0f
0cbdf7bce   Marek Szyprowski   LP3971 PMIC regul...
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
  static int lp3971_ldo_is_enabled(struct regulator_dev *dev)
  {
  	struct lp3971 *lp3971 = rdev_get_drvdata(dev);
  	int ldo = rdev_get_id(dev) - LP3971_LDO1;
  	u16 mask = 1 << (1 + ldo);
  	u16 val;
  
  	val = lp3971_reg_read(lp3971, LP3971_LDO_ENABLE_REG);
  	return (val & mask) != 0;
  }
  
  static int lp3971_ldo_enable(struct regulator_dev *dev)
  {
  	struct lp3971 *lp3971 = rdev_get_drvdata(dev);
  	int ldo = rdev_get_id(dev) - LP3971_LDO1;
  	u16 mask = 1 << (1 + ldo);
  
  	return lp3971_set_bits(lp3971, LP3971_LDO_ENABLE_REG, mask, mask);
  }
  
  static int lp3971_ldo_disable(struct regulator_dev *dev)
  {
  	struct lp3971 *lp3971 = rdev_get_drvdata(dev);
  	int ldo = rdev_get_id(dev) - LP3971_LDO1;
  	u16 mask = 1 << (1 + ldo);
  
  	return lp3971_set_bits(lp3971, LP3971_LDO_ENABLE_REG, mask, 0);
  }
f38482fa7   Axel Lin   regulator: lp3971...
132
  static int lp3971_ldo_get_voltage_sel(struct regulator_dev *dev)
0cbdf7bce   Marek Szyprowski   LP3971 PMIC regul...
133
134
135
136
137
138
139
  {
  	struct lp3971 *lp3971 = rdev_get_drvdata(dev);
  	int ldo = rdev_get_id(dev) - LP3971_LDO1;
  	u16 val, reg;
  
  	reg = lp3971_reg_read(lp3971, LP3971_LDO_VOL_CONTR_REG(ldo));
  	val = (reg >> LDO_VOL_CONTR_SHIFT(ldo)) & LDO_VOL_CONTR_MASK;
f38482fa7   Axel Lin   regulator: lp3971...
140
  	return val;
0cbdf7bce   Marek Szyprowski   LP3971 PMIC regul...
141
  }
dd8e2314b   Axel Lin   regulator: Conver...
142
143
  static int lp3971_ldo_set_voltage_sel(struct regulator_dev *dev,
  				      unsigned int selector)
0cbdf7bce   Marek Szyprowski   LP3971 PMIC regul...
144
145
146
  {
  	struct lp3971 *lp3971 = rdev_get_drvdata(dev);
  	int ldo = rdev_get_id(dev) - LP3971_LDO1;
3a93f2a9f   Mark Brown   regulator: Report...
147

0cbdf7bce   Marek Szyprowski   LP3971 PMIC regul...
148
  	return lp3971_set_bits(lp3971, LP3971_LDO_VOL_CONTR_REG(ldo),
cdb868f58   Axel Lin   lp3971: Fix setti...
149
  			LDO_VOL_CONTR_MASK << LDO_VOL_CONTR_SHIFT(ldo),
dd8e2314b   Axel Lin   regulator: Conver...
150
  			selector << LDO_VOL_CONTR_SHIFT(ldo));
0cbdf7bce   Marek Szyprowski   LP3971 PMIC regul...
151
152
153
  }
  
  static struct regulator_ops lp3971_ldo_ops = {
cad8d76e2   Axel Lin   regulator: lp3971...
154
  	.list_voltage = regulator_list_voltage_table,
3e655618e   Axel Lin   regulator: lp3971...
155
  	.map_voltage = regulator_map_voltage_ascend,
0cbdf7bce   Marek Szyprowski   LP3971 PMIC regul...
156
157
158
  	.is_enabled = lp3971_ldo_is_enabled,
  	.enable = lp3971_ldo_enable,
  	.disable = lp3971_ldo_disable,
f38482fa7   Axel Lin   regulator: lp3971...
159
  	.get_voltage_sel = lp3971_ldo_get_voltage_sel,
dd8e2314b   Axel Lin   regulator: Conver...
160
  	.set_voltage_sel = lp3971_ldo_set_voltage_sel,
0cbdf7bce   Marek Szyprowski   LP3971 PMIC regul...
161
  };
0cbdf7bce   Marek Szyprowski   LP3971 PMIC regul...
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
  static int lp3971_dcdc_is_enabled(struct regulator_dev *dev)
  {
  	struct lp3971 *lp3971 = rdev_get_drvdata(dev);
  	int buck = rdev_get_id(dev) - LP3971_DCDC1;
  	u16 mask = 1 << (buck * 2);
  	u16 val;
  
  	val = lp3971_reg_read(lp3971, LP3971_BUCK_VOL_ENABLE_REG);
  	return (val & mask) != 0;
  }
  
  static int lp3971_dcdc_enable(struct regulator_dev *dev)
  {
  	struct lp3971 *lp3971 = rdev_get_drvdata(dev);
  	int buck = rdev_get_id(dev) - LP3971_DCDC1;
  	u16 mask = 1 << (buck * 2);
  
  	return lp3971_set_bits(lp3971, LP3971_BUCK_VOL_ENABLE_REG, mask, mask);
  }
  
  static int lp3971_dcdc_disable(struct regulator_dev *dev)
  {
  	struct lp3971 *lp3971 = rdev_get_drvdata(dev);
  	int buck = rdev_get_id(dev) - LP3971_DCDC1;
  	u16 mask = 1 << (buck * 2);
  
  	return lp3971_set_bits(lp3971, LP3971_BUCK_VOL_ENABLE_REG, mask, 0);
  }
f38482fa7   Axel Lin   regulator: lp3971...
190
  static int lp3971_dcdc_get_voltage_sel(struct regulator_dev *dev)
0cbdf7bce   Marek Szyprowski   LP3971 PMIC regul...
191
192
193
194
  {
  	struct lp3971 *lp3971 = rdev_get_drvdata(dev);
  	int buck = rdev_get_id(dev) - LP3971_DCDC1;
  	u16 reg;
0cbdf7bce   Marek Szyprowski   LP3971 PMIC regul...
195
196
197
  
  	reg = lp3971_reg_read(lp3971, LP3971_BUCK_TARGET_VOL1_REG(buck));
  	reg &= BUCK_TARGET_VOL_MASK;
f38482fa7   Axel Lin   regulator: lp3971...
198
  	return reg;
0cbdf7bce   Marek Szyprowski   LP3971 PMIC regul...
199
  }
dd8e2314b   Axel Lin   regulator: Conver...
200
201
  static int lp3971_dcdc_set_voltage_sel(struct regulator_dev *dev,
  				       unsigned int selector)
0cbdf7bce   Marek Szyprowski   LP3971 PMIC regul...
202
203
204
  {
  	struct lp3971 *lp3971 = rdev_get_drvdata(dev);
  	int buck = rdev_get_id(dev) - LP3971_DCDC1;
0cbdf7bce   Marek Szyprowski   LP3971 PMIC regul...
205
  	int ret;
0cbdf7bce   Marek Szyprowski   LP3971 PMIC regul...
206
  	ret = lp3971_set_bits(lp3971, LP3971_BUCK_TARGET_VOL1_REG(buck),
dd8e2314b   Axel Lin   regulator: Conver...
207
  	       BUCK_TARGET_VOL_MASK, selector);
0cbdf7bce   Marek Szyprowski   LP3971 PMIC regul...
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
  	if (ret)
  		return ret;
  
  	ret = lp3971_set_bits(lp3971, LP3971_BUCK_VOL_CHANGE_REG,
  	       BUCK_VOL_CHANGE_FLAG_MASK << BUCK_VOL_CHANGE_SHIFT(buck),
  	       BUCK_VOL_CHANGE_FLAG_GO << BUCK_VOL_CHANGE_SHIFT(buck));
  	if (ret)
  		return ret;
  
  	return lp3971_set_bits(lp3971, LP3971_BUCK_VOL_CHANGE_REG,
  	       BUCK_VOL_CHANGE_FLAG_MASK << BUCK_VOL_CHANGE_SHIFT(buck),
  	       0 << BUCK_VOL_CHANGE_SHIFT(buck));
  }
  
  static struct regulator_ops lp3971_dcdc_ops = {
cad8d76e2   Axel Lin   regulator: lp3971...
223
  	.list_voltage = regulator_list_voltage_table,
3e655618e   Axel Lin   regulator: lp3971...
224
  	.map_voltage = regulator_map_voltage_ascend,
0cbdf7bce   Marek Szyprowski   LP3971 PMIC regul...
225
226
227
  	.is_enabled = lp3971_dcdc_is_enabled,
  	.enable = lp3971_dcdc_enable,
  	.disable = lp3971_dcdc_disable,
f38482fa7   Axel Lin   regulator: lp3971...
228
  	.get_voltage_sel = lp3971_dcdc_get_voltage_sel,
dd8e2314b   Axel Lin   regulator: Conver...
229
  	.set_voltage_sel = lp3971_dcdc_set_voltage_sel,
0cbdf7bce   Marek Szyprowski   LP3971 PMIC regul...
230
  };
14add4ff2   Axel Lin   regulator: lp3971...
231
  static const struct regulator_desc regulators[] = {
0cbdf7bce   Marek Szyprowski   LP3971 PMIC regul...
232
233
234
235
236
  	{
  		.name = "LDO1",
  		.id = LP3971_LDO1,
  		.ops = &lp3971_ldo_ops,
  		.n_voltages = ARRAY_SIZE(ldo123_voltage_map),
cad8d76e2   Axel Lin   regulator: lp3971...
237
  		.volt_table = ldo123_voltage_map,
0cbdf7bce   Marek Szyprowski   LP3971 PMIC regul...
238
239
240
241
242
243
244
245
  		.type = REGULATOR_VOLTAGE,
  		.owner = THIS_MODULE,
  	},
  	{
  		.name = "LDO2",
  		.id = LP3971_LDO2,
  		.ops = &lp3971_ldo_ops,
  		.n_voltages = ARRAY_SIZE(ldo123_voltage_map),
cad8d76e2   Axel Lin   regulator: lp3971...
246
  		.volt_table = ldo123_voltage_map,
0cbdf7bce   Marek Szyprowski   LP3971 PMIC regul...
247
248
249
250
251
252
253
254
  		.type = REGULATOR_VOLTAGE,
  		.owner = THIS_MODULE,
  	},
  	{
  		.name = "LDO3",
  		.id = LP3971_LDO3,
  		.ops = &lp3971_ldo_ops,
  		.n_voltages = ARRAY_SIZE(ldo123_voltage_map),
cad8d76e2   Axel Lin   regulator: lp3971...
255
  		.volt_table = ldo123_voltage_map,
0cbdf7bce   Marek Szyprowski   LP3971 PMIC regul...
256
257
258
259
260
261
262
263
  		.type = REGULATOR_VOLTAGE,
  		.owner = THIS_MODULE,
  	},
  	{
  		.name = "LDO4",
  		.id = LP3971_LDO4,
  		.ops = &lp3971_ldo_ops,
  		.n_voltages = ARRAY_SIZE(ldo45_voltage_map),
cad8d76e2   Axel Lin   regulator: lp3971...
264
  		.volt_table = ldo45_voltage_map,
0cbdf7bce   Marek Szyprowski   LP3971 PMIC regul...
265
266
267
268
269
270
271
272
  		.type = REGULATOR_VOLTAGE,
  		.owner = THIS_MODULE,
  	},
  	{
  		.name = "LDO5",
  		.id = LP3971_LDO5,
  		.ops = &lp3971_ldo_ops,
  		.n_voltages = ARRAY_SIZE(ldo45_voltage_map),
cad8d76e2   Axel Lin   regulator: lp3971...
273
  		.volt_table = ldo45_voltage_map,
0cbdf7bce   Marek Szyprowski   LP3971 PMIC regul...
274
275
276
277
278
279
280
281
  		.type = REGULATOR_VOLTAGE,
  		.owner = THIS_MODULE,
  	},
  	{
  		.name = "DCDC1",
  		.id = LP3971_DCDC1,
  		.ops = &lp3971_dcdc_ops,
  		.n_voltages = ARRAY_SIZE(buck_voltage_map),
cad8d76e2   Axel Lin   regulator: lp3971...
282
  		.volt_table = buck_voltage_map,
0cbdf7bce   Marek Szyprowski   LP3971 PMIC regul...
283
284
285
286
287
288
289
290
  		.type = REGULATOR_VOLTAGE,
  		.owner = THIS_MODULE,
  	},
  	{
  		.name = "DCDC2",
  		.id = LP3971_DCDC2,
  		.ops = &lp3971_dcdc_ops,
  		.n_voltages = ARRAY_SIZE(buck_voltage_map),
cad8d76e2   Axel Lin   regulator: lp3971...
291
  		.volt_table = buck_voltage_map,
0cbdf7bce   Marek Szyprowski   LP3971 PMIC regul...
292
293
294
295
296
297
298
299
  		.type = REGULATOR_VOLTAGE,
  		.owner = THIS_MODULE,
  	},
  	{
  		.name = "DCDC3",
  		.id = LP3971_DCDC3,
  		.ops = &lp3971_dcdc_ops,
  		.n_voltages = ARRAY_SIZE(buck_voltage_map),
cad8d76e2   Axel Lin   regulator: lp3971...
300
  		.volt_table = buck_voltage_map,
0cbdf7bce   Marek Szyprowski   LP3971 PMIC regul...
301
302
303
304
305
306
307
308
309
310
311
312
313
  		.type = REGULATOR_VOLTAGE,
  		.owner = THIS_MODULE,
  	},
  };
  
  static int lp3971_i2c_read(struct i2c_client *i2c, char reg, int count,
  	u16 *dest)
  {
  	int ret;
  
  	if (count != 1)
  		return -EIO;
  	ret = i2c_smbus_read_byte_data(i2c, reg);
27ef7f00c   Axel Lin   regulator: lp3971...
314
  	if (ret < 0)
a1985d469   Sachin Kamat   regulator: lp3971...
315
  		return ret;
0cbdf7bce   Marek Szyprowski   LP3971 PMIC regul...
316
317
318
319
320
321
322
323
  
  	*dest = ret;
  	return 0;
  }
  
  static int lp3971_i2c_write(struct i2c_client *i2c, char reg, int count,
  	const u16 *src)
  {
0cbdf7bce   Marek Szyprowski   LP3971 PMIC regul...
324
325
  	if (count != 1)
  		return -EIO;
1bddc2f5c   Axel Lin   regulator: lp3971...
326
  	return i2c_smbus_write_byte_data(i2c, reg, *src);
0cbdf7bce   Marek Szyprowski   LP3971 PMIC regul...
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
  }
  
  static u8 lp3971_reg_read(struct lp3971 *lp3971, u8 reg)
  {
  	u16 val = 0;
  
  	mutex_lock(&lp3971->io_lock);
  
  	lp3971_i2c_read(lp3971->i2c, reg, 1, &val);
  
  	dev_dbg(lp3971->dev, "reg read 0x%02x -> 0x%02x
  ", (int)reg,
  		(unsigned)val&0xff);
  
  	mutex_unlock(&lp3971->io_lock);
  
  	return val & 0xff;
  }
  
  static int lp3971_set_bits(struct lp3971 *lp3971, u8 reg, u16 mask, u16 val)
  {
  	u16 tmp;
  	int ret;
  
  	mutex_lock(&lp3971->io_lock);
  
  	ret = lp3971_i2c_read(lp3971->i2c, reg, 1, &tmp);
0cbdf7bce   Marek Szyprowski   LP3971 PMIC regul...
354
  	if (ret == 0) {
40e1d79ee   Dan Carpenter   regulator: lp3971...
355
  		tmp = (tmp & ~mask) | val;
0cbdf7bce   Marek Szyprowski   LP3971 PMIC regul...
356
357
358
359
360
361
362
363
364
  		ret = lp3971_i2c_write(lp3971->i2c, reg, 1, &tmp);
  		dev_dbg(lp3971->dev, "reg write 0x%02x -> 0x%02x
  ", (int)reg,
  			(unsigned)val&0xff);
  	}
  	mutex_unlock(&lp3971->io_lock);
  
  	return ret;
  }
a5023574d   Bill Pemberton   regulator: remove...
365
  static int setup_regulators(struct lp3971 *lp3971,
ebbed04fe   Dmitry Torokhov   Regulators: lp397...
366
  				      struct lp3971_platform_data *pdata)
0cbdf7bce   Marek Szyprowski   LP3971 PMIC regul...
367
368
  {
  	int i, err;
ebbed04fe   Dmitry Torokhov   Regulators: lp397...
369

0cbdf7bce   Marek Szyprowski   LP3971 PMIC regul...
370
  	/* Instantiate the regulators */
ebbed04fe   Dmitry Torokhov   Regulators: lp397...
371
  	for (i = 0; i < pdata->num_regulators; i++) {
c172708d3   Mark Brown   regulator: core: ...
372
  		struct regulator_config config = { };
ebbed04fe   Dmitry Torokhov   Regulators: lp397...
373
  		struct lp3971_regulator_subdev *reg = &pdata->regulators[i];
56dde80a1   Axel Lin   regulator: lp3971...
374
  		struct regulator_dev *rdev;
0cbdf7bce   Marek Szyprowski   LP3971 PMIC regul...
375

c172708d3   Mark Brown   regulator: core: ...
376
377
378
  		config.dev = lp3971->dev;
  		config.init_data = reg->initdata;
  		config.driver_data = lp3971;
56dde80a1   Axel Lin   regulator: lp3971...
379
380
381
382
  		rdev = devm_regulator_register(lp3971->dev,
  					       &regulators[reg->id], &config);
  		if (IS_ERR(rdev)) {
  			err = PTR_ERR(rdev);
0cbdf7bce   Marek Szyprowski   LP3971 PMIC regul...
383
384
385
  			dev_err(lp3971->dev, "regulator init failed: %d
  ",
  				err);
56dde80a1   Axel Lin   regulator: lp3971...
386
  			return err;
0cbdf7bce   Marek Szyprowski   LP3971 PMIC regul...
387
388
389
390
  		}
  	}
  
  	return 0;
0cbdf7bce   Marek Szyprowski   LP3971 PMIC regul...
391
  }
a5023574d   Bill Pemberton   regulator: remove...
392
  static int lp3971_i2c_probe(struct i2c_client *i2c,
0cbdf7bce   Marek Szyprowski   LP3971 PMIC regul...
393
394
395
  			    const struct i2c_device_id *id)
  {
  	struct lp3971 *lp3971;
dff91d0b7   Jingoo Han   regulator: use de...
396
  	struct lp3971_platform_data *pdata = dev_get_platdata(&i2c->dev);
0cbdf7bce   Marek Szyprowski   LP3971 PMIC regul...
397
398
  	int ret;
  	u16 val;
ebbed04fe   Dmitry Torokhov   Regulators: lp397...
399
400
401
402
  	if (!pdata) {
  		dev_dbg(&i2c->dev, "No platform init data supplied
  ");
  		return -ENODEV;
0cbdf7bce   Marek Szyprowski   LP3971 PMIC regul...
403
  	}
2af0af673   Nikolay Balandin   regulator: lp397x...
404
  	lp3971 = devm_kzalloc(&i2c->dev, sizeof(struct lp3971), GFP_KERNEL);
ebbed04fe   Dmitry Torokhov   Regulators: lp397...
405
406
  	if (lp3971 == NULL)
  		return -ENOMEM;
0cbdf7bce   Marek Szyprowski   LP3971 PMIC regul...
407
408
  	lp3971->i2c = i2c;
  	lp3971->dev = &i2c->dev;
0cbdf7bce   Marek Szyprowski   LP3971 PMIC regul...
409
410
411
412
413
414
415
416
417
418
  
  	mutex_init(&lp3971->io_lock);
  
  	/* Detect LP3971 */
  	ret = lp3971_i2c_read(i2c, LP3971_SYS_CONTROL1_REG, 1, &val);
  	if (ret == 0 && (val & SYS_CONTROL1_INIT_MASK) != SYS_CONTROL1_INIT_VAL)
  		ret = -ENODEV;
  	if (ret < 0) {
  		dev_err(&i2c->dev, "failed to detect device
  ");
2af0af673   Nikolay Balandin   regulator: lp397x...
419
  		return ret;
0cbdf7bce   Marek Szyprowski   LP3971 PMIC regul...
420
  	}
ebbed04fe   Dmitry Torokhov   Regulators: lp397...
421
422
  	ret = setup_regulators(lp3971, pdata);
  	if (ret < 0)
2af0af673   Nikolay Balandin   regulator: lp397x...
423
  		return ret;
0cbdf7bce   Marek Szyprowski   LP3971 PMIC regul...
424

ebbed04fe   Dmitry Torokhov   Regulators: lp397...
425
  	i2c_set_clientdata(i2c, lp3971);
0cbdf7bce   Marek Szyprowski   LP3971 PMIC regul...
426
  	return 0;
0cbdf7bce   Marek Szyprowski   LP3971 PMIC regul...
427
  }
0cbdf7bce   Marek Szyprowski   LP3971 PMIC regul...
428
  static const struct i2c_device_id lp3971_i2c_id[] = {
0a3ee93a3   Jingoo Han   regulator: lp3971...
429
430
  	{ "lp3971", 0 },
  	{ }
0cbdf7bce   Marek Szyprowski   LP3971 PMIC regul...
431
432
433
434
435
436
  };
  MODULE_DEVICE_TABLE(i2c, lp3971_i2c_id);
  
  static struct i2c_driver lp3971_i2c_driver = {
  	.driver = {
  		.name = "LP3971",
0cbdf7bce   Marek Szyprowski   LP3971 PMIC regul...
437
438
  	},
  	.probe    = lp3971_i2c_probe,
0cbdf7bce   Marek Szyprowski   LP3971 PMIC regul...
439
440
  	.id_table = lp3971_i2c_id,
  };
5af34e60d   Mark Brown   regulator: lp3971...
441
  module_i2c_driver(lp3971_i2c_driver);
0cbdf7bce   Marek Szyprowski   LP3971 PMIC regul...
442
443
444
445
  
  MODULE_LICENSE("GPL");
  MODULE_AUTHOR("Marek Szyprowski <m.szyprowski@samsung.com>");
  MODULE_DESCRIPTION("LP3971 PMIC driver");