diff options
author | Mark Brown <broonie@opensource.wolfsonmicro.com> | 2012-02-02 08:51:23 -0500 |
---|---|---|
committer | Mark Brown <broonie@opensource.wolfsonmicro.com> | 2012-02-02 08:51:23 -0500 |
commit | fb87ef1a123fa85bca1b6ac693a65752a7d0c718 (patch) | |
tree | c70dc30c026f06f5d782e9bad141caa35e12e061 /drivers | |
parent | 62aa2b537c6f5957afd98e29f96897419ed5ebab (diff) | |
parent | 20a14b84f8d62ba9ad7acad1d67a2ffa3c06468b (diff) |
Merge branch 'regulator-drivers' into regulator-supply
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/regulator/Kconfig | 31 | ||||
-rw-r--r-- | drivers/regulator/Makefile | 5 | ||||
-rw-r--r-- | drivers/regulator/db8500-prcmu.c | 118 | ||||
-rw-r--r-- | drivers/regulator/dbx500-prcmu.c | 241 | ||||
-rw-r--r-- | drivers/regulator/dbx500-prcmu.h | 63 | ||||
-rw-r--r-- | drivers/regulator/max8997.c | 8 | ||||
-rw-r--r-- | drivers/regulator/mc13xxx-regulator-core.c | 2 | ||||
-rw-r--r-- | drivers/regulator/s5m8767.c | 832 | ||||
-rw-r--r-- | drivers/regulator/tps62360-regulator.c | 472 | ||||
-rw-r--r-- | drivers/regulator/tps65217-regulator.c | 493 | ||||
-rw-r--r-- | drivers/regulator/tps65910-regulator.c | 280 | ||||
-rw-r--r-- | drivers/regulator/wm8350-regulator.c | 4 |
12 files changed, 2427 insertions, 122 deletions
diff --git a/drivers/regulator/Kconfig b/drivers/regulator/Kconfig index 7a61b17ddd04..376824b865a4 100644 --- a/drivers/regulator/Kconfig +++ b/drivers/regulator/Kconfig | |||
@@ -136,6 +136,14 @@ config REGULATOR_MAX8998 | |||
136 | via I2C bus. The provided regulator is suitable for S3C6410 | 136 | via I2C bus. The provided regulator is suitable for S3C6410 |
137 | and S5PC1XX chips to control VCC_CORE and VCC_USIM voltages. | 137 | and S5PC1XX chips to control VCC_CORE and VCC_USIM voltages. |
138 | 138 | ||
139 | config REGULATOR_S5M8767 | ||
140 | tristate "Samsung S5M8767A voltage regulator" | ||
141 | depends on MFD_S5M_CORE | ||
142 | help | ||
143 | This driver supports a Samsung S5M8767A voltage output regulator | ||
144 | via I2C bus. S5M8767A have 9 Bucks and 28 LDOs output and | ||
145 | supports DVS mode with 8bits of output voltage control. | ||
146 | |||
139 | config REGULATOR_TWL4030 | 147 | config REGULATOR_TWL4030 |
140 | bool "TI TWL4030/TWL5030/TWL6030/TPS659x0 PMIC" | 148 | bool "TI TWL4030/TWL5030/TWL6030/TPS659x0 PMIC" |
141 | depends on TWL4030_CORE | 149 | depends on TWL4030_CORE |
@@ -267,6 +275,15 @@ config REGULATOR_TPS6507X | |||
267 | three step-down converters and two general-purpose LDO voltage regulators. | 275 | three step-down converters and two general-purpose LDO voltage regulators. |
268 | It supports TI's software based Class-2 SmartReflex implementation. | 276 | It supports TI's software based Class-2 SmartReflex implementation. |
269 | 277 | ||
278 | config REGULATOR_TPS65217 | ||
279 | tristate "TI TPS65217 Power regulators" | ||
280 | depends on MFD_TPS65217 | ||
281 | help | ||
282 | This driver supports TPS65217 voltage regulator chips. TPS65217 | ||
283 | provides three step-down converters and four general-purpose LDO | ||
284 | voltage regulators. It supports software based voltage control | ||
285 | for different voltage domains | ||
286 | |||
270 | config REGULATOR_TPS65912 | 287 | config REGULATOR_TPS65912 |
271 | tristate "TI TPS65912 Power regulator" | 288 | tristate "TI TPS65912 Power regulator" |
272 | depends on (MFD_TPS65912_I2C || MFD_TPS65912_SPI) | 289 | depends on (MFD_TPS65912_I2C || MFD_TPS65912_SPI) |
@@ -299,9 +316,13 @@ config REGULATOR_AB8500 | |||
299 | This driver supports the regulators found on the ST-Ericsson mixed | 316 | This driver supports the regulators found on the ST-Ericsson mixed |
300 | signal AB8500 PMIC | 317 | signal AB8500 PMIC |
301 | 318 | ||
319 | config REGULATOR_DBX500_PRCMU | ||
320 | bool | ||
321 | |||
302 | config REGULATOR_DB8500_PRCMU | 322 | config REGULATOR_DB8500_PRCMU |
303 | bool "ST-Ericsson DB8500 Voltage Domain Regulators" | 323 | bool "ST-Ericsson DB8500 Voltage Domain Regulators" |
304 | depends on MFD_DB8500_PRCMU | 324 | depends on MFD_DB8500_PRCMU |
325 | select REGULATOR_DBX500_PRCMU | ||
305 | help | 326 | help |
306 | This driver supports the voltage domain regulators controlled by the | 327 | This driver supports the voltage domain regulators controlled by the |
307 | DB8500 PRCMU | 328 | DB8500 PRCMU |
@@ -328,6 +349,16 @@ config REGULATOR_TPS65910 | |||
328 | help | 349 | help |
329 | This driver supports TPS65910 voltage regulator chips. | 350 | This driver supports TPS65910 voltage regulator chips. |
330 | 351 | ||
352 | config REGULATOR_TPS62360 | ||
353 | tristate "TI TPS62360 Power Regulator" | ||
354 | depends on I2C | ||
355 | select REGMAP_I2C | ||
356 | help | ||
357 | This driver supports TPS62360 voltage regulator chip. This | ||
358 | regulator is meant for processor core supply. This chip is | ||
359 | high-frequency synchronous step down dc-dc converter optimized | ||
360 | for battery-powered portable applications. | ||
361 | |||
331 | config REGULATOR_AAT2870 | 362 | config REGULATOR_AAT2870 |
332 | tristate "AnalogicTech AAT2870 Regulators" | 363 | tristate "AnalogicTech AAT2870 Regulators" |
333 | depends on MFD_AAT2870_CORE | 364 | depends on MFD_AAT2870_CORE |
diff --git a/drivers/regulator/Makefile b/drivers/regulator/Makefile index 503bac87715e..4cbf8c55f8a9 100644 --- a/drivers/regulator/Makefile +++ b/drivers/regulator/Makefile | |||
@@ -40,13 +40,18 @@ obj-$(CONFIG_REGULATOR_AB3100) += ab3100.o | |||
40 | obj-$(CONFIG_REGULATOR_TPS6105X) += tps6105x-regulator.o | 40 | obj-$(CONFIG_REGULATOR_TPS6105X) += tps6105x-regulator.o |
41 | obj-$(CONFIG_REGULATOR_TPS65023) += tps65023-regulator.o | 41 | obj-$(CONFIG_REGULATOR_TPS65023) += tps65023-regulator.o |
42 | obj-$(CONFIG_REGULATOR_TPS6507X) += tps6507x-regulator.o | 42 | obj-$(CONFIG_REGULATOR_TPS6507X) += tps6507x-regulator.o |
43 | obj-$(CONFIG_REGULATOR_TPS65217) += tps65217-regulator.o | ||
43 | obj-$(CONFIG_REGULATOR_TPS6524X) += tps6524x-regulator.o | 44 | obj-$(CONFIG_REGULATOR_TPS6524X) += tps6524x-regulator.o |
44 | obj-$(CONFIG_REGULATOR_TPS65912) += tps65912-regulator.o | 45 | obj-$(CONFIG_REGULATOR_TPS65912) += tps65912-regulator.o |
45 | obj-$(CONFIG_REGULATOR_88PM8607) += 88pm8607.o | 46 | obj-$(CONFIG_REGULATOR_88PM8607) += 88pm8607.o |
46 | obj-$(CONFIG_REGULATOR_ISL6271A) += isl6271a-regulator.o | 47 | obj-$(CONFIG_REGULATOR_ISL6271A) += isl6271a-regulator.o |
47 | obj-$(CONFIG_REGULATOR_AB8500) += ab8500.o | 48 | obj-$(CONFIG_REGULATOR_AB8500) += ab8500.o |
49 | obj-$(CONFIG_REGULATOR_DBX500_PRCMU) += dbx500-prcmu.o | ||
48 | obj-$(CONFIG_REGULATOR_DB8500_PRCMU) += db8500-prcmu.o | 50 | obj-$(CONFIG_REGULATOR_DB8500_PRCMU) += db8500-prcmu.o |
49 | obj-$(CONFIG_REGULATOR_TPS65910) += tps65910-regulator.o | 51 | obj-$(CONFIG_REGULATOR_TPS65910) += tps65910-regulator.o |
52 | obj-$(CONFIG_REGULATOR_TPS62360) += tps62360-regulator.o | ||
50 | obj-$(CONFIG_REGULATOR_AAT2870) += aat2870-regulator.o | 53 | obj-$(CONFIG_REGULATOR_AAT2870) += aat2870-regulator.o |
54 | obj-$(CONFIG_REGULATOR_S5M8767) += s5m8767.o | ||
55 | |||
51 | 56 | ||
52 | ccflags-$(CONFIG_REGULATOR_DEBUG) += -DDEBUG | 57 | ccflags-$(CONFIG_REGULATOR_DEBUG) += -DDEBUG |
diff --git a/drivers/regulator/db8500-prcmu.c b/drivers/regulator/db8500-prcmu.c index 515443fcd26b..4bd25e75efa0 100644 --- a/drivers/regulator/db8500-prcmu.c +++ b/drivers/regulator/db8500-prcmu.c | |||
@@ -18,74 +18,11 @@ | |||
18 | #include <linux/regulator/machine.h> | 18 | #include <linux/regulator/machine.h> |
19 | #include <linux/regulator/db8500-prcmu.h> | 19 | #include <linux/regulator/db8500-prcmu.h> |
20 | #include <linux/module.h> | 20 | #include <linux/module.h> |
21 | 21 | #include "dbx500-prcmu.h" | |
22 | /* | ||
23 | * power state reference count | ||
24 | */ | ||
25 | static int power_state_active_cnt; /* will initialize to zero */ | ||
26 | static DEFINE_SPINLOCK(power_state_active_lock); | ||
27 | |||
28 | static void power_state_active_enable(void) | ||
29 | { | ||
30 | unsigned long flags; | ||
31 | |||
32 | spin_lock_irqsave(&power_state_active_lock, flags); | ||
33 | power_state_active_cnt++; | ||
34 | spin_unlock_irqrestore(&power_state_active_lock, flags); | ||
35 | } | ||
36 | |||
37 | static int power_state_active_disable(void) | ||
38 | { | ||
39 | int ret = 0; | ||
40 | unsigned long flags; | ||
41 | |||
42 | spin_lock_irqsave(&power_state_active_lock, flags); | ||
43 | if (power_state_active_cnt <= 0) { | ||
44 | pr_err("power state: unbalanced enable/disable calls\n"); | ||
45 | ret = -EINVAL; | ||
46 | goto out; | ||
47 | } | ||
48 | |||
49 | power_state_active_cnt--; | ||
50 | out: | ||
51 | spin_unlock_irqrestore(&power_state_active_lock, flags); | ||
52 | return ret; | ||
53 | } | ||
54 | |||
55 | /* | ||
56 | * Exported interface for CPUIdle only. This function is called when interrupts | ||
57 | * are turned off. Hence, no locking. | ||
58 | */ | ||
59 | int power_state_active_is_enabled(void) | ||
60 | { | ||
61 | return (power_state_active_cnt > 0); | ||
62 | } | ||
63 | |||
64 | /** | ||
65 | * struct db8500_regulator_info - db8500 regulator information | ||
66 | * @dev: device pointer | ||
67 | * @desc: regulator description | ||
68 | * @rdev: regulator device pointer | ||
69 | * @is_enabled: status of the regulator | ||
70 | * @epod_id: id for EPOD (power domain) | ||
71 | * @is_ramret: RAM retention switch for EPOD (power domain) | ||
72 | * @operating_point: operating point (only for vape, to be removed) | ||
73 | * | ||
74 | */ | ||
75 | struct db8500_regulator_info { | ||
76 | struct device *dev; | ||
77 | struct regulator_desc desc; | ||
78 | struct regulator_dev *rdev; | ||
79 | bool is_enabled; | ||
80 | u16 epod_id; | ||
81 | bool is_ramret; | ||
82 | bool exclude_from_power_state; | ||
83 | unsigned int operating_point; | ||
84 | }; | ||
85 | 22 | ||
86 | static int db8500_regulator_enable(struct regulator_dev *rdev) | 23 | static int db8500_regulator_enable(struct regulator_dev *rdev) |
87 | { | 24 | { |
88 | struct db8500_regulator_info *info = rdev_get_drvdata(rdev); | 25 | struct dbx500_regulator_info *info = rdev_get_drvdata(rdev); |
89 | 26 | ||
90 | if (info == NULL) | 27 | if (info == NULL) |
91 | return -EINVAL; | 28 | return -EINVAL; |
@@ -93,16 +30,18 @@ static int db8500_regulator_enable(struct regulator_dev *rdev) | |||
93 | dev_vdbg(rdev_get_dev(rdev), "regulator-%s-enable\n", | 30 | dev_vdbg(rdev_get_dev(rdev), "regulator-%s-enable\n", |
94 | info->desc.name); | 31 | info->desc.name); |
95 | 32 | ||
96 | info->is_enabled = true; | 33 | if (!info->is_enabled) { |
97 | if (!info->exclude_from_power_state) | 34 | info->is_enabled = true; |
98 | power_state_active_enable(); | 35 | if (!info->exclude_from_power_state) |
36 | power_state_active_enable(); | ||
37 | } | ||
99 | 38 | ||
100 | return 0; | 39 | return 0; |
101 | } | 40 | } |
102 | 41 | ||
103 | static int db8500_regulator_disable(struct regulator_dev *rdev) | 42 | static int db8500_regulator_disable(struct regulator_dev *rdev) |
104 | { | 43 | { |
105 | struct db8500_regulator_info *info = rdev_get_drvdata(rdev); | 44 | struct dbx500_regulator_info *info = rdev_get_drvdata(rdev); |
106 | int ret = 0; | 45 | int ret = 0; |
107 | 46 | ||
108 | if (info == NULL) | 47 | if (info == NULL) |
@@ -111,16 +50,18 @@ static int db8500_regulator_disable(struct regulator_dev *rdev) | |||
111 | dev_vdbg(rdev_get_dev(rdev), "regulator-%s-disable\n", | 50 | dev_vdbg(rdev_get_dev(rdev), "regulator-%s-disable\n", |
112 | info->desc.name); | 51 | info->desc.name); |
113 | 52 | ||
114 | info->is_enabled = false; | 53 | if (info->is_enabled) { |
115 | if (!info->exclude_from_power_state) | 54 | info->is_enabled = false; |
116 | ret = power_state_active_disable(); | 55 | if (!info->exclude_from_power_state) |
56 | ret = power_state_active_disable(); | ||
57 | } | ||
117 | 58 | ||
118 | return ret; | 59 | return ret; |
119 | } | 60 | } |
120 | 61 | ||
121 | static int db8500_regulator_is_enabled(struct regulator_dev *rdev) | 62 | static int db8500_regulator_is_enabled(struct regulator_dev *rdev) |
122 | { | 63 | { |
123 | struct db8500_regulator_info *info = rdev_get_drvdata(rdev); | 64 | struct dbx500_regulator_info *info = rdev_get_drvdata(rdev); |
124 | 65 | ||
125 | if (info == NULL) | 66 | if (info == NULL) |
126 | return -EINVAL; | 67 | return -EINVAL; |
@@ -197,7 +138,7 @@ static int disable_epod(u16 epod_id, bool ramret) | |||
197 | */ | 138 | */ |
198 | static int db8500_regulator_switch_enable(struct regulator_dev *rdev) | 139 | static int db8500_regulator_switch_enable(struct regulator_dev *rdev) |
199 | { | 140 | { |
200 | struct db8500_regulator_info *info = rdev_get_drvdata(rdev); | 141 | struct dbx500_regulator_info *info = rdev_get_drvdata(rdev); |
201 | int ret; | 142 | int ret; |
202 | 143 | ||
203 | if (info == NULL) | 144 | if (info == NULL) |
@@ -221,7 +162,7 @@ out: | |||
221 | 162 | ||
222 | static int db8500_regulator_switch_disable(struct regulator_dev *rdev) | 163 | static int db8500_regulator_switch_disable(struct regulator_dev *rdev) |
223 | { | 164 | { |
224 | struct db8500_regulator_info *info = rdev_get_drvdata(rdev); | 165 | struct dbx500_regulator_info *info = rdev_get_drvdata(rdev); |
225 | int ret; | 166 | int ret; |
226 | 167 | ||
227 | if (info == NULL) | 168 | if (info == NULL) |
@@ -245,7 +186,7 @@ out: | |||
245 | 186 | ||
246 | static int db8500_regulator_switch_is_enabled(struct regulator_dev *rdev) | 187 | static int db8500_regulator_switch_is_enabled(struct regulator_dev *rdev) |
247 | { | 188 | { |
248 | struct db8500_regulator_info *info = rdev_get_drvdata(rdev); | 189 | struct dbx500_regulator_info *info = rdev_get_drvdata(rdev); |
249 | 190 | ||
250 | if (info == NULL) | 191 | if (info == NULL) |
251 | return -EINVAL; | 192 | return -EINVAL; |
@@ -266,8 +207,8 @@ static struct regulator_ops db8500_regulator_switch_ops = { | |||
266 | /* | 207 | /* |
267 | * Regulator information | 208 | * Regulator information |
268 | */ | 209 | */ |
269 | static struct db8500_regulator_info | 210 | static struct dbx500_regulator_info |
270 | db8500_regulator_info[DB8500_NUM_REGULATORS] = { | 211 | dbx500_regulator_info[DB8500_NUM_REGULATORS] = { |
271 | [DB8500_REGULATOR_VAPE] = { | 212 | [DB8500_REGULATOR_VAPE] = { |
272 | .desc = { | 213 | .desc = { |
273 | .name = "db8500-vape", | 214 | .name = "db8500-vape", |
@@ -476,12 +417,12 @@ static int __devinit db8500_regulator_probe(struct platform_device *pdev) | |||
476 | int i, err; | 417 | int i, err; |
477 | 418 | ||
478 | /* register all regulators */ | 419 | /* register all regulators */ |
479 | for (i = 0; i < ARRAY_SIZE(db8500_regulator_info); i++) { | 420 | for (i = 0; i < ARRAY_SIZE(dbx500_regulator_info); i++) { |
480 | struct db8500_regulator_info *info; | 421 | struct dbx500_regulator_info *info; |
481 | struct regulator_init_data *init_data = &db8500_init_data[i]; | 422 | struct regulator_init_data *init_data = &db8500_init_data[i]; |
482 | 423 | ||
483 | /* assign per-regulator data */ | 424 | /* assign per-regulator data */ |
484 | info = &db8500_regulator_info[i]; | 425 | info = &dbx500_regulator_info[i]; |
485 | info->dev = &pdev->dev; | 426 | info->dev = &pdev->dev; |
486 | 427 | ||
487 | /* register with the regulator framework */ | 428 | /* register with the regulator framework */ |
@@ -494,7 +435,7 @@ static int __devinit db8500_regulator_probe(struct platform_device *pdev) | |||
494 | 435 | ||
495 | /* if failing, unregister all earlier regulators */ | 436 | /* if failing, unregister all earlier regulators */ |
496 | while (--i >= 0) { | 437 | while (--i >= 0) { |
497 | info = &db8500_regulator_info[i]; | 438 | info = &dbx500_regulator_info[i]; |
498 | regulator_unregister(info->rdev); | 439 | regulator_unregister(info->rdev); |
499 | } | 440 | } |
500 | return err; | 441 | return err; |
@@ -503,17 +444,22 @@ static int __devinit db8500_regulator_probe(struct platform_device *pdev) | |||
503 | dev_dbg(rdev_get_dev(info->rdev), | 444 | dev_dbg(rdev_get_dev(info->rdev), |
504 | "regulator-%s-probed\n", info->desc.name); | 445 | "regulator-%s-probed\n", info->desc.name); |
505 | } | 446 | } |
447 | err = ux500_regulator_debug_init(pdev, | ||
448 | dbx500_regulator_info, | ||
449 | ARRAY_SIZE(dbx500_regulator_info)); | ||
506 | 450 | ||
507 | return 0; | 451 | return err; |
508 | } | 452 | } |
509 | 453 | ||
510 | static int __exit db8500_regulator_remove(struct platform_device *pdev) | 454 | static int __exit db8500_regulator_remove(struct platform_device *pdev) |
511 | { | 455 | { |
512 | int i; | 456 | int i; |
513 | 457 | ||
514 | for (i = 0; i < ARRAY_SIZE(db8500_regulator_info); i++) { | 458 | ux500_regulator_debug_exit(); |
515 | struct db8500_regulator_info *info; | 459 | |
516 | info = &db8500_regulator_info[i]; | 460 | for (i = 0; i < ARRAY_SIZE(dbx500_regulator_info); i++) { |
461 | struct dbx500_regulator_info *info; | ||
462 | info = &dbx500_regulator_info[i]; | ||
517 | 463 | ||
518 | dev_vdbg(rdev_get_dev(info->rdev), | 464 | dev_vdbg(rdev_get_dev(info->rdev), |
519 | "regulator-%s-remove\n", info->desc.name); | 465 | "regulator-%s-remove\n", info->desc.name); |
diff --git a/drivers/regulator/dbx500-prcmu.c b/drivers/regulator/dbx500-prcmu.c new file mode 100644 index 000000000000..f2e5ecdc5864 --- /dev/null +++ b/drivers/regulator/dbx500-prcmu.c | |||
@@ -0,0 +1,241 @@ | |||
1 | /* | ||
2 | * Copyright (C) ST-Ericsson SA 2010 | ||
3 | * | ||
4 | * License Terms: GNU General Public License v2 | ||
5 | * Authors: Sundar Iyer <sundar.iyer@stericsson.com> for ST-Ericsson | ||
6 | * Bengt Jonsson <bengt.g.jonsson@stericsson.com> for ST-Ericsson | ||
7 | * | ||
8 | * UX500 common part of Power domain regulators | ||
9 | */ | ||
10 | |||
11 | #include <linux/kernel.h> | ||
12 | #include <linux/err.h> | ||
13 | #include <linux/regulator/driver.h> | ||
14 | #include <linux/debugfs.h> | ||
15 | #include <linux/seq_file.h> | ||
16 | #include <linux/slab.h> | ||
17 | |||
18 | #include "dbx500-prcmu.h" | ||
19 | |||
20 | /* | ||
21 | * power state reference count | ||
22 | */ | ||
23 | static int power_state_active_cnt; /* will initialize to zero */ | ||
24 | static DEFINE_SPINLOCK(power_state_active_lock); | ||
25 | |||
26 | int power_state_active_get(void) | ||
27 | { | ||
28 | unsigned long flags; | ||
29 | int cnt; | ||
30 | |||
31 | spin_lock_irqsave(&power_state_active_lock, flags); | ||
32 | cnt = power_state_active_cnt; | ||
33 | spin_unlock_irqrestore(&power_state_active_lock, flags); | ||
34 | |||
35 | return cnt; | ||
36 | } | ||
37 | |||
38 | void power_state_active_enable(void) | ||
39 | { | ||
40 | unsigned long flags; | ||
41 | |||
42 | spin_lock_irqsave(&power_state_active_lock, flags); | ||
43 | power_state_active_cnt++; | ||
44 | spin_unlock_irqrestore(&power_state_active_lock, flags); | ||
45 | } | ||
46 | |||
47 | int power_state_active_disable(void) | ||
48 | { | ||
49 | int ret = 0; | ||
50 | unsigned long flags; | ||
51 | |||
52 | spin_lock_irqsave(&power_state_active_lock, flags); | ||
53 | if (power_state_active_cnt <= 0) { | ||
54 | pr_err("power state: unbalanced enable/disable calls\n"); | ||
55 | ret = -EINVAL; | ||
56 | goto out; | ||
57 | } | ||
58 | |||
59 | power_state_active_cnt--; | ||
60 | out: | ||
61 | spin_unlock_irqrestore(&power_state_active_lock, flags); | ||
62 | return ret; | ||
63 | } | ||
64 | |||
65 | #ifdef CONFIG_REGULATOR_DEBUG | ||
66 | |||
67 | static struct ux500_regulator_debug { | ||
68 | struct dentry *dir; | ||
69 | struct dentry *status_file; | ||
70 | struct dentry *power_state_cnt_file; | ||
71 | struct dbx500_regulator_info *regulator_array; | ||
72 | int num_regulators; | ||
73 | u8 *state_before_suspend; | ||
74 | u8 *state_after_suspend; | ||
75 | } rdebug; | ||
76 | |||
77 | void ux500_regulator_suspend_debug(void) | ||
78 | { | ||
79 | int i; | ||
80 | for (i = 0; i < rdebug.num_regulators; i++) | ||
81 | rdebug.state_before_suspend[i] = | ||
82 | rdebug.regulator_array[i].is_enabled; | ||
83 | } | ||
84 | |||
85 | void ux500_regulator_resume_debug(void) | ||
86 | { | ||
87 | int i; | ||
88 | for (i = 0; i < rdebug.num_regulators; i++) | ||
89 | rdebug.state_after_suspend[i] = | ||
90 | rdebug.regulator_array[i].is_enabled; | ||
91 | } | ||
92 | |||
93 | static int ux500_regulator_power_state_cnt_print(struct seq_file *s, void *p) | ||
94 | { | ||
95 | struct device *dev = s->private; | ||
96 | int err; | ||
97 | |||
98 | /* print power state count */ | ||
99 | err = seq_printf(s, "ux500-regulator power state count: %i\n", | ||
100 | power_state_active_get()); | ||
101 | if (err < 0) | ||
102 | dev_err(dev, "seq_printf overflow\n"); | ||
103 | |||
104 | return 0; | ||
105 | } | ||
106 | |||
107 | static int ux500_regulator_power_state_cnt_open(struct inode *inode, | ||
108 | struct file *file) | ||
109 | { | ||
110 | return single_open(file, ux500_regulator_power_state_cnt_print, | ||
111 | inode->i_private); | ||
112 | } | ||
113 | |||
114 | static const struct file_operations ux500_regulator_power_state_cnt_fops = { | ||
115 | .open = ux500_regulator_power_state_cnt_open, | ||
116 | .read = seq_read, | ||
117 | .llseek = seq_lseek, | ||
118 | .release = single_release, | ||
119 | .owner = THIS_MODULE, | ||
120 | }; | ||
121 | |||
122 | static int ux500_regulator_status_print(struct seq_file *s, void *p) | ||
123 | { | ||
124 | struct device *dev = s->private; | ||
125 | int err; | ||
126 | int i; | ||
127 | |||
128 | /* print dump header */ | ||
129 | err = seq_printf(s, "ux500-regulator status:\n"); | ||
130 | if (err < 0) | ||
131 | dev_err(dev, "seq_printf overflow\n"); | ||
132 | |||
133 | err = seq_printf(s, "%31s : %8s : %8s\n", "current", | ||
134 | "before", "after"); | ||
135 | if (err < 0) | ||
136 | dev_err(dev, "seq_printf overflow\n"); | ||
137 | |||
138 | for (i = 0; i < rdebug.num_regulators; i++) { | ||
139 | struct dbx500_regulator_info *info; | ||
140 | /* Access per-regulator data */ | ||
141 | info = &rdebug.regulator_array[i]; | ||
142 | |||
143 | /* print status */ | ||
144 | err = seq_printf(s, "%20s : %8s : %8s : %8s\n", info->desc.name, | ||
145 | info->is_enabled ? "enabled" : "disabled", | ||
146 | rdebug.state_before_suspend[i] ? "enabled" : "disabled", | ||
147 | rdebug.state_after_suspend[i] ? "enabled" : "disabled"); | ||
148 | if (err < 0) | ||
149 | dev_err(dev, "seq_printf overflow\n"); | ||
150 | } | ||
151 | |||
152 | return 0; | ||
153 | } | ||
154 | |||
155 | static int ux500_regulator_status_open(struct inode *inode, struct file *file) | ||
156 | { | ||
157 | return single_open(file, ux500_regulator_status_print, | ||
158 | inode->i_private); | ||
159 | } | ||
160 | |||
161 | static const struct file_operations ux500_regulator_status_fops = { | ||
162 | .open = ux500_regulator_status_open, | ||
163 | .read = seq_read, | ||
164 | .llseek = seq_lseek, | ||
165 | .release = single_release, | ||
166 | .owner = THIS_MODULE, | ||
167 | }; | ||
168 | |||
169 | int __attribute__((weak)) dbx500_regulator_testcase( | ||
170 | struct dbx500_regulator_info *regulator_info, | ||
171 | int num_regulators) | ||
172 | { | ||
173 | return 0; | ||
174 | } | ||
175 | |||
176 | int __devinit | ||
177 | ux500_regulator_debug_init(struct platform_device *pdev, | ||
178 | struct dbx500_regulator_info *regulator_info, | ||
179 | int num_regulators) | ||
180 | { | ||
181 | /* create directory */ | ||
182 | rdebug.dir = debugfs_create_dir("ux500-regulator", NULL); | ||
183 | if (!rdebug.dir) | ||
184 | goto exit_no_debugfs; | ||
185 | |||
186 | /* create "status" file */ | ||
187 | rdebug.status_file = debugfs_create_file("status", | ||
188 | S_IRUGO, rdebug.dir, &pdev->dev, | ||
189 | &ux500_regulator_status_fops); | ||
190 | if (!rdebug.status_file) | ||
191 | goto exit_destroy_dir; | ||
192 | |||
193 | /* create "power-state-count" file */ | ||
194 | rdebug.power_state_cnt_file = debugfs_create_file("power-state-count", | ||
195 | S_IRUGO, rdebug.dir, &pdev->dev, | ||
196 | &ux500_regulator_power_state_cnt_fops); | ||
197 | if (!rdebug.power_state_cnt_file) | ||
198 | goto exit_destroy_status; | ||
199 | |||
200 | rdebug.regulator_array = regulator_info; | ||
201 | rdebug.num_regulators = num_regulators; | ||
202 | |||
203 | rdebug.state_before_suspend = kzalloc(num_regulators, GFP_KERNEL); | ||
204 | if (!rdebug.state_before_suspend) { | ||
205 | dev_err(&pdev->dev, | ||
206 | "could not allocate memory for saving state\n"); | ||
207 | goto exit_destroy_power_state; | ||
208 | } | ||
209 | |||
210 | rdebug.state_after_suspend = kzalloc(num_regulators, GFP_KERNEL); | ||
211 | if (!rdebug.state_after_suspend) { | ||
212 | dev_err(&pdev->dev, | ||
213 | "could not allocate memory for saving state\n"); | ||
214 | goto exit_free; | ||
215 | } | ||
216 | |||
217 | dbx500_regulator_testcase(regulator_info, num_regulators); | ||
218 | return 0; | ||
219 | |||
220 | exit_free: | ||
221 | kfree(rdebug.state_before_suspend); | ||
222 | exit_destroy_power_state: | ||
223 | debugfs_remove(rdebug.power_state_cnt_file); | ||
224 | exit_destroy_status: | ||
225 | debugfs_remove(rdebug.status_file); | ||
226 | exit_destroy_dir: | ||
227 | debugfs_remove(rdebug.dir); | ||
228 | exit_no_debugfs: | ||
229 | dev_err(&pdev->dev, "failed to create debugfs entries.\n"); | ||
230 | return -ENOMEM; | ||
231 | } | ||
232 | |||
233 | int __devexit ux500_regulator_debug_exit(void) | ||
234 | { | ||
235 | debugfs_remove_recursive(rdebug.dir); | ||
236 | kfree(rdebug.state_after_suspend); | ||
237 | kfree(rdebug.state_before_suspend); | ||
238 | |||
239 | return 0; | ||
240 | } | ||
241 | #endif | ||
diff --git a/drivers/regulator/dbx500-prcmu.h b/drivers/regulator/dbx500-prcmu.h new file mode 100644 index 000000000000..e763883a44f4 --- /dev/null +++ b/drivers/regulator/dbx500-prcmu.h | |||
@@ -0,0 +1,63 @@ | |||
1 | /* | ||
2 | * Copyright (C) ST-Ericsson SA 2010 | ||
3 | * | ||
4 | * Author: Bengt Jonsson <bengt.jonsson@stericsson.com> for ST-Ericsson, | ||
5 | * Jonas Aaberg <jonas.aberg@stericsson.com> for ST-Ericsson | ||
6 | * | ||
7 | * License Terms: GNU General Public License v2 | ||
8 | * | ||
9 | */ | ||
10 | |||
11 | #ifndef DBX500_REGULATOR_H | ||
12 | #define DBX500_REGULATOR_H | ||
13 | |||
14 | #include <linux/platform_device.h> | ||
15 | |||
16 | /** | ||
17 | * struct dbx500_regulator_info - dbx500 regulator information | ||
18 | * @dev: device pointer | ||
19 | * @desc: regulator description | ||
20 | * @rdev: regulator device pointer | ||
21 | * @is_enabled: status of the regulator | ||
22 | * @epod_id: id for EPOD (power domain) | ||
23 | * @is_ramret: RAM retention switch for EPOD (power domain) | ||
24 | * @operating_point: operating point (only for vape, to be removed) | ||
25 | * | ||
26 | */ | ||
27 | struct dbx500_regulator_info { | ||
28 | struct device *dev; | ||
29 | struct regulator_desc desc; | ||
30 | struct regulator_dev *rdev; | ||
31 | bool is_enabled; | ||
32 | u16 epod_id; | ||
33 | bool is_ramret; | ||
34 | bool exclude_from_power_state; | ||
35 | unsigned int operating_point; | ||
36 | }; | ||
37 | |||
38 | void power_state_active_enable(void); | ||
39 | int power_state_active_disable(void); | ||
40 | |||
41 | |||
42 | #ifdef CONFIG_REGULATOR_DEBUG | ||
43 | int ux500_regulator_debug_init(struct platform_device *pdev, | ||
44 | struct dbx500_regulator_info *regulator_info, | ||
45 | int num_regulators); | ||
46 | |||
47 | int ux500_regulator_debug_exit(void); | ||
48 | #else | ||
49 | |||
50 | static inline int ux500_regulator_debug_init(struct platform_device *pdev, | ||
51 | struct dbx500_regulator_info *regulator_info, | ||
52 | int num_regulators) | ||
53 | { | ||
54 | return 0; | ||
55 | } | ||
56 | |||
57 | static inline int ux500_regulator_debug_exit(void) | ||
58 | { | ||
59 | return 0; | ||
60 | } | ||
61 | |||
62 | #endif | ||
63 | #endif | ||
diff --git a/drivers/regulator/max8997.c b/drivers/regulator/max8997.c index d26e8646277b..bb7cd9df9487 100644 --- a/drivers/regulator/max8997.c +++ b/drivers/regulator/max8997.c | |||
@@ -908,13 +908,13 @@ static struct regulator_desc regulators[] = { | |||
908 | }, | 908 | }, |
909 | regulator_desc_buck(7), | 909 | regulator_desc_buck(7), |
910 | { | 910 | { |
911 | .name = "EN32KHz AP", | 911 | .name = "EN32KHz_AP", |
912 | .id = MAX8997_EN32KHZ_AP, | 912 | .id = MAX8997_EN32KHZ_AP, |
913 | .ops = &max8997_fixedvolt_ops, | 913 | .ops = &max8997_fixedvolt_ops, |
914 | .type = REGULATOR_VOLTAGE, | 914 | .type = REGULATOR_VOLTAGE, |
915 | .owner = THIS_MODULE, | 915 | .owner = THIS_MODULE, |
916 | }, { | 916 | }, { |
917 | .name = "EN32KHz CP", | 917 | .name = "EN32KHz_CP", |
918 | .id = MAX8997_EN32KHZ_CP, | 918 | .id = MAX8997_EN32KHZ_CP, |
919 | .ops = &max8997_fixedvolt_ops, | 919 | .ops = &max8997_fixedvolt_ops, |
920 | .type = REGULATOR_VOLTAGE, | 920 | .type = REGULATOR_VOLTAGE, |
@@ -938,7 +938,7 @@ static struct regulator_desc regulators[] = { | |||
938 | .type = REGULATOR_VOLTAGE, | 938 | .type = REGULATOR_VOLTAGE, |
939 | .owner = THIS_MODULE, | 939 | .owner = THIS_MODULE, |
940 | }, { | 940 | }, { |
941 | .name = "CHARGER CV", | 941 | .name = "CHARGER_CV", |
942 | .id = MAX8997_CHARGER_CV, | 942 | .id = MAX8997_CHARGER_CV, |
943 | .ops = &max8997_fixedstate_ops, | 943 | .ops = &max8997_fixedstate_ops, |
944 | .type = REGULATOR_VOLTAGE, | 944 | .type = REGULATOR_VOLTAGE, |
@@ -950,7 +950,7 @@ static struct regulator_desc regulators[] = { | |||
950 | .type = REGULATOR_CURRENT, | 950 | .type = REGULATOR_CURRENT, |
951 | .owner = THIS_MODULE, | 951 | .owner = THIS_MODULE, |
952 | }, { | 952 | }, { |
953 | .name = "CHARGER TOPOFF", | 953 | .name = "CHARGER_TOPOFF", |
954 | .id = MAX8997_CHARGER_TOPOFF, | 954 | .id = MAX8997_CHARGER_TOPOFF, |
955 | .ops = &max8997_charger_fixedstate_ops, | 955 | .ops = &max8997_charger_fixedstate_ops, |
956 | .type = REGULATOR_CURRENT, | 956 | .type = REGULATOR_CURRENT, |
diff --git a/drivers/regulator/mc13xxx-regulator-core.c b/drivers/regulator/mc13xxx-regulator-core.c index 80ecafef1bc3..62dcd0a432bb 100644 --- a/drivers/regulator/mc13xxx-regulator-core.c +++ b/drivers/regulator/mc13xxx-regulator-core.c | |||
@@ -254,6 +254,7 @@ int __devinit mc13xxx_get_num_regulators_dt(struct platform_device *pdev) | |||
254 | 254 | ||
255 | return num; | 255 | return num; |
256 | } | 256 | } |
257 | EXPORT_SYMBOL_GPL(mc13xxx_get_num_regulators_dt); | ||
257 | 258 | ||
258 | struct mc13xxx_regulator_init_data * __devinit mc13xxx_parse_regulators_dt( | 259 | struct mc13xxx_regulator_init_data * __devinit mc13xxx_parse_regulators_dt( |
259 | struct platform_device *pdev, struct mc13xxx_regulator *regulators, | 260 | struct platform_device *pdev, struct mc13xxx_regulator *regulators, |
@@ -291,6 +292,7 @@ struct mc13xxx_regulator_init_data * __devinit mc13xxx_parse_regulators_dt( | |||
291 | 292 | ||
292 | return data; | 293 | return data; |
293 | } | 294 | } |
295 | EXPORT_SYMBOL_GPL(mc13xxx_parse_regulators_dt); | ||
294 | #endif | 296 | #endif |
295 | 297 | ||
296 | MODULE_LICENSE("GPL v2"); | 298 | MODULE_LICENSE("GPL v2"); |
diff --git a/drivers/regulator/s5m8767.c b/drivers/regulator/s5m8767.c new file mode 100644 index 000000000000..5b00e5ac70cd --- /dev/null +++ b/drivers/regulator/s5m8767.c | |||
@@ -0,0 +1,832 @@ | |||
1 | /* | ||
2 | * s5m8767.c | ||
3 | * | ||
4 | * Copyright (c) 2011 Samsung Electronics Co., Ltd | ||
5 | * http://www.samsung.com | ||
6 | * | ||
7 | * This program is free software; you can redistribute it and/or modify it | ||
8 | * under the terms of the GNU General Public License as published by the | ||
9 | * Free Software Foundation; either version 2 of the License, or (at your | ||
10 | * option) any later version. | ||
11 | * | ||
12 | */ | ||
13 | |||
14 | #include <linux/bug.h> | ||
15 | #include <linux/delay.h> | ||
16 | #include <linux/err.h> | ||
17 | #include <linux/gpio.h> | ||
18 | #include <linux/slab.h> | ||
19 | #include <linux/module.h> | ||
20 | #include <linux/platform_device.h> | ||
21 | #include <linux/regulator/driver.h> | ||
22 | #include <linux/regulator/machine.h> | ||
23 | #include <linux/mfd/s5m87xx/s5m-core.h> | ||
24 | #include <linux/mfd/s5m87xx/s5m-pmic.h> | ||
25 | |||
26 | struct s5m8767_info { | ||
27 | struct device *dev; | ||
28 | struct s5m87xx_dev *iodev; | ||
29 | int num_regulators; | ||
30 | struct regulator_dev **rdev; | ||
31 | |||
32 | int ramp_delay; | ||
33 | bool buck2_ramp; | ||
34 | bool buck3_ramp; | ||
35 | bool buck4_ramp; | ||
36 | |||
37 | bool buck2_gpiodvs; | ||
38 | bool buck3_gpiodvs; | ||
39 | bool buck4_gpiodvs; | ||
40 | u8 buck2_vol[8]; | ||
41 | u8 buck3_vol[8]; | ||
42 | u8 buck4_vol[8]; | ||
43 | int buck_gpios[3]; | ||
44 | int buck_gpioindex; | ||
45 | }; | ||
46 | |||
47 | struct s5m_voltage_desc { | ||
48 | int max; | ||
49 | int min; | ||
50 | int step; | ||
51 | }; | ||
52 | |||
53 | static const struct s5m_voltage_desc buck_voltage_val1 = { | ||
54 | .max = 2225000, | ||
55 | .min = 650000, | ||
56 | .step = 6250, | ||
57 | }; | ||
58 | |||
59 | static const struct s5m_voltage_desc buck_voltage_val2 = { | ||
60 | .max = 1600000, | ||
61 | .min = 600000, | ||
62 | .step = 6250, | ||
63 | }; | ||
64 | |||
65 | static const struct s5m_voltage_desc buck_voltage_val3 = { | ||
66 | .max = 3000000, | ||
67 | .min = 750000, | ||
68 | .step = 12500, | ||
69 | }; | ||
70 | |||
71 | static const struct s5m_voltage_desc ldo_voltage_val1 = { | ||
72 | .max = 3950000, | ||
73 | .min = 800000, | ||
74 | .step = 50000, | ||
75 | }; | ||
76 | |||
77 | static const struct s5m_voltage_desc ldo_voltage_val2 = { | ||
78 | .max = 2375000, | ||
79 | .min = 800000, | ||
80 | .step = 25000, | ||
81 | }; | ||
82 | |||
83 | static const struct s5m_voltage_desc *reg_voltage_map[] = { | ||
84 | [S5M8767_LDO1] = &ldo_voltage_val2, | ||
85 | [S5M8767_LDO2] = &ldo_voltage_val2, | ||
86 | [S5M8767_LDO3] = &ldo_voltage_val1, | ||
87 | [S5M8767_LDO4] = &ldo_voltage_val1, | ||
88 | [S5M8767_LDO5] = &ldo_voltage_val1, | ||
89 | [S5M8767_LDO6] = &ldo_voltage_val2, | ||
90 | [S5M8767_LDO7] = &ldo_voltage_val2, | ||
91 | [S5M8767_LDO8] = &ldo_voltage_val2, | ||
92 | [S5M8767_LDO9] = &ldo_voltage_val1, | ||
93 | [S5M8767_LDO10] = &ldo_voltage_val1, | ||
94 | [S5M8767_LDO11] = &ldo_voltage_val1, | ||
95 | [S5M8767_LDO12] = &ldo_voltage_val1, | ||
96 | [S5M8767_LDO13] = &ldo_voltage_val1, | ||
97 | [S5M8767_LDO14] = &ldo_voltage_val1, | ||
98 | [S5M8767_LDO15] = &ldo_voltage_val2, | ||
99 | [S5M8767_LDO16] = &ldo_voltage_val1, | ||
100 | [S5M8767_LDO17] = &ldo_voltage_val1, | ||
101 | [S5M8767_LDO18] = &ldo_voltage_val1, | ||
102 | [S5M8767_LDO19] = &ldo_voltage_val1, | ||
103 | [S5M8767_LDO20] = &ldo_voltage_val1, | ||
104 | [S5M8767_LDO21] = &ldo_voltage_val1, | ||
105 | [S5M8767_LDO22] = &ldo_voltage_val1, | ||
106 | [S5M8767_LDO23] = &ldo_voltage_val1, | ||
107 | [S5M8767_LDO24] = &ldo_voltage_val1, | ||
108 | [S5M8767_LDO25] = &ldo_voltage_val1, | ||
109 | [S5M8767_LDO26] = &ldo_voltage_val1, | ||
110 | [S5M8767_LDO27] = &ldo_voltage_val1, | ||
111 | [S5M8767_LDO28] = &ldo_voltage_val1, | ||
112 | [S5M8767_BUCK1] = &buck_voltage_val1, | ||
113 | [S5M8767_BUCK2] = &buck_voltage_val2, | ||
114 | [S5M8767_BUCK3] = &buck_voltage_val2, | ||
115 | [S5M8767_BUCK4] = &buck_voltage_val2, | ||
116 | [S5M8767_BUCK5] = &buck_voltage_val1, | ||
117 | [S5M8767_BUCK6] = &buck_voltage_val1, | ||
118 | [S5M8767_BUCK7] = NULL, | ||
119 | [S5M8767_BUCK8] = NULL, | ||
120 | [S5M8767_BUCK9] = &buck_voltage_val3, | ||
121 | }; | ||
122 | |||
123 | static int s5m8767_list_voltage(struct regulator_dev *rdev, | ||
124 | unsigned int selector) | ||
125 | { | ||
126 | const struct s5m_voltage_desc *desc; | ||
127 | int reg_id = rdev_get_id(rdev); | ||
128 | int val; | ||
129 | |||
130 | if (reg_id >= ARRAY_SIZE(reg_voltage_map) || reg_id < 0) | ||
131 | return -EINVAL; | ||
132 | |||
133 | desc = reg_voltage_map[reg_id]; | ||
134 | if (desc == NULL) | ||
135 | return -EINVAL; | ||
136 | |||
137 | val = desc->min + desc->step * selector; | ||
138 | if (val > desc->max) | ||
139 | return -EINVAL; | ||
140 | |||
141 | return val; | ||
142 | } | ||
143 | |||
144 | static int s5m8767_get_register(struct regulator_dev *rdev, int *reg) | ||
145 | { | ||
146 | int reg_id = rdev_get_id(rdev); | ||
147 | |||
148 | switch (reg_id) { | ||
149 | case S5M8767_LDO1 ... S5M8767_LDO2: | ||
150 | *reg = S5M8767_REG_LDO1CTRL + (reg_id - S5M8767_LDO1); | ||
151 | break; | ||
152 | case S5M8767_LDO3 ... S5M8767_LDO28: | ||
153 | *reg = S5M8767_REG_LDO3CTRL + (reg_id - S5M8767_LDO3); | ||
154 | break; | ||
155 | case S5M8767_BUCK1: | ||
156 | *reg = S5M8767_REG_BUCK1CTRL1; | ||
157 | break; | ||
158 | case S5M8767_BUCK2 ... S5M8767_BUCK4: | ||
159 | *reg = S5M8767_REG_BUCK2CTRL + (reg_id - S5M8767_BUCK2) * 9; | ||
160 | break; | ||
161 | case S5M8767_BUCK5: | ||
162 | *reg = S5M8767_REG_BUCK5CTRL1; | ||
163 | break; | ||
164 | case S5M8767_BUCK6 ... S5M8767_BUCK9: | ||
165 | *reg = S5M8767_REG_BUCK6CTRL1 + (reg_id - S5M8767_BUCK6) * 2; | ||
166 | break; | ||
167 | default: | ||
168 | return -EINVAL; | ||
169 | } | ||
170 | |||
171 | return 0; | ||
172 | } | ||
173 | |||
174 | static int s5m8767_reg_is_enabled(struct regulator_dev *rdev) | ||
175 | { | ||
176 | struct s5m8767_info *s5m8767 = rdev_get_drvdata(rdev); | ||
177 | int ret, reg; | ||
178 | int mask = 0xc0, pattern = 0xc0; | ||
179 | u8 val; | ||
180 | |||
181 | ret = s5m8767_get_register(rdev, ®); | ||
182 | if (ret == -EINVAL) | ||
183 | return 1; | ||
184 | else if (ret) | ||
185 | return ret; | ||
186 | |||
187 | ret = s5m_reg_read(s5m8767->iodev, reg, &val); | ||
188 | if (ret) | ||
189 | return ret; | ||
190 | |||
191 | return (val & mask) == pattern; | ||
192 | } | ||
193 | |||
194 | static int s5m8767_reg_enable(struct regulator_dev *rdev) | ||
195 | { | ||
196 | struct s5m8767_info *s5m8767 = rdev_get_drvdata(rdev); | ||
197 | int ret, reg; | ||
198 | int mask = 0xc0, pattern = 0xc0; | ||
199 | |||
200 | ret = s5m8767_get_register(rdev, ®); | ||
201 | if (ret) | ||
202 | return ret; | ||
203 | |||
204 | return s5m_reg_update(s5m8767->iodev, reg, pattern, mask); | ||
205 | } | ||
206 | |||
207 | static int s5m8767_reg_disable(struct regulator_dev *rdev) | ||
208 | { | ||
209 | struct s5m8767_info *s5m8767 = rdev_get_drvdata(rdev); | ||
210 | int ret, reg; | ||
211 | int mask = 0xc0, pattern = 0xc0; | ||
212 | |||
213 | ret = s5m8767_get_register(rdev, ®); | ||
214 | if (ret) | ||
215 | return ret; | ||
216 | |||
217 | return s5m_reg_update(s5m8767->iodev, reg, ~pattern, mask); | ||
218 | } | ||
219 | |||
220 | static int s5m8767_get_voltage_register(struct regulator_dev *rdev, int *_reg) | ||
221 | { | ||
222 | int reg_id = rdev_get_id(rdev); | ||
223 | int reg; | ||
224 | |||
225 | switch (reg_id) { | ||
226 | case S5M8767_LDO1 ... S5M8767_LDO2: | ||
227 | reg = S5M8767_REG_LDO1CTRL + (reg_id - S5M8767_LDO1); | ||
228 | break; | ||
229 | case S5M8767_LDO3 ... S5M8767_LDO28: | ||
230 | reg = S5M8767_REG_LDO3CTRL + (reg_id - S5M8767_LDO3); | ||
231 | break; | ||
232 | case S5M8767_BUCK1: | ||
233 | reg = S5M8767_REG_BUCK1CTRL2; | ||
234 | break; | ||
235 | case S5M8767_BUCK2: | ||
236 | reg = S5M8767_REG_BUCK2DVS1; | ||
237 | break; | ||
238 | case S5M8767_BUCK3: | ||
239 | reg = S5M8767_REG_BUCK3DVS1; | ||
240 | break; | ||
241 | case S5M8767_BUCK4: | ||
242 | reg = S5M8767_REG_BUCK4DVS1; | ||
243 | break; | ||
244 | case S5M8767_BUCK5: | ||
245 | reg = S5M8767_REG_BUCK5CTRL2; | ||
246 | break; | ||
247 | case S5M8767_BUCK6 ... S5M8767_BUCK9: | ||
248 | reg = S5M8767_REG_BUCK6CTRL2 + (reg_id - S5M8767_BUCK6) * 2; | ||
249 | break; | ||
250 | default: | ||
251 | return -EINVAL; | ||
252 | } | ||
253 | |||
254 | *_reg = reg; | ||
255 | |||
256 | return 0; | ||
257 | } | ||
258 | |||
259 | static int s5m8767_get_voltage_sel(struct regulator_dev *rdev) | ||
260 | { | ||
261 | struct s5m8767_info *s5m8767 = rdev_get_drvdata(rdev); | ||
262 | int reg, mask = 0xff, ret; | ||
263 | int reg_id = rdev_get_id(rdev); | ||
264 | u8 val; | ||
265 | |||
266 | ret = s5m8767_get_voltage_register(rdev, ®); | ||
267 | if (ret) | ||
268 | return ret; | ||
269 | |||
270 | switch (reg_id) { | ||
271 | case S5M8767_LDO1 ... S5M8767_LDO28: | ||
272 | mask = 0x3f; | ||
273 | break; | ||
274 | case S5M8767_BUCK2: | ||
275 | if (s5m8767->buck2_gpiodvs) | ||
276 | reg += s5m8767->buck_gpioindex; | ||
277 | break; | ||
278 | case S5M8767_BUCK3: | ||
279 | if (s5m8767->buck3_gpiodvs) | ||
280 | reg += s5m8767->buck_gpioindex; | ||
281 | break; | ||
282 | case S5M8767_BUCK4: | ||
283 | if (s5m8767->buck4_gpiodvs) | ||
284 | reg += s5m8767->buck_gpioindex; | ||
285 | break; | ||
286 | } | ||
287 | |||
288 | ret = s5m_reg_read(s5m8767->iodev, reg, &val); | ||
289 | if (ret) | ||
290 | return ret; | ||
291 | |||
292 | val &= mask; | ||
293 | |||
294 | return val; | ||
295 | } | ||
296 | |||
297 | static inline int s5m8767_convert_voltage( | ||
298 | const struct s5m_voltage_desc *desc, | ||
299 | int min_vol, int max_vol) | ||
300 | { | ||
301 | int out_vol = 0; | ||
302 | |||
303 | if (desc == NULL) | ||
304 | return -EINVAL; | ||
305 | |||
306 | if (max_vol < desc->min || min_vol > desc->max) | ||
307 | return -EINVAL; | ||
308 | |||
309 | out_vol = (min_vol - desc->min) / desc->step; | ||
310 | |||
311 | if (desc->min + desc->step * out_vol > max_vol) | ||
312 | return -EINVAL; | ||
313 | |||
314 | return out_vol; | ||
315 | } | ||
316 | |||
317 | static int s5m8767_set_voltage(struct regulator_dev *rdev, | ||
318 | int min_uV, int max_uV, unsigned *selector) | ||
319 | { | ||
320 | struct s5m8767_info *s5m8767 = rdev_get_drvdata(rdev); | ||
321 | int min_vol = min_uV, max_vol = max_uV; | ||
322 | const struct s5m_voltage_desc *desc; | ||
323 | int reg_id = rdev_get_id(rdev); | ||
324 | int reg, mask, ret; | ||
325 | int i; | ||
326 | u8 val; | ||
327 | |||
328 | switch (reg_id) { | ||
329 | case S5M8767_LDO1 ... S5M8767_LDO28: | ||
330 | mask = 0x3f; | ||
331 | break; | ||
332 | case S5M8767_BUCK1 ... S5M8767_BUCK6: | ||
333 | mask = 0xff; | ||
334 | break; | ||
335 | case S5M8767_BUCK7 ... S5M8767_BUCK8: | ||
336 | return -EINVAL; | ||
337 | case S5M8767_BUCK9: | ||
338 | mask = 0xff; | ||
339 | break; | ||
340 | default: | ||
341 | return -EINVAL; | ||
342 | } | ||
343 | |||
344 | desc = reg_voltage_map[reg_id]; | ||
345 | |||
346 | i = s5m8767_convert_voltage(desc, min_vol, max_vol); | ||
347 | if (i < 0) | ||
348 | return i; | ||
349 | |||
350 | ret = s5m8767_get_voltage_register(rdev, ®); | ||
351 | if (ret) | ||
352 | return ret; | ||
353 | |||
354 | s5m_reg_read(s5m8767->iodev, reg, &val); | ||
355 | val = val & mask; | ||
356 | |||
357 | ret = s5m_reg_write(s5m8767->iodev, reg, val); | ||
358 | *selector = i; | ||
359 | |||
360 | return ret; | ||
361 | } | ||
362 | |||
363 | static inline void s5m8767_set_high(struct s5m8767_info *s5m8767) | ||
364 | { | ||
365 | int temp_index = s5m8767->buck_gpioindex; | ||
366 | |||
367 | gpio_set_value(s5m8767->buck_gpios[0], (temp_index >> 2) & 0x1); | ||
368 | gpio_set_value(s5m8767->buck_gpios[1], (temp_index >> 1) & 0x1); | ||
369 | gpio_set_value(s5m8767->buck_gpios[2], temp_index & 0x1); | ||
370 | } | ||
371 | |||
372 | static inline void s5m8767_set_low(struct s5m8767_info *s5m8767) | ||
373 | { | ||
374 | int temp_index = s5m8767->buck_gpioindex; | ||
375 | |||
376 | gpio_set_value(s5m8767->buck_gpios[2], temp_index & 0x1); | ||
377 | gpio_set_value(s5m8767->buck_gpios[1], (temp_index >> 1) & 0x1); | ||
378 | gpio_set_value(s5m8767->buck_gpios[0], (temp_index >> 2) & 0x1); | ||
379 | } | ||
380 | |||
381 | static int s5m8767_set_voltage_buck(struct regulator_dev *rdev, | ||
382 | int min_uV, int max_uV, unsigned *selector) | ||
383 | { | ||
384 | struct s5m8767_info *s5m8767 = rdev_get_drvdata(rdev); | ||
385 | int reg_id = rdev_get_id(rdev); | ||
386 | const struct s5m_voltage_desc *desc; | ||
387 | int new_val, old_val, i = 0; | ||
388 | int min_vol = min_uV, max_vol = max_uV; | ||
389 | |||
390 | if (reg_id < S5M8767_BUCK1 || reg_id > S5M8767_BUCK6) | ||
391 | return -EINVAL; | ||
392 | |||
393 | switch (reg_id) { | ||
394 | case S5M8767_BUCK1: | ||
395 | return s5m8767_set_voltage(rdev, min_uV, max_uV, selector); | ||
396 | case S5M8767_BUCK2 ... S5M8767_BUCK4: | ||
397 | break; | ||
398 | case S5M8767_BUCK5 ... S5M8767_BUCK6: | ||
399 | return s5m8767_set_voltage(rdev, min_uV, max_uV, selector); | ||
400 | case S5M8767_BUCK9: | ||
401 | return s5m8767_set_voltage(rdev, min_uV, max_uV, selector); | ||
402 | } | ||
403 | |||
404 | desc = reg_voltage_map[reg_id]; | ||
405 | new_val = s5m8767_convert_voltage(desc, min_vol, max_vol); | ||
406 | if (new_val < 0) | ||
407 | return new_val; | ||
408 | |||
409 | switch (reg_id) { | ||
410 | case S5M8767_BUCK2: | ||
411 | if (s5m8767->buck2_gpiodvs) { | ||
412 | while (s5m8767->buck2_vol[i] != new_val) | ||
413 | i++; | ||
414 | } else | ||
415 | return s5m8767_set_voltage(rdev, min_uV, | ||
416 | max_uV, selector); | ||
417 | break; | ||
418 | case S5M8767_BUCK3: | ||
419 | if (s5m8767->buck3_gpiodvs) { | ||
420 | while (s5m8767->buck3_vol[i] != new_val) | ||
421 | i++; | ||
422 | } else | ||
423 | return s5m8767_set_voltage(rdev, min_uV, | ||
424 | max_uV, selector); | ||
425 | break; | ||
426 | case S5M8767_BUCK4: | ||
427 | if (s5m8767->buck3_gpiodvs) { | ||
428 | while (s5m8767->buck4_vol[i] != new_val) | ||
429 | i++; | ||
430 | } else | ||
431 | return s5m8767_set_voltage(rdev, min_uV, | ||
432 | max_uV, selector); | ||
433 | break; | ||
434 | } | ||
435 | |||
436 | old_val = s5m8767->buck_gpioindex; | ||
437 | s5m8767->buck_gpioindex = i; | ||
438 | |||
439 | if (i > old_val) | ||
440 | s5m8767_set_high(s5m8767); | ||
441 | else | ||
442 | s5m8767_set_low(s5m8767); | ||
443 | |||
444 | *selector = new_val; | ||
445 | return 0; | ||
446 | } | ||
447 | |||
448 | static int s5m8767_set_voltage_time_sel(struct regulator_dev *rdev, | ||
449 | unsigned int old_sel, | ||
450 | unsigned int new_sel) | ||
451 | { | ||
452 | struct s5m8767_info *s5m8767 = rdev_get_drvdata(rdev); | ||
453 | const struct s5m_voltage_desc *desc; | ||
454 | int reg_id = rdev_get_id(rdev); | ||
455 | int mask; | ||
456 | int new_val, old_val; | ||
457 | |||
458 | switch (reg_id) { | ||
459 | case S5M8767_LDO1 ... S5M8767_LDO28: | ||
460 | mask = 0x3f; | ||
461 | break; | ||
462 | case S5M8767_BUCK1 ... S5M8767_BUCK6: | ||
463 | mask = 0xff; | ||
464 | break; | ||
465 | case S5M8767_BUCK7 ... S5M8767_BUCK8: | ||
466 | return -EINVAL; | ||
467 | case S5M8767_BUCK9: | ||
468 | mask = 0xff; | ||
469 | break; | ||
470 | default: | ||
471 | return -EINVAL; | ||
472 | } | ||
473 | desc = reg_voltage_map[reg_id]; | ||
474 | |||
475 | new_val = s5m8767_convert_voltage(desc, new_sel, new_sel); | ||
476 | if (new_val < 0) | ||
477 | return new_val; | ||
478 | |||
479 | old_val = s5m8767_convert_voltage(desc, old_sel, old_sel); | ||
480 | if (old_val < 0) | ||
481 | return old_val; | ||
482 | |||
483 | if (old_sel < new_sel) | ||
484 | return DIV_ROUND_UP(desc->step * (new_val - old_val), | ||
485 | s5m8767->ramp_delay); | ||
486 | else | ||
487 | return 0; | ||
488 | } | ||
489 | |||
490 | static struct regulator_ops s5m8767_ldo_ops = { | ||
491 | .list_voltage = s5m8767_list_voltage, | ||
492 | .is_enabled = s5m8767_reg_is_enabled, | ||
493 | .enable = s5m8767_reg_enable, | ||
494 | .disable = s5m8767_reg_disable, | ||
495 | .get_voltage_sel = s5m8767_get_voltage_sel, | ||
496 | .set_voltage = s5m8767_set_voltage, | ||
497 | .set_voltage_time_sel = s5m8767_set_voltage_time_sel, | ||
498 | }; | ||
499 | |||
500 | static struct regulator_ops s5m8767_buck_ops = { | ||
501 | .list_voltage = s5m8767_list_voltage, | ||
502 | .is_enabled = s5m8767_reg_is_enabled, | ||
503 | .enable = s5m8767_reg_enable, | ||
504 | .disable = s5m8767_reg_disable, | ||
505 | .get_voltage_sel = s5m8767_get_voltage_sel, | ||
506 | .set_voltage = s5m8767_set_voltage_buck, | ||
507 | .set_voltage_time_sel = s5m8767_set_voltage_time_sel, | ||
508 | }; | ||
509 | |||
510 | #define regulator_desc_ldo(num) { \ | ||
511 | .name = "LDO"#num, \ | ||
512 | .id = S5M8767_LDO##num, \ | ||
513 | .ops = &s5m8767_ldo_ops, \ | ||
514 | .type = REGULATOR_VOLTAGE, \ | ||
515 | .owner = THIS_MODULE, \ | ||
516 | } | ||
517 | #define regulator_desc_buck(num) { \ | ||
518 | .name = "BUCK"#num, \ | ||
519 | .id = S5M8767_BUCK##num, \ | ||
520 | .ops = &s5m8767_buck_ops, \ | ||
521 | .type = REGULATOR_VOLTAGE, \ | ||
522 | .owner = THIS_MODULE, \ | ||
523 | } | ||
524 | |||
525 | static struct regulator_desc regulators[] = { | ||
526 | regulator_desc_ldo(1), | ||
527 | regulator_desc_ldo(2), | ||
528 | regulator_desc_ldo(3), | ||
529 | regulator_desc_ldo(4), | ||
530 | regulator_desc_ldo(5), | ||
531 | regulator_desc_ldo(6), | ||
532 | regulator_desc_ldo(7), | ||
533 | regulator_desc_ldo(8), | ||
534 | regulator_desc_ldo(9), | ||
535 | regulator_desc_ldo(10), | ||
536 | regulator_desc_ldo(11), | ||
537 | regulator_desc_ldo(12), | ||
538 | regulator_desc_ldo(13), | ||
539 | regulator_desc_ldo(14), | ||
540 | regulator_desc_ldo(15), | ||
541 | regulator_desc_ldo(16), | ||
542 | regulator_desc_ldo(17), | ||
543 | regulator_desc_ldo(18), | ||
544 | regulator_desc_ldo(19), | ||
545 | regulator_desc_ldo(20), | ||
546 | regulator_desc_ldo(21), | ||
547 | regulator_desc_ldo(22), | ||
548 | regulator_desc_ldo(23), | ||
549 | regulator_desc_ldo(24), | ||
550 | regulator_desc_ldo(25), | ||
551 | regulator_desc_ldo(26), | ||
552 | regulator_desc_ldo(27), | ||
553 | regulator_desc_ldo(28), | ||
554 | regulator_desc_buck(1), | ||
555 | regulator_desc_buck(2), | ||
556 | regulator_desc_buck(3), | ||
557 | regulator_desc_buck(4), | ||
558 | regulator_desc_buck(5), | ||
559 | regulator_desc_buck(6), | ||
560 | regulator_desc_buck(7), | ||
561 | regulator_desc_buck(8), | ||
562 | regulator_desc_buck(9), | ||
563 | }; | ||
564 | |||
565 | static __devinit int s5m8767_pmic_probe(struct platform_device *pdev) | ||
566 | { | ||
567 | struct s5m87xx_dev *iodev = dev_get_drvdata(pdev->dev.parent); | ||
568 | struct s5m_platform_data *pdata = dev_get_platdata(iodev->dev); | ||
569 | struct regulator_dev **rdev; | ||
570 | struct s5m8767_info *s5m8767; | ||
571 | struct i2c_client *i2c; | ||
572 | int i, ret, size, reg; | ||
573 | |||
574 | if (!pdata) { | ||
575 | dev_err(pdev->dev.parent, "Platform data not supplied\n"); | ||
576 | return -ENODEV; | ||
577 | } | ||
578 | |||
579 | s5m8767 = devm_kzalloc(&pdev->dev, sizeof(struct s5m8767_info), | ||
580 | GFP_KERNEL); | ||
581 | if (!s5m8767) | ||
582 | return -ENOMEM; | ||
583 | |||
584 | size = sizeof(struct regulator_dev *) * (S5M8767_REG_MAX - 2); | ||
585 | s5m8767->rdev = devm_kzalloc(&pdev->dev, size, GFP_KERNEL); | ||
586 | if (!s5m8767->rdev) | ||
587 | return -ENOMEM; | ||
588 | |||
589 | rdev = s5m8767->rdev; | ||
590 | s5m8767->dev = &pdev->dev; | ||
591 | s5m8767->iodev = iodev; | ||
592 | s5m8767->num_regulators = S5M8767_REG_MAX - 2; | ||
593 | platform_set_drvdata(pdev, s5m8767); | ||
594 | i2c = s5m8767->iodev->i2c; | ||
595 | |||
596 | s5m8767->buck_gpioindex = pdata->buck_default_idx; | ||
597 | s5m8767->buck2_gpiodvs = pdata->buck2_gpiodvs; | ||
598 | s5m8767->buck3_gpiodvs = pdata->buck3_gpiodvs; | ||
599 | s5m8767->buck4_gpiodvs = pdata->buck4_gpiodvs; | ||
600 | s5m8767->buck_gpios[0] = pdata->buck_gpios[0]; | ||
601 | s5m8767->buck_gpios[1] = pdata->buck_gpios[1]; | ||
602 | s5m8767->buck_gpios[2] = pdata->buck_gpios[2]; | ||
603 | s5m8767->ramp_delay = pdata->buck_ramp_delay; | ||
604 | s5m8767->buck2_ramp = pdata->buck2_ramp_enable; | ||
605 | s5m8767->buck3_ramp = pdata->buck3_ramp_enable; | ||
606 | s5m8767->buck4_ramp = pdata->buck4_ramp_enable; | ||
607 | |||
608 | for (i = 0; i < 8; i++) { | ||
609 | if (s5m8767->buck2_gpiodvs) { | ||
610 | s5m8767->buck2_vol[i] = | ||
611 | s5m8767_convert_voltage( | ||
612 | &buck_voltage_val2, | ||
613 | pdata->buck2_voltage[i], | ||
614 | pdata->buck2_voltage[i] + | ||
615 | buck_voltage_val2.step); | ||
616 | } | ||
617 | |||
618 | if (s5m8767->buck3_gpiodvs) { | ||
619 | s5m8767->buck3_vol[i] = | ||
620 | s5m8767_convert_voltage( | ||
621 | &buck_voltage_val2, | ||
622 | pdata->buck3_voltage[i], | ||
623 | pdata->buck3_voltage[i] + | ||
624 | buck_voltage_val2.step); | ||
625 | } | ||
626 | |||
627 | if (s5m8767->buck4_gpiodvs) { | ||
628 | s5m8767->buck4_vol[i] = | ||
629 | s5m8767_convert_voltage( | ||
630 | &buck_voltage_val2, | ||
631 | pdata->buck4_voltage[i], | ||
632 | pdata->buck4_voltage[i] + | ||
633 | buck_voltage_val2.step); | ||
634 | } | ||
635 | } | ||
636 | |||
637 | if (pdata->buck2_gpiodvs || pdata->buck3_gpiodvs || | ||
638 | pdata->buck4_gpiodvs) { | ||
639 | if (gpio_is_valid(pdata->buck_gpios[0]) && | ||
640 | gpio_is_valid(pdata->buck_gpios[1]) && | ||
641 | gpio_is_valid(pdata->buck_gpios[2])) { | ||
642 | ret = gpio_request(pdata->buck_gpios[0], | ||
643 | "S5M8767 SET1"); | ||
644 | if (ret == -EBUSY) | ||
645 | dev_warn(&pdev->dev, "Duplicated gpio request for SET1\n"); | ||
646 | |||
647 | ret = gpio_request(pdata->buck_gpios[1], | ||
648 | "S5M8767 SET2"); | ||
649 | if (ret == -EBUSY) | ||
650 | dev_warn(&pdev->dev, "Duplicated gpio request for SET2\n"); | ||
651 | |||
652 | ret = gpio_request(pdata->buck_gpios[2], | ||
653 | "S5M8767 SET3"); | ||
654 | if (ret == -EBUSY) | ||
655 | dev_warn(&pdev->dev, "Duplicated gpio request for SET3\n"); | ||
656 | /* SET1 GPIO */ | ||
657 | gpio_direction_output(pdata->buck_gpios[0], | ||
658 | (s5m8767->buck_gpioindex >> 2) & 0x1); | ||
659 | /* SET2 GPIO */ | ||
660 | gpio_direction_output(pdata->buck_gpios[1], | ||
661 | (s5m8767->buck_gpioindex >> 1) & 0x1); | ||
662 | /* SET3 GPIO */ | ||
663 | gpio_direction_output(pdata->buck_gpios[2], | ||
664 | (s5m8767->buck_gpioindex >> 0) & 0x1); | ||
665 | ret = 0; | ||
666 | } else { | ||
667 | dev_err(&pdev->dev, "GPIO NOT VALID\n"); | ||
668 | ret = -EINVAL; | ||
669 | return ret; | ||
670 | } | ||
671 | } | ||
672 | |||
673 | if (pdata->buck2_gpiodvs) { | ||
674 | if (pdata->buck3_gpiodvs || pdata->buck4_gpiodvs) { | ||
675 | dev_err(&pdev->dev, "S5M8767 GPIO DVS NOT VALID\n"); | ||
676 | ret = -EINVAL; | ||
677 | return ret; | ||
678 | } | ||
679 | } | ||
680 | |||
681 | if (pdata->buck3_gpiodvs) { | ||
682 | if (pdata->buck2_gpiodvs || pdata->buck4_gpiodvs) { | ||
683 | dev_err(&pdev->dev, "S5M8767 GPIO DVS NOT VALID\n"); | ||
684 | ret = -EINVAL; | ||
685 | return ret; | ||
686 | } | ||
687 | } | ||
688 | |||
689 | if (pdata->buck4_gpiodvs) { | ||
690 | if (pdata->buck2_gpiodvs || pdata->buck3_gpiodvs) { | ||
691 | dev_err(&pdev->dev, "S5M8767 GPIO DVS NOT VALID\n"); | ||
692 | ret = -EINVAL; | ||
693 | return ret; | ||
694 | } | ||
695 | } | ||
696 | |||
697 | s5m_reg_update(s5m8767->iodev, S5M8767_REG_BUCK2CTRL, | ||
698 | (pdata->buck2_gpiodvs) ? (1 << 1) : (0 << 1), 1 << 1); | ||
699 | s5m_reg_update(s5m8767->iodev, S5M8767_REG_BUCK3CTRL, | ||
700 | (pdata->buck3_gpiodvs) ? (1 << 1) : (0 << 1), 1 << 1); | ||
701 | s5m_reg_update(s5m8767->iodev, S5M8767_REG_BUCK4CTRL, | ||
702 | (pdata->buck4_gpiodvs) ? (1 << 1) : (0 << 1), 1 << 1); | ||
703 | |||
704 | /* Initialize GPIO DVS registers */ | ||
705 | for (i = 0; i < 8; i++) { | ||
706 | if (s5m8767->buck2_gpiodvs) { | ||
707 | s5m_reg_write(s5m8767->iodev, S5M8767_REG_BUCK2DVS1 + i, | ||
708 | s5m8767->buck2_vol[i]); | ||
709 | } | ||
710 | |||
711 | if (s5m8767->buck3_gpiodvs) { | ||
712 | s5m_reg_write(s5m8767->iodev, S5M8767_REG_BUCK3DVS1 + i, | ||
713 | s5m8767->buck3_vol[i]); | ||
714 | } | ||
715 | |||
716 | if (s5m8767->buck4_gpiodvs) { | ||
717 | s5m_reg_write(s5m8767->iodev, S5M8767_REG_BUCK4DVS1 + i, | ||
718 | s5m8767->buck4_vol[i]); | ||
719 | } | ||
720 | } | ||
721 | s5m_reg_update(s5m8767->iodev, S5M8767_REG_BUCK2CTRL, 0x78, 0xff); | ||
722 | s5m_reg_update(s5m8767->iodev, S5M8767_REG_BUCK3CTRL, 0x58, 0xff); | ||
723 | s5m_reg_update(s5m8767->iodev, S5M8767_REG_BUCK4CTRL, 0x78, 0xff); | ||
724 | |||
725 | if (s5m8767->buck2_ramp) | ||
726 | s5m_reg_update(s5m8767->iodev, S5M8767_REG_DVSRAMP, 0x08, 0x08); | ||
727 | |||
728 | if (s5m8767->buck3_ramp) | ||
729 | s5m_reg_update(s5m8767->iodev, S5M8767_REG_DVSRAMP, 0x04, 0x04); | ||
730 | |||
731 | if (s5m8767->buck4_ramp) | ||
732 | s5m_reg_update(s5m8767->iodev, S5M8767_REG_DVSRAMP, 0x02, 0x02); | ||
733 | |||
734 | if (s5m8767->buck2_ramp || s5m8767->buck3_ramp | ||
735 | || s5m8767->buck4_ramp) { | ||
736 | switch (s5m8767->ramp_delay) { | ||
737 | case 15: | ||
738 | s5m_reg_update(s5m8767->iodev, S5M8767_REG_DVSRAMP, | ||
739 | 0xc0, 0xf0); | ||
740 | break; | ||
741 | case 25: | ||
742 | s5m_reg_update(s5m8767->iodev, S5M8767_REG_DVSRAMP, | ||
743 | 0xd0, 0xf0); | ||
744 | break; | ||
745 | case 50: | ||
746 | s5m_reg_update(s5m8767->iodev, S5M8767_REG_DVSRAMP, | ||
747 | 0xe0, 0xf0); | ||
748 | break; | ||
749 | case 100: | ||
750 | s5m_reg_update(s5m8767->iodev, S5M8767_REG_DVSRAMP, | ||
751 | 0xf0, 0xf0); | ||
752 | break; | ||
753 | default: | ||
754 | s5m_reg_update(s5m8767->iodev, S5M8767_REG_DVSRAMP, | ||
755 | 0x90, 0xf0); | ||
756 | } | ||
757 | } | ||
758 | |||
759 | for (i = 0; i < pdata->num_regulators; i++) { | ||
760 | const struct s5m_voltage_desc *desc; | ||
761 | int id = pdata->regulators[i].id; | ||
762 | |||
763 | desc = reg_voltage_map[id]; | ||
764 | if (desc) | ||
765 | regulators[id].n_voltages = | ||
766 | (desc->max - desc->min) / desc->step + 1; | ||
767 | |||
768 | rdev[i] = regulator_register(®ulators[id], s5m8767->dev, | ||
769 | pdata->regulators[i].initdata, s5m8767, NULL); | ||
770 | if (IS_ERR(rdev[i])) { | ||
771 | ret = PTR_ERR(rdev[i]); | ||
772 | dev_err(s5m8767->dev, "regulator init failed for %d\n", | ||
773 | id); | ||
774 | rdev[i] = NULL; | ||
775 | goto err; | ||
776 | } | ||
777 | } | ||
778 | |||
779 | return 0; | ||
780 | err: | ||
781 | for (i = 0; i < s5m8767->num_regulators; i++) | ||
782 | if (rdev[i]) | ||
783 | regulator_unregister(rdev[i]); | ||
784 | |||
785 | return ret; | ||
786 | } | ||
787 | |||
788 | static int __devexit s5m8767_pmic_remove(struct platform_device *pdev) | ||
789 | { | ||
790 | struct s5m8767_info *s5m8767 = platform_get_drvdata(pdev); | ||
791 | struct regulator_dev **rdev = s5m8767->rdev; | ||
792 | int i; | ||
793 | |||
794 | for (i = 0; i < s5m8767->num_regulators; i++) | ||
795 | if (rdev[i]) | ||
796 | regulator_unregister(rdev[i]); | ||
797 | |||
798 | return 0; | ||
799 | } | ||
800 | |||
801 | static const struct platform_device_id s5m8767_pmic_id[] = { | ||
802 | { "s5m8767-pmic", 0}, | ||
803 | { }, | ||
804 | }; | ||
805 | MODULE_DEVICE_TABLE(platform, s5m8767_pmic_id); | ||
806 | |||
807 | static struct platform_driver s5m8767_pmic_driver = { | ||
808 | .driver = { | ||
809 | .name = "s5m8767-pmic", | ||
810 | .owner = THIS_MODULE, | ||
811 | }, | ||
812 | .probe = s5m8767_pmic_probe, | ||
813 | .remove = __devexit_p(s5m8767_pmic_remove), | ||
814 | .id_table = s5m8767_pmic_id, | ||
815 | }; | ||
816 | |||
817 | static int __init s5m8767_pmic_init(void) | ||
818 | { | ||
819 | return platform_driver_register(&s5m8767_pmic_driver); | ||
820 | } | ||
821 | subsys_initcall(s5m8767_pmic_init); | ||
822 | |||
823 | static void __exit s5m8767_pmic_exit(void) | ||
824 | { | ||
825 | platform_driver_unregister(&s5m8767_pmic_driver); | ||
826 | } | ||
827 | module_exit(s5m8767_pmic_exit); | ||
828 | |||
829 | /* Module information */ | ||
830 | MODULE_AUTHOR("Sangbeom Kim <sbkim73@samsung.com>"); | ||
831 | MODULE_DESCRIPTION("SAMSUNG S5M8767 Regulator Driver"); | ||
832 | MODULE_LICENSE("GPL"); | ||
diff --git a/drivers/regulator/tps62360-regulator.c b/drivers/regulator/tps62360-regulator.c new file mode 100644 index 000000000000..f778ef067696 --- /dev/null +++ b/drivers/regulator/tps62360-regulator.c | |||
@@ -0,0 +1,472 @@ | |||
1 | /* | ||
2 | * tps62360.c -- TI tps62360 | ||
3 | * | ||
4 | * Driver for processor core supply tps62360 and tps62361B | ||
5 | * | ||
6 | * Copyright (c) 2012, NVIDIA Corporation. | ||
7 | * | ||
8 | * Author: Laxman Dewangan <ldewangan@nvidia.com> | ||
9 | * | ||
10 | * This program is free software; you can redistribute it and/or | ||
11 | * modify it under the terms of the GNU General Public License as | ||
12 | * published by the Free Software Foundation version 2. | ||
13 | * | ||
14 | * This program is distributed "as is" WITHOUT ANY WARRANTY of any kind, | ||
15 | * whether express or implied; without even the implied warranty of | ||
16 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
17 | * 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., 59 Temple Place, Suite 330, Boston, MA | ||
22 | * 02111-1307, USA | ||
23 | */ | ||
24 | |||
25 | #include <linux/kernel.h> | ||
26 | #include <linux/module.h> | ||
27 | #include <linux/init.h> | ||
28 | #include <linux/err.h> | ||
29 | #include <linux/platform_device.h> | ||
30 | #include <linux/regulator/driver.h> | ||
31 | #include <linux/regulator/machine.h> | ||
32 | #include <linux/regulator/tps62360.h> | ||
33 | #include <linux/gpio.h> | ||
34 | #include <linux/i2c.h> | ||
35 | #include <linux/delay.h> | ||
36 | #include <linux/slab.h> | ||
37 | #include <linux/regmap.h> | ||
38 | |||
39 | /* Register definitions */ | ||
40 | #define REG_VSET0 0 | ||
41 | #define REG_VSET1 1 | ||
42 | #define REG_VSET2 2 | ||
43 | #define REG_VSET3 3 | ||
44 | #define REG_CONTROL 4 | ||
45 | #define REG_TEMP 5 | ||
46 | #define REG_RAMPCTRL 6 | ||
47 | #define REG_CHIPID 8 | ||
48 | |||
49 | enum chips {TPS62360, TPS62361}; | ||
50 | |||
51 | #define TPS62360_BASE_VOLTAGE 770 | ||
52 | #define TPS62360_N_VOLTAGES 64 | ||
53 | |||
54 | #define TPS62361_BASE_VOLTAGE 500 | ||
55 | #define TPS62361_N_VOLTAGES 128 | ||
56 | |||
57 | /* tps 62360 chip information */ | ||
58 | struct tps62360_chip { | ||
59 | const char *name; | ||
60 | struct device *dev; | ||
61 | struct regulator_desc desc; | ||
62 | struct i2c_client *client; | ||
63 | struct regulator_dev *rdev; | ||
64 | struct regmap *regmap; | ||
65 | int chip_id; | ||
66 | int vsel0_gpio; | ||
67 | int vsel1_gpio; | ||
68 | int voltage_base; | ||
69 | u8 voltage_reg_mask; | ||
70 | bool en_internal_pulldn; | ||
71 | bool en_force_pwm; | ||
72 | bool en_discharge; | ||
73 | bool valid_gpios; | ||
74 | int lru_index[4]; | ||
75 | int curr_vset_vsel[4]; | ||
76 | int curr_vset_id; | ||
77 | }; | ||
78 | |||
79 | /* | ||
80 | * find_voltage_set_register: Find new voltage configuration register | ||
81 | * (VSET) id. | ||
82 | * The finding of the new VSET register will be based on the LRU mechanism. | ||
83 | * Each VSET register will have different voltage configured . This | ||
84 | * Function will look if any of the VSET register have requested voltage set | ||
85 | * or not. | ||
86 | * - If it is already there then it will make that register as most | ||
87 | * recently used and return as found so that caller need not to set | ||
88 | * the VSET register but need to set the proper gpios to select this | ||
89 | * VSET register. | ||
90 | * - If requested voltage is not found then it will use the least | ||
91 | * recently mechanism to get new VSET register for new configuration | ||
92 | * and will return not_found so that caller need to set new VSET | ||
93 | * register and then gpios (both). | ||
94 | */ | ||
95 | static bool find_voltage_set_register(struct tps62360_chip *tps, | ||
96 | int req_vsel, int *vset_reg_id) | ||
97 | { | ||
98 | int i; | ||
99 | bool found = false; | ||
100 | int new_vset_reg = tps->lru_index[3]; | ||
101 | int found_index = 3; | ||
102 | for (i = 0; i < 4; ++i) { | ||
103 | if (tps->curr_vset_vsel[tps->lru_index[i]] == req_vsel) { | ||
104 | new_vset_reg = tps->lru_index[i]; | ||
105 | found_index = i; | ||
106 | found = true; | ||
107 | goto update_lru_index; | ||
108 | } | ||
109 | } | ||
110 | |||
111 | update_lru_index: | ||
112 | for (i = found_index; i > 0; i--) | ||
113 | tps->lru_index[i] = tps->lru_index[i - 1]; | ||
114 | |||
115 | tps->lru_index[0] = new_vset_reg; | ||
116 | *vset_reg_id = new_vset_reg; | ||
117 | return found; | ||
118 | } | ||
119 | |||
120 | static int tps62360_dcdc_get_voltage(struct regulator_dev *dev) | ||
121 | { | ||
122 | struct tps62360_chip *tps = rdev_get_drvdata(dev); | ||
123 | int vsel; | ||
124 | unsigned int data; | ||
125 | int ret; | ||
126 | |||
127 | ret = regmap_read(tps->regmap, REG_VSET0 + tps->curr_vset_id, &data); | ||
128 | if (ret < 0) { | ||
129 | dev_err(tps->dev, "%s: Error in reading register %d\n", | ||
130 | __func__, REG_VSET0 + tps->curr_vset_id); | ||
131 | return ret; | ||
132 | } | ||
133 | vsel = (int)data & tps->voltage_reg_mask; | ||
134 | return (tps->voltage_base + vsel * 10) * 1000; | ||
135 | } | ||
136 | |||
137 | static int tps62360_dcdc_set_voltage(struct regulator_dev *dev, | ||
138 | int min_uV, int max_uV, unsigned *selector) | ||
139 | { | ||
140 | struct tps62360_chip *tps = rdev_get_drvdata(dev); | ||
141 | int vsel; | ||
142 | int ret; | ||
143 | bool found = false; | ||
144 | int new_vset_id = tps->curr_vset_id; | ||
145 | |||
146 | if (max_uV < min_uV) | ||
147 | return -EINVAL; | ||
148 | |||
149 | if (min_uV > | ||
150 | ((tps->voltage_base + (tps->desc.n_voltages - 1) * 10) * 1000)) | ||
151 | return -EINVAL; | ||
152 | |||
153 | if (max_uV < tps->voltage_base * 1000) | ||
154 | return -EINVAL; | ||
155 | |||
156 | vsel = DIV_ROUND_UP(min_uV - (tps->voltage_base * 1000), 10000); | ||
157 | if (selector) | ||
158 | *selector = (vsel & tps->voltage_reg_mask); | ||
159 | |||
160 | /* | ||
161 | * If gpios are available to select the VSET register then least | ||
162 | * recently used register for new configuration. | ||
163 | */ | ||
164 | if (tps->valid_gpios) | ||
165 | found = find_voltage_set_register(tps, vsel, &new_vset_id); | ||
166 | |||
167 | if (!found) { | ||
168 | ret = regmap_update_bits(tps->regmap, REG_VSET0 + new_vset_id, | ||
169 | tps->voltage_reg_mask, vsel); | ||
170 | if (ret < 0) { | ||
171 | dev_err(tps->dev, "%s: Error in updating register %d\n", | ||
172 | __func__, REG_VSET0 + new_vset_id); | ||
173 | return ret; | ||
174 | } | ||
175 | tps->curr_vset_id = new_vset_id; | ||
176 | tps->curr_vset_vsel[new_vset_id] = vsel; | ||
177 | } | ||
178 | |||
179 | /* Select proper VSET register vio gpios */ | ||
180 | if (tps->valid_gpios) { | ||
181 | gpio_set_value_cansleep(tps->vsel0_gpio, | ||
182 | new_vset_id & 0x1); | ||
183 | gpio_set_value_cansleep(tps->vsel1_gpio, | ||
184 | (new_vset_id >> 1) & 0x1); | ||
185 | } | ||
186 | return 0; | ||
187 | } | ||
188 | |||
189 | static int tps62360_dcdc_list_voltage(struct regulator_dev *dev, | ||
190 | unsigned selector) | ||
191 | { | ||
192 | struct tps62360_chip *tps = rdev_get_drvdata(dev); | ||
193 | |||
194 | if ((selector < 0) || (selector >= tps->desc.n_voltages)) | ||
195 | return -EINVAL; | ||
196 | return (tps->voltage_base + selector * 10) * 1000; | ||
197 | } | ||
198 | |||
199 | static struct regulator_ops tps62360_dcdc_ops = { | ||
200 | .get_voltage = tps62360_dcdc_get_voltage, | ||
201 | .set_voltage = tps62360_dcdc_set_voltage, | ||
202 | .list_voltage = tps62360_dcdc_list_voltage, | ||
203 | }; | ||
204 | |||
205 | static int tps62360_init_force_pwm(struct tps62360_chip *tps, | ||
206 | struct tps62360_regulator_platform_data *pdata, | ||
207 | int vset_id) | ||
208 | { | ||
209 | unsigned int data; | ||
210 | int ret; | ||
211 | ret = regmap_read(tps->regmap, REG_VSET0 + vset_id, &data); | ||
212 | if (ret < 0) { | ||
213 | dev_err(tps->dev, "%s() fails in writing reg %d\n", | ||
214 | __func__, REG_VSET0 + vset_id); | ||
215 | return ret; | ||
216 | } | ||
217 | tps->curr_vset_vsel[vset_id] = data & tps->voltage_reg_mask; | ||
218 | if (pdata->en_force_pwm) | ||
219 | data |= BIT(7); | ||
220 | else | ||
221 | data &= ~BIT(7); | ||
222 | ret = regmap_write(tps->regmap, REG_VSET0 + vset_id, data); | ||
223 | if (ret < 0) | ||
224 | dev_err(tps->dev, "%s() fails in writing reg %d\n", | ||
225 | __func__, REG_VSET0 + vset_id); | ||
226 | return ret; | ||
227 | } | ||
228 | |||
229 | static int tps62360_init_dcdc(struct tps62360_chip *tps, | ||
230 | struct tps62360_regulator_platform_data *pdata) | ||
231 | { | ||
232 | int ret; | ||
233 | int i; | ||
234 | |||
235 | /* Initailize internal pull up/down control */ | ||
236 | if (tps->en_internal_pulldn) | ||
237 | ret = regmap_write(tps->regmap, REG_CONTROL, 0xE0); | ||
238 | else | ||
239 | ret = regmap_write(tps->regmap, REG_CONTROL, 0x0); | ||
240 | if (ret < 0) { | ||
241 | dev_err(tps->dev, "%s() fails in writing reg %d\n", | ||
242 | __func__, REG_CONTROL); | ||
243 | return ret; | ||
244 | } | ||
245 | |||
246 | /* Initailize force PWM mode */ | ||
247 | if (tps->valid_gpios) { | ||
248 | for (i = 0; i < 4; ++i) { | ||
249 | ret = tps62360_init_force_pwm(tps, pdata, i); | ||
250 | if (ret < 0) | ||
251 | return ret; | ||
252 | } | ||
253 | } else { | ||
254 | ret = tps62360_init_force_pwm(tps, pdata, tps->curr_vset_id); | ||
255 | if (ret < 0) | ||
256 | return ret; | ||
257 | } | ||
258 | |||
259 | /* Reset output discharge path to reduce power consumption */ | ||
260 | ret = regmap_update_bits(tps->regmap, REG_RAMPCTRL, BIT(2), 0); | ||
261 | if (ret < 0) | ||
262 | dev_err(tps->dev, "%s() fails in updating reg %d\n", | ||
263 | __func__, REG_RAMPCTRL); | ||
264 | return ret; | ||
265 | } | ||
266 | |||
267 | static const struct regmap_config tps62360_regmap_config = { | ||
268 | .reg_bits = 8, | ||
269 | .val_bits = 8, | ||
270 | }; | ||
271 | |||
272 | static int __devinit tps62360_probe(struct i2c_client *client, | ||
273 | const struct i2c_device_id *id) | ||
274 | { | ||
275 | struct tps62360_regulator_platform_data *pdata; | ||
276 | struct regulator_dev *rdev; | ||
277 | struct tps62360_chip *tps; | ||
278 | int ret; | ||
279 | int i; | ||
280 | |||
281 | pdata = client->dev.platform_data; | ||
282 | if (!pdata) { | ||
283 | dev_err(&client->dev, "%s() Err: Platform data not found\n", | ||
284 | __func__); | ||
285 | return -EIO; | ||
286 | } | ||
287 | |||
288 | tps = devm_kzalloc(&client->dev, sizeof(*tps), GFP_KERNEL); | ||
289 | if (!tps) { | ||
290 | dev_err(&client->dev, "%s() Err: Memory allocation fails\n", | ||
291 | __func__); | ||
292 | return -ENOMEM; | ||
293 | } | ||
294 | |||
295 | tps->en_force_pwm = pdata->en_force_pwm; | ||
296 | tps->en_discharge = pdata->en_discharge; | ||
297 | tps->en_internal_pulldn = pdata->en_internal_pulldn; | ||
298 | tps->vsel0_gpio = pdata->vsel0_gpio; | ||
299 | tps->vsel1_gpio = pdata->vsel1_gpio; | ||
300 | tps->client = client; | ||
301 | tps->dev = &client->dev; | ||
302 | tps->name = id->name; | ||
303 | tps->voltage_base = (id->driver_data == TPS62360) ? | ||
304 | TPS62360_BASE_VOLTAGE : TPS62361_BASE_VOLTAGE; | ||
305 | tps->voltage_reg_mask = (id->driver_data == TPS62360) ? 0x3F : 0x7F; | ||
306 | |||
307 | tps->desc.name = id->name; | ||
308 | tps->desc.id = 0; | ||
309 | tps->desc.n_voltages = (id->driver_data == TPS62360) ? | ||
310 | TPS62360_N_VOLTAGES : TPS62361_N_VOLTAGES; | ||
311 | tps->desc.ops = &tps62360_dcdc_ops; | ||
312 | tps->desc.type = REGULATOR_VOLTAGE; | ||
313 | tps->desc.owner = THIS_MODULE; | ||
314 | tps->regmap = regmap_init_i2c(client, &tps62360_regmap_config); | ||
315 | if (IS_ERR(tps->regmap)) { | ||
316 | ret = PTR_ERR(tps->regmap); | ||
317 | dev_err(&client->dev, "%s() Err: Failed to allocate register" | ||
318 | "map: %d\n", __func__, ret); | ||
319 | return ret; | ||
320 | } | ||
321 | i2c_set_clientdata(client, tps); | ||
322 | |||
323 | tps->curr_vset_id = (pdata->vsel1_def_state & 1) * 2 + | ||
324 | (pdata->vsel0_def_state & 1); | ||
325 | tps->lru_index[0] = tps->curr_vset_id; | ||
326 | tps->valid_gpios = false; | ||
327 | |||
328 | if (gpio_is_valid(tps->vsel0_gpio) && gpio_is_valid(tps->vsel1_gpio)) { | ||
329 | ret = gpio_request(tps->vsel0_gpio, "tps62360-vsel0"); | ||
330 | if (ret) { | ||
331 | dev_err(&client->dev, | ||
332 | "Err: Could not obtain vsel0 GPIO %d: %d\n", | ||
333 | tps->vsel0_gpio, ret); | ||
334 | goto err_gpio0; | ||
335 | } | ||
336 | ret = gpio_direction_output(tps->vsel0_gpio, | ||
337 | pdata->vsel0_def_state); | ||
338 | if (ret) { | ||
339 | dev_err(&client->dev, "Err: Could not set direction of" | ||
340 | "vsel0 GPIO %d: %d\n", tps->vsel0_gpio, ret); | ||
341 | gpio_free(tps->vsel0_gpio); | ||
342 | goto err_gpio0; | ||
343 | } | ||
344 | |||
345 | ret = gpio_request(tps->vsel1_gpio, "tps62360-vsel1"); | ||
346 | if (ret) { | ||
347 | dev_err(&client->dev, | ||
348 | "Err: Could not obtain vsel1 GPIO %d: %d\n", | ||
349 | tps->vsel1_gpio, ret); | ||
350 | goto err_gpio1; | ||
351 | } | ||
352 | ret = gpio_direction_output(tps->vsel1_gpio, | ||
353 | pdata->vsel1_def_state); | ||
354 | if (ret) { | ||
355 | dev_err(&client->dev, "Err: Could not set direction of" | ||
356 | "vsel1 GPIO %d: %d\n", tps->vsel1_gpio, ret); | ||
357 | gpio_free(tps->vsel1_gpio); | ||
358 | goto err_gpio1; | ||
359 | } | ||
360 | tps->valid_gpios = true; | ||
361 | |||
362 | /* | ||
363 | * Initialize the lru index with vset_reg id | ||
364 | * The index 0 will be most recently used and | ||
365 | * set with the tps->curr_vset_id */ | ||
366 | for (i = 0; i < 4; ++i) | ||
367 | tps->lru_index[i] = i; | ||
368 | tps->lru_index[0] = tps->curr_vset_id; | ||
369 | tps->lru_index[tps->curr_vset_id] = 0; | ||
370 | } | ||
371 | |||
372 | ret = tps62360_init_dcdc(tps, pdata); | ||
373 | if (ret < 0) { | ||
374 | dev_err(tps->dev, "%s() Err: Init fails with = %d\n", | ||
375 | __func__, ret); | ||
376 | goto err_init; | ||
377 | } | ||
378 | |||
379 | /* Register the regulators */ | ||
380 | rdev = regulator_register(&tps->desc, &client->dev, | ||
381 | &pdata->reg_init_data, tps, NULL); | ||
382 | if (IS_ERR(rdev)) { | ||
383 | dev_err(tps->dev, "%s() Err: Failed to register %s\n", | ||
384 | __func__, id->name); | ||
385 | ret = PTR_ERR(rdev); | ||
386 | goto err_init; | ||
387 | } | ||
388 | |||
389 | tps->rdev = rdev; | ||
390 | return 0; | ||
391 | |||
392 | err_init: | ||
393 | if (gpio_is_valid(tps->vsel1_gpio)) | ||
394 | gpio_free(tps->vsel1_gpio); | ||
395 | err_gpio1: | ||
396 | if (gpio_is_valid(tps->vsel0_gpio)) | ||
397 | gpio_free(tps->vsel0_gpio); | ||
398 | err_gpio0: | ||
399 | regmap_exit(tps->regmap); | ||
400 | return ret; | ||
401 | } | ||
402 | |||
403 | /** | ||
404 | * tps62360_remove - tps62360 driver i2c remove handler | ||
405 | * @client: i2c driver client device structure | ||
406 | * | ||
407 | * Unregister TPS driver as an i2c client device driver | ||
408 | */ | ||
409 | static int __devexit tps62360_remove(struct i2c_client *client) | ||
410 | { | ||
411 | struct tps62360_chip *tps = i2c_get_clientdata(client); | ||
412 | |||
413 | if (gpio_is_valid(tps->vsel1_gpio)) | ||
414 | gpio_free(tps->vsel1_gpio); | ||
415 | |||
416 | if (gpio_is_valid(tps->vsel0_gpio)) | ||
417 | gpio_free(tps->vsel0_gpio); | ||
418 | |||
419 | regulator_unregister(tps->rdev); | ||
420 | regmap_exit(tps->regmap); | ||
421 | return 0; | ||
422 | } | ||
423 | |||
424 | static void tps62360_shutdown(struct i2c_client *client) | ||
425 | { | ||
426 | struct tps62360_chip *tps = i2c_get_clientdata(client); | ||
427 | int st; | ||
428 | |||
429 | if (!tps->en_discharge) | ||
430 | return; | ||
431 | |||
432 | /* Configure the output discharge path */ | ||
433 | st = regmap_update_bits(tps->regmap, REG_RAMPCTRL, BIT(2), BIT(2)); | ||
434 | if (st < 0) | ||
435 | dev_err(tps->dev, "%s() fails in updating reg %d\n", | ||
436 | __func__, REG_RAMPCTRL); | ||
437 | } | ||
438 | |||
439 | static const struct i2c_device_id tps62360_id[] = { | ||
440 | {.name = "tps62360", .driver_data = TPS62360}, | ||
441 | {.name = "tps62361", .driver_data = TPS62361}, | ||
442 | {}, | ||
443 | }; | ||
444 | |||
445 | MODULE_DEVICE_TABLE(i2c, tps62360_id); | ||
446 | |||
447 | static struct i2c_driver tps62360_i2c_driver = { | ||
448 | .driver = { | ||
449 | .name = "tps62360", | ||
450 | .owner = THIS_MODULE, | ||
451 | }, | ||
452 | .probe = tps62360_probe, | ||
453 | .remove = __devexit_p(tps62360_remove), | ||
454 | .shutdown = tps62360_shutdown, | ||
455 | .id_table = tps62360_id, | ||
456 | }; | ||
457 | |||
458 | static int __init tps62360_init(void) | ||
459 | { | ||
460 | return i2c_add_driver(&tps62360_i2c_driver); | ||
461 | } | ||
462 | subsys_initcall(tps62360_init); | ||
463 | |||
464 | static void __exit tps62360_cleanup(void) | ||
465 | { | ||
466 | i2c_del_driver(&tps62360_i2c_driver); | ||
467 | } | ||
468 | module_exit(tps62360_cleanup); | ||
469 | |||
470 | MODULE_AUTHOR("Laxman Dewangan <ldewangan@nvidia.com>"); | ||
471 | MODULE_DESCRIPTION("TPS62360 voltage regulator driver"); | ||
472 | MODULE_LICENSE("GPL v2"); | ||
diff --git a/drivers/regulator/tps65217-regulator.c b/drivers/regulator/tps65217-regulator.c new file mode 100644 index 000000000000..28a10eaeda17 --- /dev/null +++ b/drivers/regulator/tps65217-regulator.c | |||
@@ -0,0 +1,493 @@ | |||
1 | /* | ||
2 | * tps65217-regulator.c | ||
3 | * | ||
4 | * Regulator driver for TPS65217 PMIC | ||
5 | * | ||
6 | * Copyright (C) 2011 Texas Instruments Incorporated - http://www.ti.com/ | ||
7 | * | ||
8 | * This program is free software; you can redistribute it and/or | ||
9 | * modify it under the terms of the GNU General Public License as | ||
10 | * published by the Free Software Foundation version 2. | ||
11 | * | ||
12 | * This program is distributed "as is" WITHOUT ANY WARRANTY of any | ||
13 | * kind, whether express or implied; without even the implied warranty | ||
14 | * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
15 | * GNU General Public License for more details. | ||
16 | */ | ||
17 | |||
18 | #include <linux/kernel.h> | ||
19 | #include <linux/module.h> | ||
20 | #include <linux/device.h> | ||
21 | #include <linux/init.h> | ||
22 | #include <linux/err.h> | ||
23 | #include <linux/platform_device.h> | ||
24 | |||
25 | #include <linux/regulator/driver.h> | ||
26 | #include <linux/regulator/machine.h> | ||
27 | #include <linux/mfd/tps65217.h> | ||
28 | |||
29 | #define TPS65217_REGULATOR(_name, _id, _ops, _n) \ | ||
30 | { \ | ||
31 | .name = _name, \ | ||
32 | .id = _id, \ | ||
33 | .ops = &_ops, \ | ||
34 | .n_voltages = _n, \ | ||
35 | .type = REGULATOR_VOLTAGE, \ | ||
36 | .owner = THIS_MODULE, \ | ||
37 | } \ | ||
38 | |||
39 | #define TPS65217_INFO(_nm, _min, _max, _f1, _f2, _t, _n, _em, _vr, _vm) \ | ||
40 | { \ | ||
41 | .name = _nm, \ | ||
42 | .min_uV = _min, \ | ||
43 | .max_uV = _max, \ | ||
44 | .vsel_to_uv = _f1, \ | ||
45 | .uv_to_vsel = _f2, \ | ||
46 | .table = _t, \ | ||
47 | .table_len = _n, \ | ||
48 | .enable_mask = _em, \ | ||
49 | .set_vout_reg = _vr, \ | ||
50 | .set_vout_mask = _vm, \ | ||
51 | } | ||
52 | |||
53 | static const int LDO1_VSEL_table[] = { | ||
54 | 1000000, 1100000, 1200000, 1250000, | ||
55 | 1300000, 1350000, 1400000, 1500000, | ||
56 | 1600000, 1800000, 2500000, 2750000, | ||
57 | 2800000, 3000000, 3100000, 3300000, | ||
58 | }; | ||
59 | |||
60 | static int tps65217_vsel_to_uv1(unsigned int vsel) | ||
61 | { | ||
62 | int uV = 0; | ||
63 | |||
64 | if (vsel > 63) | ||
65 | return -EINVAL; | ||
66 | |||
67 | if (vsel <= 24) | ||
68 | uV = vsel * 25000 + 900000; | ||
69 | else if (vsel <= 52) | ||
70 | uV = (vsel - 24) * 50000 + 1500000; | ||
71 | else if (vsel < 56) | ||
72 | uV = (vsel - 52) * 100000 + 2900000; | ||
73 | else | ||
74 | uV = 3300000; | ||
75 | |||
76 | return uV; | ||
77 | } | ||
78 | |||
79 | static int tps65217_uv_to_vsel1(int uV, unsigned int *vsel) | ||
80 | { | ||
81 | if ((uV < 0) && (uV > 3300000)) | ||
82 | return -EINVAL; | ||
83 | |||
84 | if (uV <= 1500000) | ||
85 | *vsel = (uV - 875001) / 25000; | ||
86 | else if (uV <= 2900000) | ||
87 | *vsel = 24 + (uV - 1450001) / 50000; | ||
88 | else if (uV < 3300000) | ||
89 | *vsel = 52 + (uV - 2800001) / 100000; | ||
90 | else | ||
91 | *vsel = 56; | ||
92 | |||
93 | return 0; | ||
94 | } | ||
95 | |||
96 | static int tps65217_vsel_to_uv2(unsigned int vsel) | ||
97 | { | ||
98 | int uV = 0; | ||
99 | |||
100 | if (vsel > 31) | ||
101 | return -EINVAL; | ||
102 | |||
103 | if (vsel <= 8) | ||
104 | uV = vsel * 50000 + 1500000; | ||
105 | else if (vsel <= 13) | ||
106 | uV = (vsel - 8) * 100000 + 1900000; | ||
107 | else | ||
108 | uV = (vsel - 13) * 50000 + 2400000; | ||
109 | |||
110 | return uV; | ||
111 | } | ||
112 | |||
113 | static int tps65217_uv_to_vsel2(int uV, unsigned int *vsel) | ||
114 | { | ||
115 | if ((uV < 0) && (uV > 3300000)) | ||
116 | return -EINVAL; | ||
117 | |||
118 | if (uV <= 1900000) | ||
119 | *vsel = (uV - 1450001) / 50000; | ||
120 | else if (uV <= 2400000) | ||
121 | *vsel = 8 + (uV - 1800001) / 100000; | ||
122 | else | ||
123 | *vsel = 13 + (uV - 2350001) / 50000; | ||
124 | |||
125 | return 0; | ||
126 | } | ||
127 | |||
128 | static struct tps_info tps65217_pmic_regs[] = { | ||
129 | TPS65217_INFO("DCDC1", 900000, 1800000, tps65217_vsel_to_uv1, | ||
130 | tps65217_uv_to_vsel1, NULL, 64, TPS65217_ENABLE_DC1_EN, | ||
131 | TPS65217_REG_DEFDCDC1, TPS65217_DEFDCDCX_DCDC_MASK), | ||
132 | TPS65217_INFO("DCDC2", 900000, 3300000, tps65217_vsel_to_uv1, | ||
133 | tps65217_uv_to_vsel1, NULL, 64, TPS65217_ENABLE_DC2_EN, | ||
134 | TPS65217_REG_DEFDCDC2, TPS65217_DEFDCDCX_DCDC_MASK), | ||
135 | TPS65217_INFO("DCDC3", 900000, 1500000, tps65217_vsel_to_uv1, | ||
136 | tps65217_uv_to_vsel1, NULL, 64, TPS65217_ENABLE_DC3_EN, | ||
137 | TPS65217_REG_DEFDCDC3, TPS65217_DEFDCDCX_DCDC_MASK), | ||
138 | TPS65217_INFO("LDO1", 1000000, 3300000, NULL, NULL, LDO1_VSEL_table, | ||
139 | 16, TPS65217_ENABLE_LDO1_EN, TPS65217_REG_DEFLDO1, | ||
140 | TPS65217_DEFLDO1_LDO1_MASK), | ||
141 | TPS65217_INFO("LDO2", 900000, 3300000, tps65217_vsel_to_uv1, | ||
142 | tps65217_uv_to_vsel1, NULL, 64, TPS65217_ENABLE_LDO2_EN, | ||
143 | TPS65217_REG_DEFLDO2, TPS65217_DEFLDO2_LDO2_MASK), | ||
144 | TPS65217_INFO("LDO3", 1800000, 3300000, tps65217_vsel_to_uv2, | ||
145 | tps65217_uv_to_vsel2, NULL, 32, | ||
146 | TPS65217_ENABLE_LS1_EN | TPS65217_DEFLDO3_LDO3_EN, | ||
147 | TPS65217_REG_DEFLS1, TPS65217_DEFLDO3_LDO3_MASK), | ||
148 | TPS65217_INFO("LDO4", 1800000, 3300000, tps65217_vsel_to_uv2, | ||
149 | tps65217_uv_to_vsel2, NULL, 32, | ||
150 | TPS65217_ENABLE_LS2_EN | TPS65217_DEFLDO4_LDO4_EN, | ||
151 | TPS65217_REG_DEFLS2, TPS65217_DEFLDO4_LDO4_MASK), | ||
152 | }; | ||
153 | |||
154 | static int tps65217_pmic_dcdc_is_enabled(struct regulator_dev *dev) | ||
155 | { | ||
156 | int ret; | ||
157 | struct tps65217 *tps = rdev_get_drvdata(dev); | ||
158 | unsigned int data, dcdc = rdev_get_id(dev); | ||
159 | |||
160 | if (dcdc < TPS65217_DCDC_1 || dcdc > TPS65217_DCDC_3) | ||
161 | return -EINVAL; | ||
162 | |||
163 | ret = tps65217_reg_read(tps, TPS65217_REG_ENABLE, &data); | ||
164 | if (ret) | ||
165 | return ret; | ||
166 | |||
167 | return (data & tps->info[dcdc]->enable_mask) ? 1 : 0; | ||
168 | } | ||
169 | |||
170 | static int tps65217_pmic_ldo_is_enabled(struct regulator_dev *dev) | ||
171 | { | ||
172 | int ret; | ||
173 | struct tps65217 *tps = rdev_get_drvdata(dev); | ||
174 | unsigned int data, ldo = rdev_get_id(dev); | ||
175 | |||
176 | if (ldo < TPS65217_LDO_1 || ldo > TPS65217_LDO_4) | ||
177 | return -EINVAL; | ||
178 | |||
179 | ret = tps65217_reg_read(tps, TPS65217_REG_ENABLE, &data); | ||
180 | if (ret) | ||
181 | return ret; | ||
182 | |||
183 | return (data & tps->info[ldo]->enable_mask) ? 1 : 0; | ||
184 | } | ||
185 | |||
186 | static int tps65217_pmic_dcdc_enable(struct regulator_dev *dev) | ||
187 | { | ||
188 | struct tps65217 *tps = rdev_get_drvdata(dev); | ||
189 | unsigned int dcdc = rdev_get_id(dev); | ||
190 | |||
191 | if (dcdc < TPS65217_DCDC_1 || dcdc > TPS65217_DCDC_3) | ||
192 | return -EINVAL; | ||
193 | |||
194 | /* Enable the regulator and password protection is level 1 */ | ||
195 | return tps65217_set_bits(tps, TPS65217_REG_ENABLE, | ||
196 | tps->info[dcdc]->enable_mask, | ||
197 | tps->info[dcdc]->enable_mask, | ||
198 | TPS65217_PROTECT_L1); | ||
199 | } | ||
200 | |||
201 | static int tps65217_pmic_dcdc_disable(struct regulator_dev *dev) | ||
202 | { | ||
203 | struct tps65217 *tps = rdev_get_drvdata(dev); | ||
204 | unsigned int dcdc = rdev_get_id(dev); | ||
205 | |||
206 | if (dcdc < TPS65217_DCDC_1 || dcdc > TPS65217_DCDC_3) | ||
207 | return -EINVAL; | ||
208 | |||
209 | /* Disable the regulator and password protection is level 1 */ | ||
210 | return tps65217_clear_bits(tps, TPS65217_REG_ENABLE, | ||
211 | tps->info[dcdc]->enable_mask, TPS65217_PROTECT_L1); | ||
212 | } | ||
213 | |||
214 | static int tps65217_pmic_ldo_enable(struct regulator_dev *dev) | ||
215 | { | ||
216 | struct tps65217 *tps = rdev_get_drvdata(dev); | ||
217 | unsigned int ldo = rdev_get_id(dev); | ||
218 | |||
219 | if (ldo < TPS65217_LDO_1 || ldo > TPS65217_LDO_4) | ||
220 | return -EINVAL; | ||
221 | |||
222 | /* Enable the regulator and password protection is level 1 */ | ||
223 | return tps65217_set_bits(tps, TPS65217_REG_ENABLE, | ||
224 | tps->info[ldo]->enable_mask, | ||
225 | tps->info[ldo]->enable_mask, | ||
226 | TPS65217_PROTECT_L1); | ||
227 | } | ||
228 | |||
229 | static int tps65217_pmic_ldo_disable(struct regulator_dev *dev) | ||
230 | { | ||
231 | struct tps65217 *tps = rdev_get_drvdata(dev); | ||
232 | unsigned int ldo = rdev_get_id(dev); | ||
233 | |||
234 | if (ldo < TPS65217_LDO_1 || ldo > TPS65217_LDO_4) | ||
235 | return -EINVAL; | ||
236 | |||
237 | /* Disable the regulator and password protection is level 1 */ | ||
238 | return tps65217_clear_bits(tps, TPS65217_REG_ENABLE, | ||
239 | tps->info[ldo]->enable_mask, TPS65217_PROTECT_L1); | ||
240 | } | ||
241 | |||
242 | static int tps65217_pmic_dcdc_get_voltage_sel(struct regulator_dev *dev) | ||
243 | { | ||
244 | int ret; | ||
245 | struct tps65217 *tps = rdev_get_drvdata(dev); | ||
246 | unsigned int selector, dcdc = rdev_get_id(dev); | ||
247 | |||
248 | if (dcdc < TPS65217_DCDC_1 || dcdc > TPS65217_DCDC_3) | ||
249 | return -EINVAL; | ||
250 | |||
251 | ret = tps65217_reg_read(tps, tps->info[dcdc]->set_vout_reg, &selector); | ||
252 | if (ret) | ||
253 | return ret; | ||
254 | |||
255 | selector &= tps->info[dcdc]->set_vout_mask; | ||
256 | |||
257 | return selector; | ||
258 | } | ||
259 | |||
260 | static int tps65217_pmic_dcdc_set_voltage(struct regulator_dev *dev, | ||
261 | int min_uV, int max_uV, unsigned *selector) | ||
262 | { | ||
263 | int ret; | ||
264 | struct tps65217 *tps = rdev_get_drvdata(dev); | ||
265 | unsigned int dcdc = rdev_get_id(dev); | ||
266 | |||
267 | if (dcdc < TPS65217_DCDC_1 || dcdc > TPS65217_DCDC_3) | ||
268 | return -EINVAL; | ||
269 | |||
270 | if (min_uV < tps->info[dcdc]->min_uV | ||
271 | || min_uV > tps->info[dcdc]->max_uV) | ||
272 | return -EINVAL; | ||
273 | |||
274 | if (max_uV < tps->info[dcdc]->min_uV | ||
275 | || max_uV > tps->info[dcdc]->max_uV) | ||
276 | return -EINVAL; | ||
277 | |||
278 | ret = tps->info[dcdc]->uv_to_vsel(min_uV, selector); | ||
279 | if (ret) | ||
280 | return ret; | ||
281 | |||
282 | /* Set the voltage based on vsel value and write protect level is 2 */ | ||
283 | ret = tps65217_set_bits(tps, tps->info[dcdc]->set_vout_reg, | ||
284 | tps->info[dcdc]->set_vout_mask, | ||
285 | *selector, TPS65217_PROTECT_L2); | ||
286 | if (ret) | ||
287 | return ret; | ||
288 | |||
289 | /* Set GO bit to initiate voltage transistion */ | ||
290 | return tps65217_set_bits(tps, TPS65217_REG_DEFSLEW, | ||
291 | TPS65217_DEFSLEW_GO, TPS65217_DEFSLEW_GO, | ||
292 | TPS65217_PROTECT_L2); | ||
293 | } | ||
294 | |||
295 | static int tps65217_pmic_ldo_get_voltage_sel(struct regulator_dev *dev) | ||
296 | { | ||
297 | int ret; | ||
298 | struct tps65217 *tps = rdev_get_drvdata(dev); | ||
299 | unsigned int selector, ldo = rdev_get_id(dev); | ||
300 | |||
301 | if (ldo < TPS65217_LDO_1 || ldo > TPS65217_LDO_4) | ||
302 | return -EINVAL; | ||
303 | |||
304 | ret = tps65217_reg_read(tps, tps->info[ldo]->set_vout_reg, &selector); | ||
305 | if (ret) | ||
306 | return ret; | ||
307 | |||
308 | selector &= tps->info[ldo]->set_vout_mask; | ||
309 | |||
310 | return selector; | ||
311 | } | ||
312 | |||
313 | static int tps65217_pmic_ldo_set_voltage_sel(struct regulator_dev *dev, | ||
314 | unsigned selector) | ||
315 | { | ||
316 | struct tps65217 *tps = rdev_get_drvdata(dev); | ||
317 | int ldo = rdev_get_id(dev); | ||
318 | |||
319 | if (ldo != TPS65217_LDO_1) | ||
320 | return -EINVAL; | ||
321 | |||
322 | if (selector >= tps->info[ldo]->table_len) | ||
323 | return -EINVAL; | ||
324 | |||
325 | /* Set the voltage based on vsel value and write protect level is 2 */ | ||
326 | return tps65217_set_bits(tps, tps->info[ldo]->set_vout_reg, | ||
327 | tps->info[ldo]->set_vout_mask, | ||
328 | selector, TPS65217_PROTECT_L2); | ||
329 | } | ||
330 | |||
331 | static int tps65217_pmic_ldo_set_voltage(struct regulator_dev *dev, | ||
332 | int min_uV, int max_uV, unsigned *selector) | ||
333 | { | ||
334 | int ret; | ||
335 | struct tps65217 *tps = rdev_get_drvdata(dev); | ||
336 | unsigned int ldo = rdev_get_id(dev); | ||
337 | |||
338 | if (ldo < TPS65217_LDO_2 || ldo > TPS65217_LDO_4) | ||
339 | return -EINVAL; | ||
340 | |||
341 | if (min_uV < tps->info[ldo]->min_uV | ||
342 | || min_uV > tps->info[ldo]->max_uV) | ||
343 | return -EINVAL; | ||
344 | |||
345 | if (max_uV < tps->info[ldo]->min_uV | ||
346 | || max_uV > tps->info[ldo]->max_uV) | ||
347 | return -EINVAL; | ||
348 | |||
349 | ret = tps->info[ldo]->uv_to_vsel(min_uV, selector); | ||
350 | if (ret) | ||
351 | return ret; | ||
352 | |||
353 | /* Set the voltage based on vsel value and write protect level is 2 */ | ||
354 | return tps65217_set_bits(tps, tps->info[ldo]->set_vout_reg, | ||
355 | tps->info[ldo]->set_vout_mask, | ||
356 | *selector, TPS65217_PROTECT_L2); | ||
357 | } | ||
358 | |||
359 | static int tps65217_pmic_dcdc_list_voltage(struct regulator_dev *dev, | ||
360 | unsigned selector) | ||
361 | { | ||
362 | struct tps65217 *tps = rdev_get_drvdata(dev); | ||
363 | unsigned int dcdc = rdev_get_id(dev); | ||
364 | |||
365 | if (dcdc < TPS65217_DCDC_1 || dcdc > TPS65217_DCDC_3) | ||
366 | return -EINVAL; | ||
367 | |||
368 | if (selector >= tps->info[dcdc]->table_len) | ||
369 | return -EINVAL; | ||
370 | |||
371 | return tps->info[dcdc]->vsel_to_uv(selector); | ||
372 | } | ||
373 | |||
374 | static int tps65217_pmic_ldo_list_voltage(struct regulator_dev *dev, | ||
375 | unsigned selector) | ||
376 | { | ||
377 | struct tps65217 *tps = rdev_get_drvdata(dev); | ||
378 | unsigned int ldo = rdev_get_id(dev); | ||
379 | |||
380 | if (ldo < TPS65217_LDO_1 || ldo > TPS65217_LDO_4) | ||
381 | return -EINVAL; | ||
382 | |||
383 | if (selector >= tps->info[ldo]->table_len) | ||
384 | return -EINVAL; | ||
385 | |||
386 | if (tps->info[ldo]->table) | ||
387 | return tps->info[ldo]->table[selector]; | ||
388 | |||
389 | return tps->info[ldo]->vsel_to_uv(selector); | ||
390 | } | ||
391 | |||
392 | /* Operations permitted on DCDCx */ | ||
393 | static struct regulator_ops tps65217_pmic_dcdc_ops = { | ||
394 | .is_enabled = tps65217_pmic_dcdc_is_enabled, | ||
395 | .enable = tps65217_pmic_dcdc_enable, | ||
396 | .disable = tps65217_pmic_dcdc_disable, | ||
397 | .get_voltage_sel = tps65217_pmic_dcdc_get_voltage_sel, | ||
398 | .set_voltage = tps65217_pmic_dcdc_set_voltage, | ||
399 | .list_voltage = tps65217_pmic_dcdc_list_voltage, | ||
400 | }; | ||
401 | |||
402 | /* Operations permitted on LDO1 */ | ||
403 | static struct regulator_ops tps65217_pmic_ldo1_ops = { | ||
404 | .is_enabled = tps65217_pmic_ldo_is_enabled, | ||
405 | .enable = tps65217_pmic_ldo_enable, | ||
406 | .disable = tps65217_pmic_ldo_disable, | ||
407 | .get_voltage_sel = tps65217_pmic_ldo_get_voltage_sel, | ||
408 | .set_voltage_sel = tps65217_pmic_ldo_set_voltage_sel, | ||
409 | .list_voltage = tps65217_pmic_ldo_list_voltage, | ||
410 | }; | ||
411 | |||
412 | /* Operations permitted on LDO2, LDO3 and LDO4 */ | ||
413 | static struct regulator_ops tps65217_pmic_ldo234_ops = { | ||
414 | .is_enabled = tps65217_pmic_ldo_is_enabled, | ||
415 | .enable = tps65217_pmic_ldo_enable, | ||
416 | .disable = tps65217_pmic_ldo_disable, | ||
417 | .get_voltage_sel = tps65217_pmic_ldo_get_voltage_sel, | ||
418 | .set_voltage = tps65217_pmic_ldo_set_voltage, | ||
419 | .list_voltage = tps65217_pmic_ldo_list_voltage, | ||
420 | }; | ||
421 | |||
422 | static struct regulator_desc regulators[] = { | ||
423 | TPS65217_REGULATOR("DCDC1", TPS65217_DCDC_1, | ||
424 | tps65217_pmic_dcdc_ops, 64), | ||
425 | TPS65217_REGULATOR("DCDC2",TPS65217_DCDC_2, | ||
426 | tps65217_pmic_dcdc_ops, 64), | ||
427 | TPS65217_REGULATOR("DCDC3", TPS65217_DCDC_3, | ||
428 | tps65217_pmic_dcdc_ops, 64), | ||
429 | TPS65217_REGULATOR("LDO1", TPS65217_LDO_1, | ||
430 | tps65217_pmic_ldo1_ops, 16), | ||
431 | TPS65217_REGULATOR("LDO2", TPS65217_LDO_2, | ||
432 | tps65217_pmic_ldo234_ops, 64), | ||
433 | TPS65217_REGULATOR("LDO3", TPS65217_LDO_3, | ||
434 | tps65217_pmic_ldo234_ops, 32), | ||
435 | TPS65217_REGULATOR("LDO4", TPS65217_LDO_4, | ||
436 | tps65217_pmic_ldo234_ops, 32), | ||
437 | }; | ||
438 | |||
439 | static int __devinit tps65217_regulator_probe(struct platform_device *pdev) | ||
440 | { | ||
441 | struct regulator_dev *rdev; | ||
442 | struct tps65217 *tps; | ||
443 | struct tps_info *info = &tps65217_pmic_regs[pdev->id]; | ||
444 | |||
445 | /* Already set by core driver */ | ||
446 | tps = dev_to_tps65217(pdev->dev.parent); | ||
447 | tps->info[pdev->id] = info; | ||
448 | |||
449 | rdev = regulator_register(®ulators[pdev->id], &pdev->dev, | ||
450 | pdev->dev.platform_data, tps, NULL); | ||
451 | if (IS_ERR(rdev)) | ||
452 | return PTR_ERR(rdev); | ||
453 | |||
454 | platform_set_drvdata(pdev, rdev); | ||
455 | |||
456 | return 0; | ||
457 | } | ||
458 | |||
459 | static int __devexit tps65217_regulator_remove(struct platform_device *pdev) | ||
460 | { | ||
461 | struct regulator_dev *rdev = platform_get_drvdata(pdev); | ||
462 | |||
463 | platform_set_drvdata(pdev, NULL); | ||
464 | regulator_unregister(rdev); | ||
465 | |||
466 | return 0; | ||
467 | } | ||
468 | |||
469 | static struct platform_driver tps65217_regulator_driver = { | ||
470 | .driver = { | ||
471 | .name = "tps65217-pmic", | ||
472 | }, | ||
473 | .probe = tps65217_regulator_probe, | ||
474 | .remove = __devexit_p(tps65217_regulator_remove), | ||
475 | }; | ||
476 | |||
477 | static int __init tps65217_regulator_init(void) | ||
478 | { | ||
479 | return platform_driver_register(&tps65217_regulator_driver); | ||
480 | } | ||
481 | subsys_initcall(tps65217_regulator_init); | ||
482 | |||
483 | static void __exit tps65217_regulator_exit(void) | ||
484 | { | ||
485 | platform_driver_unregister(&tps65217_regulator_driver); | ||
486 | } | ||
487 | module_exit(tps65217_regulator_exit); | ||
488 | |||
489 | |||
490 | MODULE_AUTHOR("AnilKumar Ch <anilkumar@ti.com>"); | ||
491 | MODULE_DESCRIPTION("TPS65217 voltage regulator driver"); | ||
492 | MODULE_ALIAS("platform:tps65217-pmic"); | ||
493 | MODULE_LICENSE("GPL v2"); | ||
diff --git a/drivers/regulator/tps65910-regulator.c b/drivers/regulator/tps65910-regulator.c index 5c15ba01e9c7..9092b7f998c1 100644 --- a/drivers/regulator/tps65910-regulator.c +++ b/drivers/regulator/tps65910-regulator.c | |||
@@ -26,6 +26,9 @@ | |||
26 | #include <linux/mfd/tps65910.h> | 26 | #include <linux/mfd/tps65910.h> |
27 | 27 | ||
28 | #define TPS65910_SUPPLY_STATE_ENABLED 0x1 | 28 | #define TPS65910_SUPPLY_STATE_ENABLED 0x1 |
29 | #define EXT_SLEEP_CONTROL (TPS65910_SLEEP_CONTROL_EXT_INPUT_EN1 | \ | ||
30 | TPS65910_SLEEP_CONTROL_EXT_INPUT_EN2 | \ | ||
31 | TPS65910_SLEEP_CONTROL_EXT_INPUT_EN3) | ||
29 | 32 | ||
30 | /* supported VIO voltages in milivolts */ | 33 | /* supported VIO voltages in milivolts */ |
31 | static const u16 VIO_VSEL_table[] = { | 34 | static const u16 VIO_VSEL_table[] = { |
@@ -83,8 +86,8 @@ struct tps_info { | |||
83 | const char *name; | 86 | const char *name; |
84 | unsigned min_uV; | 87 | unsigned min_uV; |
85 | unsigned max_uV; | 88 | unsigned max_uV; |
86 | u8 table_len; | 89 | u8 n_voltages; |
87 | const u16 *table; | 90 | const u16 *voltage_table; |
88 | }; | 91 | }; |
89 | 92 | ||
90 | static struct tps_info tps65910_regs[] = { | 93 | static struct tps_info tps65910_regs[] = { |
@@ -95,8 +98,8 @@ static struct tps_info tps65910_regs[] = { | |||
95 | .name = "VIO", | 98 | .name = "VIO", |
96 | .min_uV = 1500000, | 99 | .min_uV = 1500000, |
97 | .max_uV = 3300000, | 100 | .max_uV = 3300000, |
98 | .table_len = ARRAY_SIZE(VIO_VSEL_table), | 101 | .n_voltages = ARRAY_SIZE(VIO_VSEL_table), |
99 | .table = VIO_VSEL_table, | 102 | .voltage_table = VIO_VSEL_table, |
100 | }, | 103 | }, |
101 | { | 104 | { |
102 | .name = "VDD1", | 105 | .name = "VDD1", |
@@ -112,132 +115,179 @@ static struct tps_info tps65910_regs[] = { | |||
112 | .name = "VDD3", | 115 | .name = "VDD3", |
113 | .min_uV = 5000000, | 116 | .min_uV = 5000000, |
114 | .max_uV = 5000000, | 117 | .max_uV = 5000000, |
115 | .table_len = ARRAY_SIZE(VDD3_VSEL_table), | 118 | .n_voltages = ARRAY_SIZE(VDD3_VSEL_table), |
116 | .table = VDD3_VSEL_table, | 119 | .voltage_table = VDD3_VSEL_table, |
117 | }, | 120 | }, |
118 | { | 121 | { |
119 | .name = "VDIG1", | 122 | .name = "VDIG1", |
120 | .min_uV = 1200000, | 123 | .min_uV = 1200000, |
121 | .max_uV = 2700000, | 124 | .max_uV = 2700000, |
122 | .table_len = ARRAY_SIZE(VDIG1_VSEL_table), | 125 | .n_voltages = ARRAY_SIZE(VDIG1_VSEL_table), |
123 | .table = VDIG1_VSEL_table, | 126 | .voltage_table = VDIG1_VSEL_table, |
124 | }, | 127 | }, |
125 | { | 128 | { |
126 | .name = "VDIG2", | 129 | .name = "VDIG2", |
127 | .min_uV = 1000000, | 130 | .min_uV = 1000000, |
128 | .max_uV = 1800000, | 131 | .max_uV = 1800000, |
129 | .table_len = ARRAY_SIZE(VDIG2_VSEL_table), | 132 | .n_voltages = ARRAY_SIZE(VDIG2_VSEL_table), |
130 | .table = VDIG2_VSEL_table, | 133 | .voltage_table = VDIG2_VSEL_table, |
131 | }, | 134 | }, |
132 | { | 135 | { |
133 | .name = "VPLL", | 136 | .name = "VPLL", |
134 | .min_uV = 1000000, | 137 | .min_uV = 1000000, |
135 | .max_uV = 2500000, | 138 | .max_uV = 2500000, |
136 | .table_len = ARRAY_SIZE(VPLL_VSEL_table), | 139 | .n_voltages = ARRAY_SIZE(VPLL_VSEL_table), |
137 | .table = VPLL_VSEL_table, | 140 | .voltage_table = VPLL_VSEL_table, |
138 | }, | 141 | }, |
139 | { | 142 | { |
140 | .name = "VDAC", | 143 | .name = "VDAC", |
141 | .min_uV = 1800000, | 144 | .min_uV = 1800000, |
142 | .max_uV = 2850000, | 145 | .max_uV = 2850000, |
143 | .table_len = ARRAY_SIZE(VDAC_VSEL_table), | 146 | .n_voltages = ARRAY_SIZE(VDAC_VSEL_table), |
144 | .table = VDAC_VSEL_table, | 147 | .voltage_table = VDAC_VSEL_table, |
145 | }, | 148 | }, |
146 | { | 149 | { |
147 | .name = "VAUX1", | 150 | .name = "VAUX1", |
148 | .min_uV = 1800000, | 151 | .min_uV = 1800000, |
149 | .max_uV = 2850000, | 152 | .max_uV = 2850000, |
150 | .table_len = ARRAY_SIZE(VAUX1_VSEL_table), | 153 | .n_voltages = ARRAY_SIZE(VAUX1_VSEL_table), |
151 | .table = VAUX1_VSEL_table, | 154 | .voltage_table = VAUX1_VSEL_table, |
152 | }, | 155 | }, |
153 | { | 156 | { |
154 | .name = "VAUX2", | 157 | .name = "VAUX2", |
155 | .min_uV = 1800000, | 158 | .min_uV = 1800000, |
156 | .max_uV = 3300000, | 159 | .max_uV = 3300000, |
157 | .table_len = ARRAY_SIZE(VAUX2_VSEL_table), | 160 | .n_voltages = ARRAY_SIZE(VAUX2_VSEL_table), |
158 | .table = VAUX2_VSEL_table, | 161 | .voltage_table = VAUX2_VSEL_table, |
159 | }, | 162 | }, |
160 | { | 163 | { |
161 | .name = "VAUX33", | 164 | .name = "VAUX33", |
162 | .min_uV = 1800000, | 165 | .min_uV = 1800000, |
163 | .max_uV = 3300000, | 166 | .max_uV = 3300000, |
164 | .table_len = ARRAY_SIZE(VAUX33_VSEL_table), | 167 | .n_voltages = ARRAY_SIZE(VAUX33_VSEL_table), |
165 | .table = VAUX33_VSEL_table, | 168 | .voltage_table = VAUX33_VSEL_table, |
166 | }, | 169 | }, |
167 | { | 170 | { |
168 | .name = "VMMC", | 171 | .name = "VMMC", |
169 | .min_uV = 1800000, | 172 | .min_uV = 1800000, |
170 | .max_uV = 3300000, | 173 | .max_uV = 3300000, |
171 | .table_len = ARRAY_SIZE(VMMC_VSEL_table), | 174 | .n_voltages = ARRAY_SIZE(VMMC_VSEL_table), |
172 | .table = VMMC_VSEL_table, | 175 | .voltage_table = VMMC_VSEL_table, |
173 | }, | 176 | }, |
174 | }; | 177 | }; |
175 | 178 | ||
176 | static struct tps_info tps65911_regs[] = { | 179 | static struct tps_info tps65911_regs[] = { |
177 | { | 180 | { |
181 | .name = "VRTC", | ||
182 | }, | ||
183 | { | ||
178 | .name = "VIO", | 184 | .name = "VIO", |
179 | .min_uV = 1500000, | 185 | .min_uV = 1500000, |
180 | .max_uV = 3300000, | 186 | .max_uV = 3300000, |
181 | .table_len = ARRAY_SIZE(VIO_VSEL_table), | 187 | .n_voltages = ARRAY_SIZE(VIO_VSEL_table), |
182 | .table = VIO_VSEL_table, | 188 | .voltage_table = VIO_VSEL_table, |
183 | }, | 189 | }, |
184 | { | 190 | { |
185 | .name = "VDD1", | 191 | .name = "VDD1", |
186 | .min_uV = 600000, | 192 | .min_uV = 600000, |
187 | .max_uV = 4500000, | 193 | .max_uV = 4500000, |
194 | .n_voltages = 73, | ||
188 | }, | 195 | }, |
189 | { | 196 | { |
190 | .name = "VDD2", | 197 | .name = "VDD2", |
191 | .min_uV = 600000, | 198 | .min_uV = 600000, |
192 | .max_uV = 4500000, | 199 | .max_uV = 4500000, |
200 | .n_voltages = 73, | ||
193 | }, | 201 | }, |
194 | { | 202 | { |
195 | .name = "VDDCTRL", | 203 | .name = "VDDCTRL", |
196 | .min_uV = 600000, | 204 | .min_uV = 600000, |
197 | .max_uV = 1400000, | 205 | .max_uV = 1400000, |
206 | .n_voltages = 65, | ||
198 | }, | 207 | }, |
199 | { | 208 | { |
200 | .name = "LDO1", | 209 | .name = "LDO1", |
201 | .min_uV = 1000000, | 210 | .min_uV = 1000000, |
202 | .max_uV = 3300000, | 211 | .max_uV = 3300000, |
212 | .n_voltages = 47, | ||
203 | }, | 213 | }, |
204 | { | 214 | { |
205 | .name = "LDO2", | 215 | .name = "LDO2", |
206 | .min_uV = 1000000, | 216 | .min_uV = 1000000, |
207 | .max_uV = 3300000, | 217 | .max_uV = 3300000, |
218 | .n_voltages = 47, | ||
208 | }, | 219 | }, |
209 | { | 220 | { |
210 | .name = "LDO3", | 221 | .name = "LDO3", |
211 | .min_uV = 1000000, | 222 | .min_uV = 1000000, |
212 | .max_uV = 3300000, | 223 | .max_uV = 3300000, |
224 | .n_voltages = 24, | ||
213 | }, | 225 | }, |
214 | { | 226 | { |
215 | .name = "LDO4", | 227 | .name = "LDO4", |
216 | .min_uV = 1000000, | 228 | .min_uV = 1000000, |
217 | .max_uV = 3300000, | 229 | .max_uV = 3300000, |
230 | .n_voltages = 47, | ||
218 | }, | 231 | }, |
219 | { | 232 | { |
220 | .name = "LDO5", | 233 | .name = "LDO5", |
221 | .min_uV = 1000000, | 234 | .min_uV = 1000000, |
222 | .max_uV = 3300000, | 235 | .max_uV = 3300000, |
236 | .n_voltages = 24, | ||
223 | }, | 237 | }, |
224 | { | 238 | { |
225 | .name = "LDO6", | 239 | .name = "LDO6", |
226 | .min_uV = 1000000, | 240 | .min_uV = 1000000, |
227 | .max_uV = 3300000, | 241 | .max_uV = 3300000, |
242 | .n_voltages = 24, | ||
228 | }, | 243 | }, |
229 | { | 244 | { |
230 | .name = "LDO7", | 245 | .name = "LDO7", |
231 | .min_uV = 1000000, | 246 | .min_uV = 1000000, |
232 | .max_uV = 3300000, | 247 | .max_uV = 3300000, |
248 | .n_voltages = 24, | ||
233 | }, | 249 | }, |
234 | { | 250 | { |
235 | .name = "LDO8", | 251 | .name = "LDO8", |
236 | .min_uV = 1000000, | 252 | .min_uV = 1000000, |
237 | .max_uV = 3300000, | 253 | .max_uV = 3300000, |
254 | .n_voltages = 24, | ||
238 | }, | 255 | }, |
239 | }; | 256 | }; |
240 | 257 | ||
258 | #define EXT_CONTROL_REG_BITS(id, regs_offs, bits) (((regs_offs) << 8) | (bits)) | ||
259 | static unsigned int tps65910_ext_sleep_control[] = { | ||
260 | 0, | ||
261 | EXT_CONTROL_REG_BITS(VIO, 1, 0), | ||
262 | EXT_CONTROL_REG_BITS(VDD1, 1, 1), | ||
263 | EXT_CONTROL_REG_BITS(VDD2, 1, 2), | ||
264 | EXT_CONTROL_REG_BITS(VDD3, 1, 3), | ||
265 | EXT_CONTROL_REG_BITS(VDIG1, 0, 1), | ||
266 | EXT_CONTROL_REG_BITS(VDIG2, 0, 2), | ||
267 | EXT_CONTROL_REG_BITS(VPLL, 0, 6), | ||
268 | EXT_CONTROL_REG_BITS(VDAC, 0, 7), | ||
269 | EXT_CONTROL_REG_BITS(VAUX1, 0, 3), | ||
270 | EXT_CONTROL_REG_BITS(VAUX2, 0, 4), | ||
271 | EXT_CONTROL_REG_BITS(VAUX33, 0, 5), | ||
272 | EXT_CONTROL_REG_BITS(VMMC, 0, 0), | ||
273 | }; | ||
274 | |||
275 | static unsigned int tps65911_ext_sleep_control[] = { | ||
276 | 0, | ||
277 | EXT_CONTROL_REG_BITS(VIO, 1, 0), | ||
278 | EXT_CONTROL_REG_BITS(VDD1, 1, 1), | ||
279 | EXT_CONTROL_REG_BITS(VDD2, 1, 2), | ||
280 | EXT_CONTROL_REG_BITS(VDDCTRL, 1, 3), | ||
281 | EXT_CONTROL_REG_BITS(LDO1, 0, 1), | ||
282 | EXT_CONTROL_REG_BITS(LDO2, 0, 2), | ||
283 | EXT_CONTROL_REG_BITS(LDO3, 0, 7), | ||
284 | EXT_CONTROL_REG_BITS(LDO4, 0, 6), | ||
285 | EXT_CONTROL_REG_BITS(LDO5, 0, 3), | ||
286 | EXT_CONTROL_REG_BITS(LDO6, 0, 0), | ||
287 | EXT_CONTROL_REG_BITS(LDO7, 0, 5), | ||
288 | EXT_CONTROL_REG_BITS(LDO8, 0, 4), | ||
289 | }; | ||
290 | |||
241 | struct tps65910_reg { | 291 | struct tps65910_reg { |
242 | struct regulator_desc *desc; | 292 | struct regulator_desc *desc; |
243 | struct tps65910 *mfd; | 293 | struct tps65910 *mfd; |
@@ -247,6 +297,8 @@ struct tps65910_reg { | |||
247 | int num_regulators; | 297 | int num_regulators; |
248 | int mode; | 298 | int mode; |
249 | int (*get_ctrl_reg)(int); | 299 | int (*get_ctrl_reg)(int); |
300 | unsigned int *ext_sleep_control; | ||
301 | unsigned int board_ext_control[TPS65910_NUM_REGS]; | ||
250 | }; | 302 | }; |
251 | 303 | ||
252 | static inline int tps65910_read(struct tps65910_reg *pmic, u8 reg) | 304 | static inline int tps65910_read(struct tps65910_reg *pmic, u8 reg) |
@@ -572,7 +624,7 @@ static int tps65910_get_voltage(struct regulator_dev *dev) | |||
572 | return -EINVAL; | 624 | return -EINVAL; |
573 | } | 625 | } |
574 | 626 | ||
575 | voltage = pmic->info[id]->table[value] * 1000; | 627 | voltage = pmic->info[id]->voltage_table[value] * 1000; |
576 | 628 | ||
577 | return voltage; | 629 | return voltage; |
578 | } | 630 | } |
@@ -622,7 +674,7 @@ static int tps65911_get_voltage(struct regulator_dev *dev) | |||
622 | step_mv = 100; | 674 | step_mv = 100; |
623 | break; | 675 | break; |
624 | case TPS65910_REG_VIO: | 676 | case TPS65910_REG_VIO: |
625 | return pmic->info[id]->table[value] * 1000; | 677 | return pmic->info[id]->voltage_table[value] * 1000; |
626 | break; | 678 | break; |
627 | default: | 679 | default: |
628 | return -EINVAL; | 680 | return -EINVAL; |
@@ -756,10 +808,10 @@ static int tps65910_list_voltage(struct regulator_dev *dev, | |||
756 | if (id < TPS65910_REG_VIO || id > TPS65910_REG_VMMC) | 808 | if (id < TPS65910_REG_VIO || id > TPS65910_REG_VMMC) |
757 | return -EINVAL; | 809 | return -EINVAL; |
758 | 810 | ||
759 | if (selector >= pmic->info[id]->table_len) | 811 | if (selector >= pmic->info[id]->n_voltages) |
760 | return -EINVAL; | 812 | return -EINVAL; |
761 | else | 813 | else |
762 | voltage = pmic->info[id]->table[selector] * 1000; | 814 | voltage = pmic->info[id]->voltage_table[selector] * 1000; |
763 | 815 | ||
764 | return voltage; | 816 | return voltage; |
765 | } | 817 | } |
@@ -795,7 +847,7 @@ static int tps65911_list_voltage(struct regulator_dev *dev, unsigned selector) | |||
795 | step_mv = 100; | 847 | step_mv = 100; |
796 | break; | 848 | break; |
797 | case TPS65910_REG_VIO: | 849 | case TPS65910_REG_VIO: |
798 | return pmic->info[id]->table[selector] * 1000; | 850 | return pmic->info[id]->voltage_table[selector] * 1000; |
799 | default: | 851 | default: |
800 | return -EINVAL; | 852 | return -EINVAL; |
801 | } | 853 | } |
@@ -847,6 +899,131 @@ static struct regulator_ops tps65911_ops = { | |||
847 | .list_voltage = tps65911_list_voltage, | 899 | .list_voltage = tps65911_list_voltage, |
848 | }; | 900 | }; |
849 | 901 | ||
902 | static int tps65910_set_ext_sleep_config(struct tps65910_reg *pmic, | ||
903 | int id, int ext_sleep_config) | ||
904 | { | ||
905 | struct tps65910 *mfd = pmic->mfd; | ||
906 | u8 regoffs = (pmic->ext_sleep_control[id] >> 8) & 0xFF; | ||
907 | u8 bit_pos = (1 << pmic->ext_sleep_control[id] & 0xFF); | ||
908 | int ret; | ||
909 | |||
910 | /* | ||
911 | * Regulator can not be control from multiple external input EN1, EN2 | ||
912 | * and EN3 together. | ||
913 | */ | ||
914 | if (ext_sleep_config & EXT_SLEEP_CONTROL) { | ||
915 | int en_count; | ||
916 | en_count = ((ext_sleep_config & | ||
917 | TPS65910_SLEEP_CONTROL_EXT_INPUT_EN1) != 0); | ||
918 | en_count += ((ext_sleep_config & | ||
919 | TPS65910_SLEEP_CONTROL_EXT_INPUT_EN2) != 0); | ||
920 | en_count += ((ext_sleep_config & | ||
921 | TPS65910_SLEEP_CONTROL_EXT_INPUT_EN3) != 0); | ||
922 | if (en_count > 1) { | ||
923 | dev_err(mfd->dev, | ||
924 | "External sleep control flag is not proper\n"); | ||
925 | return -EINVAL; | ||
926 | } | ||
927 | } | ||
928 | |||
929 | pmic->board_ext_control[id] = ext_sleep_config; | ||
930 | |||
931 | /* External EN1 control */ | ||
932 | if (ext_sleep_config & TPS65910_SLEEP_CONTROL_EXT_INPUT_EN1) | ||
933 | ret = tps65910_set_bits(mfd, | ||
934 | TPS65910_EN1_LDO_ASS + regoffs, bit_pos); | ||
935 | else | ||
936 | ret = tps65910_clear_bits(mfd, | ||
937 | TPS65910_EN1_LDO_ASS + regoffs, bit_pos); | ||
938 | if (ret < 0) { | ||
939 | dev_err(mfd->dev, | ||
940 | "Error in configuring external control EN1\n"); | ||
941 | return ret; | ||
942 | } | ||
943 | |||
944 | /* External EN2 control */ | ||
945 | if (ext_sleep_config & TPS65910_SLEEP_CONTROL_EXT_INPUT_EN2) | ||
946 | ret = tps65910_set_bits(mfd, | ||
947 | TPS65910_EN2_LDO_ASS + regoffs, bit_pos); | ||
948 | else | ||
949 | ret = tps65910_clear_bits(mfd, | ||
950 | TPS65910_EN2_LDO_ASS + regoffs, bit_pos); | ||
951 | if (ret < 0) { | ||
952 | dev_err(mfd->dev, | ||
953 | "Error in configuring external control EN2\n"); | ||
954 | return ret; | ||
955 | } | ||
956 | |||
957 | /* External EN3 control for TPS65910 LDO only */ | ||
958 | if ((tps65910_chip_id(mfd) == TPS65910) && | ||
959 | (id >= TPS65910_REG_VDIG1)) { | ||
960 | if (ext_sleep_config & TPS65910_SLEEP_CONTROL_EXT_INPUT_EN3) | ||
961 | ret = tps65910_set_bits(mfd, | ||
962 | TPS65910_EN3_LDO_ASS + regoffs, bit_pos); | ||
963 | else | ||
964 | ret = tps65910_clear_bits(mfd, | ||
965 | TPS65910_EN3_LDO_ASS + regoffs, bit_pos); | ||
966 | if (ret < 0) { | ||
967 | dev_err(mfd->dev, | ||
968 | "Error in configuring external control EN3\n"); | ||
969 | return ret; | ||
970 | } | ||
971 | } | ||
972 | |||
973 | /* Return if no external control is selected */ | ||
974 | if (!(ext_sleep_config & EXT_SLEEP_CONTROL)) { | ||
975 | /* Clear all sleep controls */ | ||
976 | ret = tps65910_clear_bits(mfd, | ||
977 | TPS65910_SLEEP_KEEP_LDO_ON + regoffs, bit_pos); | ||
978 | if (!ret) | ||
979 | ret = tps65910_clear_bits(mfd, | ||
980 | TPS65910_SLEEP_SET_LDO_OFF + regoffs, bit_pos); | ||
981 | if (ret < 0) | ||
982 | dev_err(mfd->dev, | ||
983 | "Error in configuring SLEEP register\n"); | ||
984 | return ret; | ||
985 | } | ||
986 | |||
987 | /* | ||
988 | * For regulator that has separate operational and sleep register make | ||
989 | * sure that operational is used and clear sleep register to turn | ||
990 | * regulator off when external control is inactive | ||
991 | */ | ||
992 | if ((id == TPS65910_REG_VDD1) || | ||
993 | (id == TPS65910_REG_VDD2) || | ||
994 | ((id == TPS65911_REG_VDDCTRL) && | ||
995 | (tps65910_chip_id(mfd) == TPS65911))) { | ||
996 | int op_reg_add = pmic->get_ctrl_reg(id) + 1; | ||
997 | int sr_reg_add = pmic->get_ctrl_reg(id) + 2; | ||
998 | int opvsel = tps65910_reg_read(pmic, op_reg_add); | ||
999 | int srvsel = tps65910_reg_read(pmic, sr_reg_add); | ||
1000 | if (opvsel & VDD1_OP_CMD_MASK) { | ||
1001 | u8 reg_val = srvsel & VDD1_OP_SEL_MASK; | ||
1002 | ret = tps65910_reg_write(pmic, op_reg_add, reg_val); | ||
1003 | if (ret < 0) { | ||
1004 | dev_err(mfd->dev, | ||
1005 | "Error in configuring op register\n"); | ||
1006 | return ret; | ||
1007 | } | ||
1008 | } | ||
1009 | ret = tps65910_reg_write(pmic, sr_reg_add, 0); | ||
1010 | if (ret < 0) { | ||
1011 | dev_err(mfd->dev, "Error in settting sr register\n"); | ||
1012 | return ret; | ||
1013 | } | ||
1014 | } | ||
1015 | |||
1016 | ret = tps65910_clear_bits(mfd, | ||
1017 | TPS65910_SLEEP_KEEP_LDO_ON + regoffs, bit_pos); | ||
1018 | if (!ret) | ||
1019 | ret = tps65910_set_bits(mfd, | ||
1020 | TPS65910_SLEEP_SET_LDO_OFF + regoffs, bit_pos); | ||
1021 | if (ret < 0) | ||
1022 | dev_err(mfd->dev, | ||
1023 | "Error in configuring SLEEP register\n"); | ||
1024 | return ret; | ||
1025 | } | ||
1026 | |||
850 | static __devinit int tps65910_probe(struct platform_device *pdev) | 1027 | static __devinit int tps65910_probe(struct platform_device *pdev) |
851 | { | 1028 | { |
852 | struct tps65910 *tps65910 = dev_get_drvdata(pdev->dev.parent); | 1029 | struct tps65910 *tps65910 = dev_get_drvdata(pdev->dev.parent); |
@@ -877,11 +1054,13 @@ static __devinit int tps65910_probe(struct platform_device *pdev) | |||
877 | case TPS65910: | 1054 | case TPS65910: |
878 | pmic->get_ctrl_reg = &tps65910_get_ctrl_register; | 1055 | pmic->get_ctrl_reg = &tps65910_get_ctrl_register; |
879 | pmic->num_regulators = ARRAY_SIZE(tps65910_regs); | 1056 | pmic->num_regulators = ARRAY_SIZE(tps65910_regs); |
1057 | pmic->ext_sleep_control = tps65910_ext_sleep_control; | ||
880 | info = tps65910_regs; | 1058 | info = tps65910_regs; |
881 | break; | 1059 | break; |
882 | case TPS65911: | 1060 | case TPS65911: |
883 | pmic->get_ctrl_reg = &tps65911_get_ctrl_register; | 1061 | pmic->get_ctrl_reg = &tps65911_get_ctrl_register; |
884 | pmic->num_regulators = ARRAY_SIZE(tps65911_regs); | 1062 | pmic->num_regulators = ARRAY_SIZE(tps65911_regs); |
1063 | pmic->ext_sleep_control = tps65911_ext_sleep_control; | ||
885 | info = tps65911_regs; | 1064 | info = tps65911_regs; |
886 | break; | 1065 | break; |
887 | default: | 1066 | default: |
@@ -926,7 +1105,7 @@ static __devinit int tps65910_probe(struct platform_device *pdev) | |||
926 | 1105 | ||
927 | pmic->desc[i].name = info->name; | 1106 | pmic->desc[i].name = info->name; |
928 | pmic->desc[i].id = i; | 1107 | pmic->desc[i].id = i; |
929 | pmic->desc[i].n_voltages = info->table_len; | 1108 | pmic->desc[i].n_voltages = info->n_voltages; |
930 | 1109 | ||
931 | if (i == TPS65910_REG_VDD1 || i == TPS65910_REG_VDD2) { | 1110 | if (i == TPS65910_REG_VDD1 || i == TPS65910_REG_VDD2) { |
932 | pmic->desc[i].ops = &tps65910_ops_dcdc; | 1111 | pmic->desc[i].ops = &tps65910_ops_dcdc; |
@@ -944,6 +1123,16 @@ static __devinit int tps65910_probe(struct platform_device *pdev) | |||
944 | pmic->desc[i].ops = &tps65911_ops; | 1123 | pmic->desc[i].ops = &tps65911_ops; |
945 | } | 1124 | } |
946 | 1125 | ||
1126 | err = tps65910_set_ext_sleep_config(pmic, i, | ||
1127 | pmic_plat_data->regulator_ext_sleep_control[i]); | ||
1128 | /* | ||
1129 | * Failing on regulator for configuring externally control | ||
1130 | * is not a serious issue, just throw warning. | ||
1131 | */ | ||
1132 | if (err < 0) | ||
1133 | dev_warn(tps65910->dev, | ||
1134 | "Failed to initialise ext control config\n"); | ||
1135 | |||
947 | pmic->desc[i].type = REGULATOR_VOLTAGE; | 1136 | pmic->desc[i].type = REGULATOR_VOLTAGE; |
948 | pmic->desc[i].owner = THIS_MODULE; | 1137 | pmic->desc[i].owner = THIS_MODULE; |
949 | 1138 | ||
@@ -990,6 +1179,36 @@ static int __devexit tps65910_remove(struct platform_device *pdev) | |||
990 | return 0; | 1179 | return 0; |
991 | } | 1180 | } |
992 | 1181 | ||
1182 | static void tps65910_shutdown(struct platform_device *pdev) | ||
1183 | { | ||
1184 | struct tps65910_reg *pmic = platform_get_drvdata(pdev); | ||
1185 | int i; | ||
1186 | |||
1187 | /* | ||
1188 | * Before bootloader jumps to kernel, it makes sure that required | ||
1189 | * external control signals are in desired state so that given rails | ||
1190 | * can be configure accordingly. | ||
1191 | * If rails are configured to be controlled from external control | ||
1192 | * then before shutting down/rebooting the system, the external | ||
1193 | * control configuration need to be remove from the rails so that | ||
1194 | * its output will be available as per register programming even | ||
1195 | * if external controls are removed. This is require when the POR | ||
1196 | * value of the control signals are not in active state and before | ||
1197 | * bootloader initializes it, the system requires the rail output | ||
1198 | * to be active for booting. | ||
1199 | */ | ||
1200 | for (i = 0; i < pmic->num_regulators; i++) { | ||
1201 | int err; | ||
1202 | if (!pmic->rdev[i]) | ||
1203 | continue; | ||
1204 | |||
1205 | err = tps65910_set_ext_sleep_config(pmic, i, 0); | ||
1206 | if (err < 0) | ||
1207 | dev_err(&pdev->dev, | ||
1208 | "Error in clearing external control\n"); | ||
1209 | } | ||
1210 | } | ||
1211 | |||
993 | static struct platform_driver tps65910_driver = { | 1212 | static struct platform_driver tps65910_driver = { |
994 | .driver = { | 1213 | .driver = { |
995 | .name = "tps65910-pmic", | 1214 | .name = "tps65910-pmic", |
@@ -997,6 +1216,7 @@ static struct platform_driver tps65910_driver = { | |||
997 | }, | 1216 | }, |
998 | .probe = tps65910_probe, | 1217 | .probe = tps65910_probe, |
999 | .remove = __devexit_p(tps65910_remove), | 1218 | .remove = __devexit_p(tps65910_remove), |
1219 | .shutdown = tps65910_shutdown, | ||
1000 | }; | 1220 | }; |
1001 | 1221 | ||
1002 | static int __init tps65910_init(void) | 1222 | static int __init tps65910_init(void) |
diff --git a/drivers/regulator/wm8350-regulator.c b/drivers/regulator/wm8350-regulator.c index 6894009d815a..4f46067455c8 100644 --- a/drivers/regulator/wm8350-regulator.c +++ b/drivers/regulator/wm8350-regulator.c | |||
@@ -1544,7 +1544,7 @@ int wm8350_register_led(struct wm8350 *wm8350, int lednum, int dcdc, int isink, | |||
1544 | return -ENOMEM; | 1544 | return -ENOMEM; |
1545 | } | 1545 | } |
1546 | 1546 | ||
1547 | led->isink_consumer.dev = &pdev->dev; | 1547 | led->isink_consumer.dev_name = dev_name(&pdev->dev); |
1548 | led->isink_consumer.supply = "led_isink"; | 1548 | led->isink_consumer.supply = "led_isink"; |
1549 | led->isink_init.num_consumer_supplies = 1; | 1549 | led->isink_init.num_consumer_supplies = 1; |
1550 | led->isink_init.consumer_supplies = &led->isink_consumer; | 1550 | led->isink_init.consumer_supplies = &led->isink_consumer; |
@@ -1559,7 +1559,7 @@ int wm8350_register_led(struct wm8350 *wm8350, int lednum, int dcdc, int isink, | |||
1559 | return ret; | 1559 | return ret; |
1560 | } | 1560 | } |
1561 | 1561 | ||
1562 | led->dcdc_consumer.dev = &pdev->dev; | 1562 | led->dcdc_consumer.dev_name = dev_name(&pdev->dev); |
1563 | led->dcdc_consumer.supply = "led_vcc"; | 1563 | led->dcdc_consumer.supply = "led_vcc"; |
1564 | led->dcdc_init.num_consumer_supplies = 1; | 1564 | led->dcdc_init.num_consumer_supplies = 1; |
1565 | led->dcdc_init.consumer_supplies = &led->dcdc_consumer; | 1565 | led->dcdc_init.consumer_supplies = &led->dcdc_consumer; |