diff options
author | Marek Szyprowski <m.szyprowski@samsung.com> | 2009-05-19 01:33:55 -0400 |
---|---|---|
committer | Liam Girdwood <lrg@slimlogic.co.uk> | 2009-06-15 06:18:26 -0400 |
commit | 0cbdf7bce5b98807b946d1a96956f30dcae24a50 (patch) | |
tree | a13822c57cf0b2e7cce0ad5f01399e51d6a80534 | |
parent | 1909e2f658ee6ec5bcca62a5599f5653857cfe18 (diff) |
LP3971 PMIC regulator driver (updated and combined version)
This patch adds regulator drivers for National Semiconductors LP3971 PMIC.
This LP3971 PMIC controller has 3 DC/DC voltage converters and 5 low
drop-out (LDO) regulators. LP3971 PMIC controller uses I2C interface.
Reviewed-by: Kyungmin Park <kyungmin.park@samsung.com>
Signed-off-by: Marek Szyprowski <m.szyprowski@samsung.com>
Acked-by: Mark Brown <broonie@opensource.wolfsonmicro.com>
Signed-off-by: Liam Girdwood <lrg@slimlogic.co.uk>
-rw-r--r-- | drivers/regulator/Kconfig | 7 | ||||
-rw-r--r-- | drivers/regulator/Makefile | 1 | ||||
-rw-r--r-- | drivers/regulator/lp3971.c | 562 | ||||
-rw-r--r-- | include/linux/regulator/lp3971.h | 51 |
4 files changed, 621 insertions, 0 deletions
diff --git a/drivers/regulator/Kconfig b/drivers/regulator/Kconfig index 5bec17cf1d5c..f4317798e47c 100644 --- a/drivers/regulator/Kconfig +++ b/drivers/regulator/Kconfig | |||
@@ -110,4 +110,11 @@ config REGULATOR_PCF50633 | |||
110 | Say Y here to support the voltage regulators and convertors | 110 | Say Y here to support the voltage regulators and convertors |
111 | on PCF50633 | 111 | on PCF50633 |
112 | 112 | ||
113 | config REGULATOR_LP3971 | ||
114 | tristate "National Semiconductors LP3971 PMIC regulator driver" | ||
115 | depends on I2C | ||
116 | help | ||
117 | Say Y here to support the voltage regulators and convertors | ||
118 | on National Semiconductors LP3971 PMIC | ||
119 | |||
113 | endif | 120 | endif |
diff --git a/drivers/regulator/Makefile b/drivers/regulator/Makefile index faf7bcc1af98..4d762c4cccfd 100644 --- a/drivers/regulator/Makefile +++ b/drivers/regulator/Makefile | |||
@@ -9,6 +9,7 @@ obj-$(CONFIG_REGULATOR_VIRTUAL_CONSUMER) += virtual.o | |||
9 | obj-$(CONFIG_REGULATOR_USERSPACE_CONSUMER) += userspace-consumer.o | 9 | obj-$(CONFIG_REGULATOR_USERSPACE_CONSUMER) += userspace-consumer.o |
10 | 10 | ||
11 | obj-$(CONFIG_REGULATOR_BQ24022) += bq24022.o | 11 | obj-$(CONFIG_REGULATOR_BQ24022) += bq24022.o |
12 | obj-$(CONFIG_REGULATOR_LP3971) += lp3971.o | ||
12 | obj-$(CONFIG_REGULATOR_MAX1586) += max1586.o | 13 | obj-$(CONFIG_REGULATOR_MAX1586) += max1586.o |
13 | obj-$(CONFIG_REGULATOR_TWL4030) += twl4030-regulator.o | 14 | obj-$(CONFIG_REGULATOR_TWL4030) += twl4030-regulator.o |
14 | obj-$(CONFIG_REGULATOR_WM8350) += wm8350-regulator.o | 15 | obj-$(CONFIG_REGULATOR_WM8350) += wm8350-regulator.o |
diff --git a/drivers/regulator/lp3971.c b/drivers/regulator/lp3971.c new file mode 100644 index 000000000000..35abebea4ed5 --- /dev/null +++ b/drivers/regulator/lp3971.c | |||
@@ -0,0 +1,562 @@ | |||
1 | /* | ||
2 | * Regulator driver for National Semiconductors LP3971 PMIC chip | ||
3 | * | ||
4 | * Copyright (C) 2009 Samsung Electronics | ||
5 | * Author: Marek Szyprowski <m.szyprowski@samsung.com> | ||
6 | * | ||
7 | * Based on wm8350.c | ||
8 | * | ||
9 | * This program is free software; you can redistribute it and/or modify | ||
10 | * it under the terms of the GNU General Public License version 2 as | ||
11 | * published by the Free Software Foundation. | ||
12 | * | ||
13 | */ | ||
14 | |||
15 | #include <linux/bug.h> | ||
16 | #include <linux/err.h> | ||
17 | #include <linux/i2c.h> | ||
18 | #include <linux/kernel.h> | ||
19 | #include <linux/regulator/driver.h> | ||
20 | #include <linux/regulator/lp3971.h> | ||
21 | |||
22 | struct lp3971 { | ||
23 | struct device *dev; | ||
24 | struct mutex io_lock; | ||
25 | struct i2c_client *i2c; | ||
26 | int num_regulators; | ||
27 | struct regulator_dev **rdev; | ||
28 | }; | ||
29 | |||
30 | static u8 lp3971_reg_read(struct lp3971 *lp3971, u8 reg); | ||
31 | static int lp3971_set_bits(struct lp3971 *lp3971, u8 reg, u16 mask, u16 val); | ||
32 | |||
33 | #define LP3971_SYS_CONTROL1_REG 0x07 | ||
34 | |||
35 | /* System control register 1 initial value, | ||
36 | bits 4 and 5 are EPROM programmable */ | ||
37 | #define SYS_CONTROL1_INIT_VAL 0x40 | ||
38 | #define SYS_CONTROL1_INIT_MASK 0xCF | ||
39 | |||
40 | #define LP3971_BUCK_VOL_ENABLE_REG 0x10 | ||
41 | #define LP3971_BUCK_VOL_CHANGE_REG 0x20 | ||
42 | |||
43 | /* Voltage control registers shift: | ||
44 | LP3971_BUCK1 -> 0 | ||
45 | LP3971_BUCK2 -> 4 | ||
46 | LP3971_BUCK3 -> 6 | ||
47 | */ | ||
48 | #define BUCK_VOL_CHANGE_SHIFT(x) (((1 << x) & ~0x01) << 1) | ||
49 | #define BUCK_VOL_CHANGE_FLAG_GO 0x01 | ||
50 | #define BUCK_VOL_CHANGE_FLAG_TARGET 0x02 | ||
51 | #define BUCK_VOL_CHANGE_FLAG_MASK 0x03 | ||
52 | |||
53 | #define LP3971_BUCK1_BASE 0x23 | ||
54 | #define LP3971_BUCK2_BASE 0x29 | ||
55 | #define LP3971_BUCK3_BASE 0x32 | ||
56 | |||
57 | const static int buck_base_addr[] = { | ||
58 | LP3971_BUCK1_BASE, | ||
59 | LP3971_BUCK2_BASE, | ||
60 | LP3971_BUCK3_BASE, | ||
61 | }; | ||
62 | |||
63 | #define LP3971_BUCK_TARGET_VOL1_REG(x) (buck_base_addr[x]) | ||
64 | #define LP3971_BUCK_TARGET_VOL2_REG(x) (buck_base_addr[x]+1) | ||
65 | |||
66 | const static int buck_voltage_map[] = { | ||
67 | 0, 800, 850, 900, 950, 1000, 1050, 1100, | ||
68 | 1150, 1200, 1250, 1300, 1350, 1400, 1450, 1500, | ||
69 | 1550, 1600, 1650, 1700, 1800, 1900, 2500, 2800, | ||
70 | 3000, 3300, | ||
71 | }; | ||
72 | |||
73 | #define BUCK_TARGET_VOL_MASK 0x3f | ||
74 | #define BUCK_TARGET_VOL_MIN_IDX 0x01 | ||
75 | #define BUCK_TARGET_VOL_MAX_IDX 0x19 | ||
76 | |||
77 | #define LP3971_BUCK_RAMP_REG(x) (buck_base_addr[x]+2) | ||
78 | |||
79 | #define LP3971_LDO_ENABLE_REG 0x12 | ||
80 | #define LP3971_LDO_VOL_CONTR_BASE 0x39 | ||
81 | |||
82 | /* Voltage control registers: | ||
83 | LP3971_LDO1 -> LP3971_LDO_VOL_CONTR_BASE + 0 | ||
84 | LP3971_LDO2 -> LP3971_LDO_VOL_CONTR_BASE + 0 | ||
85 | LP3971_LDO3 -> LP3971_LDO_VOL_CONTR_BASE + 1 | ||
86 | LP3971_LDO4 -> LP3971_LDO_VOL_CONTR_BASE + 1 | ||
87 | LP3971_LDO5 -> LP3971_LDO_VOL_CONTR_BASE + 2 | ||
88 | */ | ||
89 | #define LP3971_LDO_VOL_CONTR_REG(x) (LP3971_LDO_VOL_CONTR_BASE + (x >> 1)) | ||
90 | |||
91 | /* Voltage control registers shift: | ||
92 | LP3971_LDO1 -> 0, LP3971_LDO2 -> 4 | ||
93 | LP3971_LDO3 -> 0, LP3971_LDO4 -> 4 | ||
94 | LP3971_LDO5 -> 0 | ||
95 | */ | ||
96 | #define LDO_VOL_CONTR_SHIFT(x) ((x & 1) << 2) | ||
97 | #define LDO_VOL_CONTR_MASK 0x0f | ||
98 | |||
99 | const static int ldo45_voltage_map[] = { | ||
100 | 1000, 1050, 1100, 1150, 1200, 1250, 1300, 1350, | ||
101 | 1400, 1500, 1800, 1900, 2500, 2800, 3000, 3300, | ||
102 | }; | ||
103 | |||
104 | const static int ldo123_voltage_map[] = { | ||
105 | 1800, 1900, 2000, 2100, 2200, 2300, 2400, 2500, | ||
106 | 2600, 2700, 2800, 2900, 3000, 3100, 3200, 3300, | ||
107 | }; | ||
108 | |||
109 | const static int *ldo_voltage_map[] = { | ||
110 | ldo123_voltage_map, /* LDO1 */ | ||
111 | ldo123_voltage_map, /* LDO2 */ | ||
112 | ldo123_voltage_map, /* LDO3 */ | ||
113 | ldo45_voltage_map, /* LDO4 */ | ||
114 | ldo45_voltage_map, /* LDO5 */ | ||
115 | }; | ||
116 | |||
117 | #define LDO_VOL_VALUE_MAP(x) (ldo_voltage_map[(x - LP3971_LDO1)]) | ||
118 | |||
119 | #define LDO_VOL_MIN_IDX 0x00 | ||
120 | #define LDO_VOL_MAX_IDX 0x0f | ||
121 | |||
122 | static int lp3971_ldo_list_voltage(struct regulator_dev *dev, unsigned index) | ||
123 | { | ||
124 | int ldo = rdev_get_id(dev) - LP3971_LDO1; | ||
125 | return 1000 * LDO_VOL_VALUE_MAP(ldo)[index]; | ||
126 | } | ||
127 | |||
128 | static int lp3971_ldo_is_enabled(struct regulator_dev *dev) | ||
129 | { | ||
130 | struct lp3971 *lp3971 = rdev_get_drvdata(dev); | ||
131 | int ldo = rdev_get_id(dev) - LP3971_LDO1; | ||
132 | u16 mask = 1 << (1 + ldo); | ||
133 | u16 val; | ||
134 | |||
135 | val = lp3971_reg_read(lp3971, LP3971_LDO_ENABLE_REG); | ||
136 | return (val & mask) != 0; | ||
137 | } | ||
138 | |||
139 | static int lp3971_ldo_enable(struct regulator_dev *dev) | ||
140 | { | ||
141 | struct lp3971 *lp3971 = rdev_get_drvdata(dev); | ||
142 | int ldo = rdev_get_id(dev) - LP3971_LDO1; | ||
143 | u16 mask = 1 << (1 + ldo); | ||
144 | |||
145 | return lp3971_set_bits(lp3971, LP3971_LDO_ENABLE_REG, mask, mask); | ||
146 | } | ||
147 | |||
148 | static int lp3971_ldo_disable(struct regulator_dev *dev) | ||
149 | { | ||
150 | struct lp3971 *lp3971 = rdev_get_drvdata(dev); | ||
151 | int ldo = rdev_get_id(dev) - LP3971_LDO1; | ||
152 | u16 mask = 1 << (1 + ldo); | ||
153 | |||
154 | return lp3971_set_bits(lp3971, LP3971_LDO_ENABLE_REG, mask, 0); | ||
155 | } | ||
156 | |||
157 | static int lp3971_ldo_get_voltage(struct regulator_dev *dev) | ||
158 | { | ||
159 | struct lp3971 *lp3971 = rdev_get_drvdata(dev); | ||
160 | int ldo = rdev_get_id(dev) - LP3971_LDO1; | ||
161 | u16 val, reg; | ||
162 | |||
163 | reg = lp3971_reg_read(lp3971, LP3971_LDO_VOL_CONTR_REG(ldo)); | ||
164 | val = (reg >> LDO_VOL_CONTR_SHIFT(ldo)) & LDO_VOL_CONTR_MASK; | ||
165 | |||
166 | return 1000 * LDO_VOL_VALUE_MAP(ldo)[val]; | ||
167 | } | ||
168 | |||
169 | static int lp3971_ldo_set_voltage(struct regulator_dev *dev, | ||
170 | int min_uV, int max_uV) | ||
171 | { | ||
172 | struct lp3971 *lp3971 = rdev_get_drvdata(dev); | ||
173 | int ldo = rdev_get_id(dev) - LP3971_LDO1; | ||
174 | int min_vol = min_uV / 1000, max_vol = max_uV / 1000; | ||
175 | const int *vol_map = LDO_VOL_VALUE_MAP(ldo); | ||
176 | u16 val; | ||
177 | |||
178 | if (min_vol < vol_map[LDO_VOL_MIN_IDX] || | ||
179 | min_vol > vol_map[LDO_VOL_MAX_IDX]) | ||
180 | return -EINVAL; | ||
181 | |||
182 | for (val = LDO_VOL_MIN_IDX; val <= LDO_VOL_MAX_IDX; val++) | ||
183 | if (vol_map[val] >= min_vol) | ||
184 | break; | ||
185 | |||
186 | if (vol_map[val] > max_vol) | ||
187 | return -EINVAL; | ||
188 | |||
189 | return lp3971_set_bits(lp3971, LP3971_LDO_VOL_CONTR_REG(ldo), | ||
190 | LDO_VOL_CONTR_MASK << LDO_VOL_CONTR_SHIFT(ldo), val); | ||
191 | } | ||
192 | |||
193 | static struct regulator_ops lp3971_ldo_ops = { | ||
194 | .list_voltage = lp3971_ldo_list_voltage, | ||
195 | .is_enabled = lp3971_ldo_is_enabled, | ||
196 | .enable = lp3971_ldo_enable, | ||
197 | .disable = lp3971_ldo_disable, | ||
198 | .get_voltage = lp3971_ldo_get_voltage, | ||
199 | .set_voltage = lp3971_ldo_set_voltage, | ||
200 | }; | ||
201 | |||
202 | static int lp3971_dcdc_list_voltage(struct regulator_dev *dev, unsigned index) | ||
203 | { | ||
204 | return 1000 * buck_voltage_map[index]; | ||
205 | } | ||
206 | |||
207 | static int lp3971_dcdc_is_enabled(struct regulator_dev *dev) | ||
208 | { | ||
209 | struct lp3971 *lp3971 = rdev_get_drvdata(dev); | ||
210 | int buck = rdev_get_id(dev) - LP3971_DCDC1; | ||
211 | u16 mask = 1 << (buck * 2); | ||
212 | u16 val; | ||
213 | |||
214 | val = lp3971_reg_read(lp3971, LP3971_BUCK_VOL_ENABLE_REG); | ||
215 | return (val & mask) != 0; | ||
216 | } | ||
217 | |||
218 | static int lp3971_dcdc_enable(struct regulator_dev *dev) | ||
219 | { | ||
220 | struct lp3971 *lp3971 = rdev_get_drvdata(dev); | ||
221 | int buck = rdev_get_id(dev) - LP3971_DCDC1; | ||
222 | u16 mask = 1 << (buck * 2); | ||
223 | |||
224 | return lp3971_set_bits(lp3971, LP3971_BUCK_VOL_ENABLE_REG, mask, mask); | ||
225 | } | ||
226 | |||
227 | static int lp3971_dcdc_disable(struct regulator_dev *dev) | ||
228 | { | ||
229 | struct lp3971 *lp3971 = rdev_get_drvdata(dev); | ||
230 | int buck = rdev_get_id(dev) - LP3971_DCDC1; | ||
231 | u16 mask = 1 << (buck * 2); | ||
232 | |||
233 | return lp3971_set_bits(lp3971, LP3971_BUCK_VOL_ENABLE_REG, mask, 0); | ||
234 | } | ||
235 | |||
236 | static int lp3971_dcdc_get_voltage(struct regulator_dev *dev) | ||
237 | { | ||
238 | struct lp3971 *lp3971 = rdev_get_drvdata(dev); | ||
239 | int buck = rdev_get_id(dev) - LP3971_DCDC1; | ||
240 | u16 reg; | ||
241 | int val; | ||
242 | |||
243 | reg = lp3971_reg_read(lp3971, LP3971_BUCK_TARGET_VOL1_REG(buck)); | ||
244 | reg &= BUCK_TARGET_VOL_MASK; | ||
245 | |||
246 | if (reg <= BUCK_TARGET_VOL_MAX_IDX) | ||
247 | val = 1000 * buck_voltage_map[reg]; | ||
248 | else { | ||
249 | val = 0; | ||
250 | dev_warn(&dev->dev, "chip reported incorrect voltage value.\n"); | ||
251 | } | ||
252 | |||
253 | return val; | ||
254 | } | ||
255 | |||
256 | static int lp3971_dcdc_set_voltage(struct regulator_dev *dev, | ||
257 | int min_uV, int max_uV) | ||
258 | { | ||
259 | struct lp3971 *lp3971 = rdev_get_drvdata(dev); | ||
260 | int buck = rdev_get_id(dev) - LP3971_DCDC1; | ||
261 | int min_vol = min_uV / 1000, max_vol = max_uV / 1000; | ||
262 | const int *vol_map = buck_voltage_map; | ||
263 | u16 val; | ||
264 | int ret; | ||
265 | |||
266 | if (min_vol < vol_map[BUCK_TARGET_VOL_MIN_IDX] || | ||
267 | min_vol > vol_map[BUCK_TARGET_VOL_MAX_IDX]) | ||
268 | return -EINVAL; | ||
269 | |||
270 | for (val = BUCK_TARGET_VOL_MIN_IDX; val <= BUCK_TARGET_VOL_MAX_IDX; | ||
271 | val++) | ||
272 | if (vol_map[val] >= min_vol) | ||
273 | break; | ||
274 | |||
275 | if (vol_map[val] > max_vol) | ||
276 | return -EINVAL; | ||
277 | |||
278 | ret = lp3971_set_bits(lp3971, LP3971_BUCK_TARGET_VOL1_REG(buck), | ||
279 | BUCK_TARGET_VOL_MASK, val); | ||
280 | if (ret) | ||
281 | return ret; | ||
282 | |||
283 | ret = lp3971_set_bits(lp3971, LP3971_BUCK_VOL_CHANGE_REG, | ||
284 | BUCK_VOL_CHANGE_FLAG_MASK << BUCK_VOL_CHANGE_SHIFT(buck), | ||
285 | BUCK_VOL_CHANGE_FLAG_GO << BUCK_VOL_CHANGE_SHIFT(buck)); | ||
286 | if (ret) | ||
287 | return ret; | ||
288 | |||
289 | return lp3971_set_bits(lp3971, LP3971_BUCK_VOL_CHANGE_REG, | ||
290 | BUCK_VOL_CHANGE_FLAG_MASK << BUCK_VOL_CHANGE_SHIFT(buck), | ||
291 | 0 << BUCK_VOL_CHANGE_SHIFT(buck)); | ||
292 | } | ||
293 | |||
294 | static struct regulator_ops lp3971_dcdc_ops = { | ||
295 | .list_voltage = lp3971_dcdc_list_voltage, | ||
296 | .is_enabled = lp3971_dcdc_is_enabled, | ||
297 | .enable = lp3971_dcdc_enable, | ||
298 | .disable = lp3971_dcdc_disable, | ||
299 | .get_voltage = lp3971_dcdc_get_voltage, | ||
300 | .set_voltage = lp3971_dcdc_set_voltage, | ||
301 | }; | ||
302 | |||
303 | static struct regulator_desc regulators[] = { | ||
304 | { | ||
305 | .name = "LDO1", | ||
306 | .id = LP3971_LDO1, | ||
307 | .ops = &lp3971_ldo_ops, | ||
308 | .n_voltages = ARRAY_SIZE(ldo123_voltage_map), | ||
309 | .type = REGULATOR_VOLTAGE, | ||
310 | .owner = THIS_MODULE, | ||
311 | }, | ||
312 | { | ||
313 | .name = "LDO2", | ||
314 | .id = LP3971_LDO2, | ||
315 | .ops = &lp3971_ldo_ops, | ||
316 | .n_voltages = ARRAY_SIZE(ldo123_voltage_map), | ||
317 | .type = REGULATOR_VOLTAGE, | ||
318 | .owner = THIS_MODULE, | ||
319 | }, | ||
320 | { | ||
321 | .name = "LDO3", | ||
322 | .id = LP3971_LDO3, | ||
323 | .ops = &lp3971_ldo_ops, | ||
324 | .n_voltages = ARRAY_SIZE(ldo123_voltage_map), | ||
325 | .type = REGULATOR_VOLTAGE, | ||
326 | .owner = THIS_MODULE, | ||
327 | }, | ||
328 | { | ||
329 | .name = "LDO4", | ||
330 | .id = LP3971_LDO4, | ||
331 | .ops = &lp3971_ldo_ops, | ||
332 | .n_voltages = ARRAY_SIZE(ldo45_voltage_map), | ||
333 | .type = REGULATOR_VOLTAGE, | ||
334 | .owner = THIS_MODULE, | ||
335 | }, | ||
336 | { | ||
337 | .name = "LDO5", | ||
338 | .id = LP3971_LDO5, | ||
339 | .ops = &lp3971_ldo_ops, | ||
340 | .n_voltages = ARRAY_SIZE(ldo45_voltage_map), | ||
341 | .type = REGULATOR_VOLTAGE, | ||
342 | .owner = THIS_MODULE, | ||
343 | }, | ||
344 | { | ||
345 | .name = "DCDC1", | ||
346 | .id = LP3971_DCDC1, | ||
347 | .ops = &lp3971_dcdc_ops, | ||
348 | .n_voltages = ARRAY_SIZE(buck_voltage_map), | ||
349 | .type = REGULATOR_VOLTAGE, | ||
350 | .owner = THIS_MODULE, | ||
351 | }, | ||
352 | { | ||
353 | .name = "DCDC2", | ||
354 | .id = LP3971_DCDC2, | ||
355 | .ops = &lp3971_dcdc_ops, | ||
356 | .n_voltages = ARRAY_SIZE(buck_voltage_map), | ||
357 | .type = REGULATOR_VOLTAGE, | ||
358 | .owner = THIS_MODULE, | ||
359 | }, | ||
360 | { | ||
361 | .name = "DCDC3", | ||
362 | .id = LP3971_DCDC3, | ||
363 | .ops = &lp3971_dcdc_ops, | ||
364 | .n_voltages = ARRAY_SIZE(buck_voltage_map), | ||
365 | .type = REGULATOR_VOLTAGE, | ||
366 | .owner = THIS_MODULE, | ||
367 | }, | ||
368 | }; | ||
369 | |||
370 | static int lp3971_i2c_read(struct i2c_client *i2c, char reg, int count, | ||
371 | u16 *dest) | ||
372 | { | ||
373 | int ret; | ||
374 | |||
375 | if (count != 1) | ||
376 | return -EIO; | ||
377 | ret = i2c_smbus_read_byte_data(i2c, reg); | ||
378 | if (ret < 0 || count != 1) | ||
379 | return -EIO; | ||
380 | |||
381 | *dest = ret; | ||
382 | return 0; | ||
383 | } | ||
384 | |||
385 | static int lp3971_i2c_write(struct i2c_client *i2c, char reg, int count, | ||
386 | const u16 *src) | ||
387 | { | ||
388 | int ret; | ||
389 | |||
390 | if (count != 1) | ||
391 | return -EIO; | ||
392 | ret = i2c_smbus_write_byte_data(i2c, reg, *src); | ||
393 | if (ret >= 0) | ||
394 | return 0; | ||
395 | |||
396 | return ret; | ||
397 | } | ||
398 | |||
399 | static u8 lp3971_reg_read(struct lp3971 *lp3971, u8 reg) | ||
400 | { | ||
401 | u16 val = 0; | ||
402 | |||
403 | mutex_lock(&lp3971->io_lock); | ||
404 | |||
405 | lp3971_i2c_read(lp3971->i2c, reg, 1, &val); | ||
406 | |||
407 | dev_dbg(lp3971->dev, "reg read 0x%02x -> 0x%02x\n", (int)reg, | ||
408 | (unsigned)val&0xff); | ||
409 | |||
410 | mutex_unlock(&lp3971->io_lock); | ||
411 | |||
412 | return val & 0xff; | ||
413 | } | ||
414 | |||
415 | static int lp3971_set_bits(struct lp3971 *lp3971, u8 reg, u16 mask, u16 val) | ||
416 | { | ||
417 | u16 tmp; | ||
418 | int ret; | ||
419 | |||
420 | mutex_lock(&lp3971->io_lock); | ||
421 | |||
422 | ret = lp3971_i2c_read(lp3971->i2c, reg, 1, &tmp); | ||
423 | tmp = (tmp & ~mask) | val; | ||
424 | if (ret == 0) { | ||
425 | ret = lp3971_i2c_write(lp3971->i2c, reg, 1, &tmp); | ||
426 | dev_dbg(lp3971->dev, "reg write 0x%02x -> 0x%02x\n", (int)reg, | ||
427 | (unsigned)val&0xff); | ||
428 | } | ||
429 | mutex_unlock(&lp3971->io_lock); | ||
430 | |||
431 | return ret; | ||
432 | } | ||
433 | |||
434 | static int setup_regulators(struct lp3971 *lp3971, | ||
435 | struct lp3971_platform_data *pdata) | ||
436 | { | ||
437 | int i, err; | ||
438 | int num_regulators = pdata->num_regulators; | ||
439 | lp3971->num_regulators = num_regulators; | ||
440 | lp3971->rdev = kzalloc(sizeof(struct regulator_dev *) * num_regulators, | ||
441 | GFP_KERNEL); | ||
442 | |||
443 | /* Instantiate the regulators */ | ||
444 | for (i = 0; i < num_regulators; i++) { | ||
445 | int id = pdata->regulators[i].id; | ||
446 | lp3971->rdev[i] = regulator_register(®ulators[id], | ||
447 | lp3971->dev, pdata->regulators[i].initdata, lp3971); | ||
448 | |||
449 | err = IS_ERR(lp3971->rdev[i]); | ||
450 | if (err) { | ||
451 | dev_err(lp3971->dev, "regulator init failed: %d\n", | ||
452 | err); | ||
453 | goto error; | ||
454 | } | ||
455 | } | ||
456 | |||
457 | return 0; | ||
458 | error: | ||
459 | for (i = 0; i < num_regulators; i++) | ||
460 | if (lp3971->rdev[i]) | ||
461 | regulator_unregister(lp3971->rdev[i]); | ||
462 | kfree(lp3971->rdev); | ||
463 | lp3971->rdev = NULL; | ||
464 | return err; | ||
465 | } | ||
466 | |||
467 | static int __devinit lp3971_i2c_probe(struct i2c_client *i2c, | ||
468 | const struct i2c_device_id *id) | ||
469 | { | ||
470 | struct lp3971 *lp3971; | ||
471 | struct lp3971_platform_data *pdata = i2c->dev.platform_data; | ||
472 | int ret; | ||
473 | u16 val; | ||
474 | |||
475 | lp3971 = kzalloc(sizeof(struct lp3971), GFP_KERNEL); | ||
476 | if (lp3971 == NULL) { | ||
477 | ret = -ENOMEM; | ||
478 | goto err; | ||
479 | } | ||
480 | |||
481 | lp3971->i2c = i2c; | ||
482 | lp3971->dev = &i2c->dev; | ||
483 | i2c_set_clientdata(i2c, lp3971); | ||
484 | |||
485 | mutex_init(&lp3971->io_lock); | ||
486 | |||
487 | /* Detect LP3971 */ | ||
488 | ret = lp3971_i2c_read(i2c, LP3971_SYS_CONTROL1_REG, 1, &val); | ||
489 | if (ret == 0 && (val & SYS_CONTROL1_INIT_MASK) != SYS_CONTROL1_INIT_VAL) | ||
490 | ret = -ENODEV; | ||
491 | if (ret < 0) { | ||
492 | dev_err(&i2c->dev, "failed to detect device\n"); | ||
493 | goto err_detect; | ||
494 | } | ||
495 | |||
496 | if (pdata) { | ||
497 | ret = setup_regulators(lp3971, pdata); | ||
498 | if (ret < 0) | ||
499 | goto err_detect; | ||
500 | } else | ||
501 | dev_warn(lp3971->dev, "No platform init data supplied\n"); | ||
502 | |||
503 | return 0; | ||
504 | |||
505 | err_detect: | ||
506 | i2c_set_clientdata(i2c, NULL); | ||
507 | kfree(lp3971); | ||
508 | err: | ||
509 | return ret; | ||
510 | } | ||
511 | |||
512 | static int __devexit lp3971_i2c_remove(struct i2c_client *i2c) | ||
513 | { | ||
514 | struct lp3971 *lp3971 = i2c_get_clientdata(i2c); | ||
515 | int i; | ||
516 | for (i = 0; i < lp3971->num_regulators; i++) | ||
517 | if (lp3971->rdev[i]) | ||
518 | regulator_unregister(lp3971->rdev[i]); | ||
519 | kfree(lp3971->rdev); | ||
520 | i2c_set_clientdata(i2c, NULL); | ||
521 | kfree(lp3971); | ||
522 | |||
523 | return 0; | ||
524 | } | ||
525 | |||
526 | static const struct i2c_device_id lp3971_i2c_id[] = { | ||
527 | { "lp3971", 0 }, | ||
528 | { } | ||
529 | }; | ||
530 | MODULE_DEVICE_TABLE(i2c, lp3971_i2c_id); | ||
531 | |||
532 | static struct i2c_driver lp3971_i2c_driver = { | ||
533 | .driver = { | ||
534 | .name = "LP3971", | ||
535 | .owner = THIS_MODULE, | ||
536 | }, | ||
537 | .probe = lp3971_i2c_probe, | ||
538 | .remove = lp3971_i2c_remove, | ||
539 | .id_table = lp3971_i2c_id, | ||
540 | }; | ||
541 | |||
542 | static int __init lp3971_module_init(void) | ||
543 | { | ||
544 | int ret = -ENODEV; | ||
545 | |||
546 | ret = i2c_add_driver(&lp3971_i2c_driver); | ||
547 | if (ret != 0) | ||
548 | pr_err("Failed to register I2C driver: %d\n", ret); | ||
549 | |||
550 | return ret; | ||
551 | } | ||
552 | module_init(lp3971_module_init); | ||
553 | |||
554 | static void __exit lp3971_module_exit(void) | ||
555 | { | ||
556 | i2c_del_driver(&lp3971_i2c_driver); | ||
557 | } | ||
558 | module_exit(lp3971_module_exit); | ||
559 | |||
560 | MODULE_LICENSE("GPL"); | ||
561 | MODULE_AUTHOR("Marek Szyprowski <m.szyprowski@samsung.com>"); | ||
562 | MODULE_DESCRIPTION("LP3971 PMIC driver"); | ||
diff --git a/include/linux/regulator/lp3971.h b/include/linux/regulator/lp3971.h new file mode 100644 index 000000000000..61401649fe7d --- /dev/null +++ b/include/linux/regulator/lp3971.h | |||
@@ -0,0 +1,51 @@ | |||
1 | /* | ||
2 | * National Semiconductors LP3971 PMIC chip client interface | ||
3 | * | ||
4 | * Copyright (C) 2009 Samsung Electronics | ||
5 | * Author: Marek Szyprowski <m.szyprowski@samsung.com> | ||
6 | * | ||
7 | * Based on wm8400.h | ||
8 | * | ||
9 | * This program is free software; you can redistribute it and/or modify | ||
10 | * it under the terms of the GNU General Public License as published by | ||
11 | * the Free Software Foundation; either version 2 of the License, or | ||
12 | * (at your option) any later version. | ||
13 | * | ||
14 | * This program is distributed in the hope that it will be useful, | ||
15 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
16 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
17 | * GNU General Public License for more details. | ||
18 | * | ||
19 | * You should have received a copy of the GNU General Public License | ||
20 | * along with this program; if not, write to the Free Software | ||
21 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | ||
22 | */ | ||
23 | |||
24 | #ifndef __LINUX_REGULATOR_LP3971_H | ||
25 | #define __LINUX_REGULATOR_LP3971_H | ||
26 | |||
27 | #include <linux/regulator/machine.h> | ||
28 | |||
29 | #define LP3971_LDO1 0 | ||
30 | #define LP3971_LDO2 1 | ||
31 | #define LP3971_LDO3 2 | ||
32 | #define LP3971_LDO4 3 | ||
33 | #define LP3971_LDO5 4 | ||
34 | |||
35 | #define LP3971_DCDC1 5 | ||
36 | #define LP3971_DCDC2 6 | ||
37 | #define LP3971_DCDC3 7 | ||
38 | |||
39 | #define LP3971_NUM_REGULATORS 8 | ||
40 | |||
41 | struct lp3971_regulator_subdev { | ||
42 | int id; | ||
43 | struct regulator_init_data *initdata; | ||
44 | }; | ||
45 | |||
46 | struct lp3971_platform_data { | ||
47 | int num_regulators; | ||
48 | struct lp3971_regulator_subdev *regulators; | ||
49 | }; | ||
50 | |||
51 | #endif | ||