Blame view

drivers/regulator/lp3971.c 11.5 KB
d2912cb15   Thomas Gleixner   treewide: Replace...
1
  // SPDX-License-Identifier: GPL-2.0-only
0cbdf7bce   Marek Szyprowski   LP3971 PMIC regul...
2
3
4
5
6
7
8
  /*
   * Regulator driver for National Semiconductors LP3971 PMIC chip
   *
   *  Copyright (C) 2009 Samsung Electronics
   *  Author: Marek Szyprowski <m.szyprowski@samsung.com>
   *
   * Based on wm8350.c
0cbdf7bce   Marek Szyprowski   LP3971 PMIC regul...
9
10
11
12
13
14
   */
  
  #include <linux/bug.h>
  #include <linux/err.h>
  #include <linux/i2c.h>
  #include <linux/kernel.h>
65602c32e   Paul Gortmaker   regulator: Add mo...
15
  #include <linux/module.h>
0cbdf7bce   Marek Szyprowski   LP3971 PMIC regul...
16
17
  #include <linux/regulator/driver.h>
  #include <linux/regulator/lp3971.h>
5a0e3ad6a   Tejun Heo   include cleanup: ...
18
  #include <linux/slab.h>
0cbdf7bce   Marek Szyprowski   LP3971 PMIC regul...
19
20
21
22
23
  
  struct lp3971 {
  	struct device *dev;
  	struct mutex io_lock;
  	struct i2c_client *i2c;
0cbdf7bce   Marek Szyprowski   LP3971 PMIC regul...
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
  };
  
  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_...
44
  #define BUCK_VOL_CHANGE_SHIFT(x) (((!!x) << 2) | (x & ~0x01))
0cbdf7bce   Marek Szyprowski   LP3971 PMIC regul...
45
46
47
48
49
50
51
  #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:...
52
  static const int buck_base_addr[] = {
0cbdf7bce   Marek Szyprowski   LP3971 PMIC regul...
53
54
55
56
57
58
59
  	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...
60
61
62
63
64
  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...
65
66
67
  };
  
  #define BUCK_TARGET_VOL_MASK 0x3f
0cbdf7bce   Marek Szyprowski   LP3971 PMIC regul...
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
  
  #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...
90
91
92
  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...
93
  };
cad8d76e2   Axel Lin   regulator: lp3971...
94
95
96
  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...
97
  };
0cbdf7bce   Marek Szyprowski   LP3971 PMIC regul...
98
99
  #define LDO_VOL_MIN_IDX 0x00
  #define LDO_VOL_MAX_IDX 0x0f
0cbdf7bce   Marek Szyprowski   LP3971 PMIC regul...
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
  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...
128
  static int lp3971_ldo_get_voltage_sel(struct regulator_dev *dev)
0cbdf7bce   Marek Szyprowski   LP3971 PMIC regul...
129
130
131
132
133
134
135
  {
  	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...
136
  	return val;
0cbdf7bce   Marek Szyprowski   LP3971 PMIC regul...
137
  }
dd8e2314b   Axel Lin   regulator: Conver...
138
139
  static int lp3971_ldo_set_voltage_sel(struct regulator_dev *dev,
  				      unsigned int selector)
0cbdf7bce   Marek Szyprowski   LP3971 PMIC regul...
140
141
142
  {
  	struct lp3971 *lp3971 = rdev_get_drvdata(dev);
  	int ldo = rdev_get_id(dev) - LP3971_LDO1;
3a93f2a9f   Mark Brown   regulator: Report...
143

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

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

c172708d3   Mark Brown   regulator: core: ...
370
371
372
  		config.dev = lp3971->dev;
  		config.init_data = reg->initdata;
  		config.driver_data = lp3971;
56dde80a1   Axel Lin   regulator: lp3971...
373
374
375
376
  		rdev = devm_regulator_register(lp3971->dev,
  					       &regulators[reg->id], &config);
  		if (IS_ERR(rdev)) {
  			err = PTR_ERR(rdev);
0cbdf7bce   Marek Szyprowski   LP3971 PMIC regul...
377
378
379
  			dev_err(lp3971->dev, "regulator init failed: %d
  ",
  				err);
56dde80a1   Axel Lin   regulator: lp3971...
380
  			return err;
0cbdf7bce   Marek Szyprowski   LP3971 PMIC regul...
381
382
383
384
  		}
  	}
  
  	return 0;
0cbdf7bce   Marek Szyprowski   LP3971 PMIC regul...
385
  }
77e29598c   Axel Lin   regulator: Conver...
386
  static int lp3971_i2c_probe(struct i2c_client *i2c)
0cbdf7bce   Marek Szyprowski   LP3971 PMIC regul...
387
388
  {
  	struct lp3971 *lp3971;
dff91d0b7   Jingoo Han   regulator: use de...
389
  	struct lp3971_platform_data *pdata = dev_get_platdata(&i2c->dev);
0cbdf7bce   Marek Szyprowski   LP3971 PMIC regul...
390
391
  	int ret;
  	u16 val;
ebbed04fe   Dmitry Torokhov   Regulators: lp397...
392
393
394
395
  	if (!pdata) {
  		dev_dbg(&i2c->dev, "No platform init data supplied
  ");
  		return -ENODEV;
0cbdf7bce   Marek Szyprowski   LP3971 PMIC regul...
396
  	}
2af0af673   Nikolay Balandin   regulator: lp397x...
397
  	lp3971 = devm_kzalloc(&i2c->dev, sizeof(struct lp3971), GFP_KERNEL);
ebbed04fe   Dmitry Torokhov   Regulators: lp397...
398
399
  	if (lp3971 == NULL)
  		return -ENOMEM;
0cbdf7bce   Marek Szyprowski   LP3971 PMIC regul...
400
401
  	lp3971->i2c = i2c;
  	lp3971->dev = &i2c->dev;
0cbdf7bce   Marek Szyprowski   LP3971 PMIC regul...
402
403
404
405
406
407
408
409
410
411
  
  	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...
412
  		return ret;
0cbdf7bce   Marek Szyprowski   LP3971 PMIC regul...
413
  	}
ebbed04fe   Dmitry Torokhov   Regulators: lp397...
414
415
  	ret = setup_regulators(lp3971, pdata);
  	if (ret < 0)
2af0af673   Nikolay Balandin   regulator: lp397x...
416
  		return ret;
0cbdf7bce   Marek Szyprowski   LP3971 PMIC regul...
417

ebbed04fe   Dmitry Torokhov   Regulators: lp397...
418
  	i2c_set_clientdata(i2c, lp3971);
0cbdf7bce   Marek Szyprowski   LP3971 PMIC regul...
419
  	return 0;
0cbdf7bce   Marek Szyprowski   LP3971 PMIC regul...
420
  }
0cbdf7bce   Marek Szyprowski   LP3971 PMIC regul...
421
  static const struct i2c_device_id lp3971_i2c_id[] = {
0a3ee93a3   Jingoo Han   regulator: lp3971...
422
423
  	{ "lp3971", 0 },
  	{ }
0cbdf7bce   Marek Szyprowski   LP3971 PMIC regul...
424
425
426
427
428
429
  };
  MODULE_DEVICE_TABLE(i2c, lp3971_i2c_id);
  
  static struct i2c_driver lp3971_i2c_driver = {
  	.driver = {
  		.name = "LP3971",
0cbdf7bce   Marek Szyprowski   LP3971 PMIC regul...
430
  	},
77e29598c   Axel Lin   regulator: Conver...
431
  	.probe_new = lp3971_i2c_probe,
0cbdf7bce   Marek Szyprowski   LP3971 PMIC regul...
432
433
  	.id_table = lp3971_i2c_id,
  };
5af34e60d   Mark Brown   regulator: lp3971...
434
  module_i2c_driver(lp3971_i2c_driver);
0cbdf7bce   Marek Szyprowski   LP3971 PMIC regul...
435
436
437
438
  
  MODULE_LICENSE("GPL");
  MODULE_AUTHOR("Marek Szyprowski <m.szyprowski@samsung.com>");
  MODULE_DESCRIPTION("LP3971 PMIC driver");