diff options
author | Mark Brown <broonie@opensource.wolfsonmicro.com> | 2013-02-19 07:43:08 -0500 |
---|---|---|
committer | Mark Brown <broonie@opensource.wolfsonmicro.com> | 2013-02-19 07:43:08 -0500 |
commit | 178a097d5e6ae57d67310ff18bef0afb5589f2dd (patch) | |
tree | f64a80af7069b46bea3f55c5f2d90e9881565a36 | |
parent | 728088871c867f912f8a33ea049b7c4135c95637 (diff) | |
parent | e81d7bc89c9623ea000890fb4cdf7e731dc21f71 (diff) |
Merge remote-tracking branch 'regulator/topic/s5m8767' into regulator-next
-rw-r--r-- | Documentation/devicetree/bindings/regulator/s5m8767-regulator.txt | 152 | ||||
-rw-r--r-- | drivers/mfd/sec-core.c | 75 | ||||
-rw-r--r-- | drivers/regulator/s5m8767.c | 268 | ||||
-rw-r--r-- | include/linux/mfd/samsung/core.h | 11 |
4 files changed, 438 insertions, 68 deletions
diff --git a/Documentation/devicetree/bindings/regulator/s5m8767-regulator.txt b/Documentation/devicetree/bindings/regulator/s5m8767-regulator.txt new file mode 100644 index 000000000000..a35ff99003a5 --- /dev/null +++ b/Documentation/devicetree/bindings/regulator/s5m8767-regulator.txt | |||
@@ -0,0 +1,152 @@ | |||
1 | * Samsung S5M8767 Voltage and Current Regulator | ||
2 | |||
3 | The Samsung S5M8767 is a multi-function device which includes volatage and | ||
4 | current regulators, rtc, charger controller and other sub-blocks. It is | ||
5 | interfaced to the host controller using a i2c interface. Each sub-block is | ||
6 | addressed by the host system using different i2c slave address. This document | ||
7 | describes the bindings for 'pmic' sub-block of s5m8767. | ||
8 | |||
9 | Required properties: | ||
10 | - compatible: Should be "samsung,s5m8767-pmic". | ||
11 | - reg: Specifies the i2c slave address of the pmic block. It should be 0x66. | ||
12 | |||
13 | - s5m8767,pmic-buck2-dvs-voltage: A set of 8 voltage values in micro-volt (uV) | ||
14 | units for buck2 when changing voltage using gpio dvs. Refer to [1] below | ||
15 | for additional information. | ||
16 | |||
17 | - s5m8767,pmic-buck3-dvs-voltage: A set of 8 voltage values in micro-volt (uV) | ||
18 | units for buck3 when changing voltage using gpio dvs. Refer to [1] below | ||
19 | for additional information. | ||
20 | |||
21 | - s5m8767,pmic-buck4-dvs-voltage: A set of 8 voltage values in micro-volt (uV) | ||
22 | units for buck4 when changing voltage using gpio dvs. Refer to [1] below | ||
23 | for additional information. | ||
24 | |||
25 | - s5m8767,pmic-buck-ds-gpios: GPIO specifiers for three host gpio's used | ||
26 | for selecting GPIO DVS lines. It is one-to-one mapped to dvs gpio lines. | ||
27 | |||
28 | [1] If none of the 's5m8767,pmic-buck[2/3/4]-uses-gpio-dvs' optional | ||
29 | property is specified, the 's5m8767,pmic-buck[2/3/4]-dvs-voltage' | ||
30 | property should specify atleast one voltage level (which would be a | ||
31 | safe operating voltage). | ||
32 | |||
33 | If either of the 's5m8767,pmic-buck[2/3/4]-uses-gpio-dvs' optional | ||
34 | property is specified, then all the eight voltage values for the | ||
35 | 's5m8767,pmic-buck[2/3/4]-dvs-voltage' should be specified. | ||
36 | |||
37 | Optional properties: | ||
38 | - interrupt-parent: Specifies the phandle of the interrupt controller to which | ||
39 | the interrupts from s5m8767 are delivered to. | ||
40 | - interrupts: Interrupt specifiers for two interrupt sources. | ||
41 | - First interrupt specifier is for 'irq1' interrupt. | ||
42 | - Second interrupt specifier is for 'alert' interrupt. | ||
43 | - s5m8767,pmic-buck2-uses-gpio-dvs: 'buck2' can be controlled by gpio dvs. | ||
44 | - s5m8767,pmic-buck3-uses-gpio-dvs: 'buck3' can be controlled by gpio dvs. | ||
45 | - s5m8767,pmic-buck4-uses-gpio-dvs: 'buck4' can be controlled by gpio dvs. | ||
46 | |||
47 | Additional properties required if either of the optional properties are used: | ||
48 | |||
49 | - s5m8767,pmic-buck234-default-dvs-idx: Default voltage setting selected from | ||
50 | the possible 8 options selectable by the dvs gpios. The value of this | ||
51 | property should be between 0 and 7. If not specified or if out of range, the | ||
52 | default value of this property is set to 0. | ||
53 | |||
54 | - s5m8767,pmic-buck-dvs-gpios: GPIO specifiers for three host gpio's used | ||
55 | for dvs. The format of the gpio specifier depends in the gpio controller. | ||
56 | |||
57 | Regulators: The regulators of s5m8767 that have to be instantiated should be | ||
58 | included in a sub-node named 'regulators'. Regulator nodes included in this | ||
59 | sub-node should be of the format as listed below. | ||
60 | |||
61 | regulator_name { | ||
62 | ldo1_reg: LDO1 { | ||
63 | regulator-name = "VDD_ALIVE_1.0V"; | ||
64 | regulator-min-microvolt = <1100000>; | ||
65 | regulator-max-microvolt = <1100000>; | ||
66 | regulator-always-on; | ||
67 | regulator-boot-on; | ||
68 | op_mode = <1>; /* Normal Mode */ | ||
69 | }; | ||
70 | }; | ||
71 | The above regulator entries are defined in regulator bindings documentation | ||
72 | except op_mode description. | ||
73 | - op_mode: describes the different operating modes of the LDO's with | ||
74 | power mode change in SOC. The different possible values are, | ||
75 | 0 - always off mode | ||
76 | 1 - on in normal mode | ||
77 | 2 - low power mode | ||
78 | 3 - suspend mode | ||
79 | |||
80 | The following are the names of the regulators that the s5m8767 pmic block | ||
81 | supports. Note: The 'n' in LDOn and BUCKn represents the LDO or BUCK number | ||
82 | as per the datasheet of s5m8767. | ||
83 | |||
84 | - LDOn | ||
85 | - valid values for n are 1 to 28 | ||
86 | - Example: LDO0, LD01, LDO28 | ||
87 | - BUCKn | ||
88 | - valid values for n are 1 to 9. | ||
89 | - Example: BUCK1, BUCK2, BUCK9 | ||
90 | |||
91 | The bindings inside the regulator nodes use the standard regulator bindings | ||
92 | which are documented elsewhere. | ||
93 | |||
94 | Example: | ||
95 | |||
96 | s5m8767_pmic@66 { | ||
97 | compatible = "samsung,s5m8767-pmic"; | ||
98 | reg = <0x66>; | ||
99 | |||
100 | s5m8767,pmic-buck2-uses-gpio-dvs; | ||
101 | s5m8767,pmic-buck3-uses-gpio-dvs; | ||
102 | s5m8767,pmic-buck4-uses-gpio-dvs; | ||
103 | |||
104 | s5m8767,pmic-buck-default-dvs-idx = <0>; | ||
105 | |||
106 | s5m8767,pmic-buck-dvs-gpios = <&gpx0 0 1 0 0>, /* DVS1 */ | ||
107 | <&gpx0 1 1 0 0>, /* DVS2 */ | ||
108 | <&gpx0 2 1 0 0>; /* DVS3 */ | ||
109 | |||
110 | s5m8767,pmic-buck-ds-gpios = <&gpx2 3 1 0 0>, /* SET1 */ | ||
111 | <&gpx2 4 1 0 0>, /* SET2 */ | ||
112 | <&gpx2 5 1 0 0>; /* SET3 */ | ||
113 | |||
114 | s5m8767,pmic-buck2-dvs-voltage = <1350000>, <1300000>, | ||
115 | <1250000>, <1200000>, | ||
116 | <1150000>, <1100000>, | ||
117 | <1000000>, <950000>; | ||
118 | |||
119 | s5m8767,pmic-buck3-dvs-voltage = <1100000>, <1100000>, | ||
120 | <1100000>, <1100000>, | ||
121 | <1000000>, <1000000>, | ||
122 | <1000000>, <1000000>; | ||
123 | |||
124 | s5m8767,pmic-buck4-dvs-voltage = <1200000>, <1200000>, | ||
125 | <1200000>, <1200000>, | ||
126 | <1200000>, <1200000>, | ||
127 | <1200000>, <1200000>; | ||
128 | |||
129 | regulators { | ||
130 | ldo1_reg: LDO1 { | ||
131 | regulator-name = "VDD_ABB_3.3V"; | ||
132 | regulator-min-microvolt = <3300000>; | ||
133 | regulator-max-microvolt = <3300000>; | ||
134 | op_mode = <1>; /* Normal Mode */ | ||
135 | }; | ||
136 | |||
137 | ldo2_reg: LDO2 { | ||
138 | regulator-name = "VDD_ALIVE_1.1V"; | ||
139 | regulator-min-microvolt = <1100000>; | ||
140 | regulator-max-microvolt = <1100000>; | ||
141 | regulator-always-on; | ||
142 | }; | ||
143 | |||
144 | buck1_reg: BUCK1 { | ||
145 | regulator-name = "VDD_MIF_1.2V"; | ||
146 | regulator-min-microvolt = <950000>; | ||
147 | regulator-max-microvolt = <1350000>; | ||
148 | regulator-always-on; | ||
149 | regulator-boot-on; | ||
150 | }; | ||
151 | }; | ||
152 | }; | ||
diff --git a/drivers/mfd/sec-core.c b/drivers/mfd/sec-core.c index 49d361a618d0..77ee26ef5941 100644 --- a/drivers/mfd/sec-core.c +++ b/drivers/mfd/sec-core.c | |||
@@ -17,6 +17,7 @@ | |||
17 | #include <linux/err.h> | 17 | #include <linux/err.h> |
18 | #include <linux/slab.h> | 18 | #include <linux/slab.h> |
19 | #include <linux/i2c.h> | 19 | #include <linux/i2c.h> |
20 | #include <linux/of_irq.h> | ||
20 | #include <linux/interrupt.h> | 21 | #include <linux/interrupt.h> |
21 | #include <linux/pm_runtime.h> | 22 | #include <linux/pm_runtime.h> |
22 | #include <linux/mutex.h> | 23 | #include <linux/mutex.h> |
@@ -60,6 +61,15 @@ static struct mfd_cell s2mps11_devs[] = { | |||
60 | }, | 61 | }, |
61 | }; | 62 | }; |
62 | 63 | ||
64 | #ifdef CONFIG_OF | ||
65 | static struct of_device_id sec_dt_match[] = { | ||
66 | { .compatible = "samsung,s5m8767-pmic", | ||
67 | .data = (void *)S5M8767X, | ||
68 | }, | ||
69 | {}, | ||
70 | }; | ||
71 | #endif | ||
72 | |||
63 | int sec_reg_read(struct sec_pmic_dev *sec_pmic, u8 reg, void *dest) | 73 | int sec_reg_read(struct sec_pmic_dev *sec_pmic, u8 reg, void *dest) |
64 | { | 74 | { |
65 | return regmap_read(sec_pmic->regmap, reg, dest); | 75 | return regmap_read(sec_pmic->regmap, reg, dest); |
@@ -95,6 +105,57 @@ static struct regmap_config sec_regmap_config = { | |||
95 | .val_bits = 8, | 105 | .val_bits = 8, |
96 | }; | 106 | }; |
97 | 107 | ||
108 | |||
109 | #ifdef CONFIG_OF | ||
110 | /* | ||
111 | * Only the common platform data elements for s5m8767 are parsed here from the | ||
112 | * device tree. Other sub-modules of s5m8767 such as pmic, rtc , charger and | ||
113 | * others have to parse their own platform data elements from device tree. | ||
114 | * | ||
115 | * The s5m8767 platform data structure is instantiated here and the drivers for | ||
116 | * the sub-modules need not instantiate another instance while parsing their | ||
117 | * platform data. | ||
118 | */ | ||
119 | static struct sec_platform_data *sec_pmic_i2c_parse_dt_pdata( | ||
120 | struct device *dev) | ||
121 | { | ||
122 | struct sec_platform_data *pd; | ||
123 | |||
124 | pd = devm_kzalloc(dev, sizeof(*pd), GFP_KERNEL); | ||
125 | if (!pd) { | ||
126 | dev_err(dev, "could not allocate memory for pdata\n"); | ||
127 | return ERR_PTR(-ENOMEM); | ||
128 | } | ||
129 | |||
130 | /* | ||
131 | * ToDo: the 'wakeup' member in the platform data is more of a linux | ||
132 | * specfic information. Hence, there is no binding for that yet and | ||
133 | * not parsed here. | ||
134 | */ | ||
135 | |||
136 | return pd; | ||
137 | } | ||
138 | #else | ||
139 | static struct sec_platform_data *sec_pmic_i2c_parse_dt_pdata( | ||
140 | struct device *dev) | ||
141 | { | ||
142 | return 0; | ||
143 | } | ||
144 | #endif | ||
145 | |||
146 | static inline int sec_i2c_get_driver_data(struct i2c_client *i2c, | ||
147 | const struct i2c_device_id *id) | ||
148 | { | ||
149 | #ifdef CONFIG_OF | ||
150 | if (i2c->dev.of_node) { | ||
151 | const struct of_device_id *match; | ||
152 | match = of_match_node(sec_dt_match, i2c->dev.of_node); | ||
153 | return (int)match->data; | ||
154 | } | ||
155 | #endif | ||
156 | return (int)id->driver_data; | ||
157 | } | ||
158 | |||
98 | static int sec_pmic_probe(struct i2c_client *i2c, | 159 | static int sec_pmic_probe(struct i2c_client *i2c, |
99 | const struct i2c_device_id *id) | 160 | const struct i2c_device_id *id) |
100 | { | 161 | { |
@@ -111,13 +172,22 @@ static int sec_pmic_probe(struct i2c_client *i2c, | |||
111 | sec_pmic->dev = &i2c->dev; | 172 | sec_pmic->dev = &i2c->dev; |
112 | sec_pmic->i2c = i2c; | 173 | sec_pmic->i2c = i2c; |
113 | sec_pmic->irq = i2c->irq; | 174 | sec_pmic->irq = i2c->irq; |
114 | sec_pmic->type = id->driver_data; | 175 | sec_pmic->type = sec_i2c_get_driver_data(i2c, id); |
115 | 176 | ||
177 | if (sec_pmic->dev->of_node) { | ||
178 | pdata = sec_pmic_i2c_parse_dt_pdata(sec_pmic->dev); | ||
179 | if (IS_ERR(pdata)) { | ||
180 | ret = PTR_ERR(pdata); | ||
181 | return ret; | ||
182 | } | ||
183 | pdata->device_type = sec_pmic->type; | ||
184 | } | ||
116 | if (pdata) { | 185 | if (pdata) { |
117 | sec_pmic->device_type = pdata->device_type; | 186 | sec_pmic->device_type = pdata->device_type; |
118 | sec_pmic->ono = pdata->ono; | 187 | sec_pmic->ono = pdata->ono; |
119 | sec_pmic->irq_base = pdata->irq_base; | 188 | sec_pmic->irq_base = pdata->irq_base; |
120 | sec_pmic->wakeup = pdata->wakeup; | 189 | sec_pmic->wakeup = pdata->wakeup; |
190 | sec_pmic->pdata = pdata; | ||
121 | } | 191 | } |
122 | 192 | ||
123 | sec_pmic->regmap = devm_regmap_init_i2c(i2c, &sec_regmap_config); | 193 | sec_pmic->regmap = devm_regmap_init_i2c(i2c, &sec_regmap_config); |
@@ -192,6 +262,7 @@ static struct i2c_driver sec_pmic_driver = { | |||
192 | .driver = { | 262 | .driver = { |
193 | .name = "sec_pmic", | 263 | .name = "sec_pmic", |
194 | .owner = THIS_MODULE, | 264 | .owner = THIS_MODULE, |
265 | .of_match_table = of_match_ptr(sec_dt_match), | ||
195 | }, | 266 | }, |
196 | .probe = sec_pmic_probe, | 267 | .probe = sec_pmic_probe, |
197 | .remove = sec_pmic_remove, | 268 | .remove = sec_pmic_remove, |
diff --git a/drivers/regulator/s5m8767.c b/drivers/regulator/s5m8767.c index 33b65c9ad5d5..8a831947c351 100644 --- a/drivers/regulator/s5m8767.c +++ b/drivers/regulator/s5m8767.c | |||
@@ -14,6 +14,7 @@ | |||
14 | #include <linux/bug.h> | 14 | #include <linux/bug.h> |
15 | #include <linux/err.h> | 15 | #include <linux/err.h> |
16 | #include <linux/gpio.h> | 16 | #include <linux/gpio.h> |
17 | #include <linux/of_gpio.h> | ||
17 | #include <linux/slab.h> | 18 | #include <linux/slab.h> |
18 | #include <linux/module.h> | 19 | #include <linux/module.h> |
19 | #include <linux/platform_device.h> | 20 | #include <linux/platform_device.h> |
@@ -21,6 +22,9 @@ | |||
21 | #include <linux/regulator/machine.h> | 22 | #include <linux/regulator/machine.h> |
22 | #include <linux/mfd/samsung/core.h> | 23 | #include <linux/mfd/samsung/core.h> |
23 | #include <linux/mfd/samsung/s5m8767.h> | 24 | #include <linux/mfd/samsung/s5m8767.h> |
25 | #include <linux/regulator/of_regulator.h> | ||
26 | |||
27 | #define S5M8767_OPMODE_NORMAL_MODE 0x1 | ||
24 | 28 | ||
25 | struct s5m8767_info { | 29 | struct s5m8767_info { |
26 | struct device *dev; | 30 | struct device *dev; |
@@ -255,10 +259,8 @@ static int s5m8767_reg_disable(struct regulator_dev *rdev) | |||
255 | return sec_reg_update(s5m8767->iodev, reg, ~mask, mask); | 259 | return sec_reg_update(s5m8767->iodev, reg, ~mask, mask); |
256 | } | 260 | } |
257 | 261 | ||
258 | static int s5m8767_get_voltage_register(struct regulator_dev *rdev, int *_reg) | 262 | static int s5m8767_get_vsel_reg(int reg_id, struct s5m8767_info *s5m8767) |
259 | { | 263 | { |
260 | struct s5m8767_info *s5m8767 = rdev_get_drvdata(rdev); | ||
261 | int reg_id = rdev_get_id(rdev); | ||
262 | int reg; | 264 | int reg; |
263 | 265 | ||
264 | switch (reg_id) { | 266 | switch (reg_id) { |
@@ -296,43 +298,18 @@ static int s5m8767_get_voltage_register(struct regulator_dev *rdev, int *_reg) | |||
296 | return -EINVAL; | 298 | return -EINVAL; |
297 | } | 299 | } |
298 | 300 | ||
299 | *_reg = reg; | 301 | return reg; |
300 | |||
301 | return 0; | ||
302 | } | ||
303 | |||
304 | static int s5m8767_get_voltage_sel(struct regulator_dev *rdev) | ||
305 | { | ||
306 | struct s5m8767_info *s5m8767 = rdev_get_drvdata(rdev); | ||
307 | int reg, mask, ret; | ||
308 | int reg_id = rdev_get_id(rdev); | ||
309 | unsigned int val; | ||
310 | |||
311 | ret = s5m8767_get_voltage_register(rdev, ®); | ||
312 | if (ret) | ||
313 | return ret; | ||
314 | |||
315 | mask = (reg_id < S5M8767_BUCK1) ? 0x3f : 0xff; | ||
316 | |||
317 | ret = sec_reg_read(s5m8767->iodev, reg, &val); | ||
318 | if (ret) | ||
319 | return ret; | ||
320 | |||
321 | val &= mask; | ||
322 | |||
323 | return val; | ||
324 | } | 302 | } |
325 | 303 | ||
326 | static int s5m8767_convert_voltage_to_sel( | 304 | static int s5m8767_convert_voltage_to_sel(const struct sec_voltage_desc *desc, |
327 | const struct sec_voltage_desc *desc, | 305 | int min_vol) |
328 | int min_vol, int max_vol) | ||
329 | { | 306 | { |
330 | int selector = 0; | 307 | int selector = 0; |
331 | 308 | ||
332 | if (desc == NULL) | 309 | if (desc == NULL) |
333 | return -EINVAL; | 310 | return -EINVAL; |
334 | 311 | ||
335 | if (max_vol < desc->min || min_vol > desc->max) | 312 | if (min_vol > desc->max) |
336 | return -EINVAL; | 313 | return -EINVAL; |
337 | 314 | ||
338 | if (min_vol < desc->min) | 315 | if (min_vol < desc->min) |
@@ -340,7 +317,7 @@ static int s5m8767_convert_voltage_to_sel( | |||
340 | 317 | ||
341 | selector = DIV_ROUND_UP(min_vol - desc->min, desc->step); | 318 | selector = DIV_ROUND_UP(min_vol - desc->min, desc->step); |
342 | 319 | ||
343 | if (desc->min + desc->step * selector > max_vol) | 320 | if (desc->min + desc->step * selector > desc->max) |
344 | return -EINVAL; | 321 | return -EINVAL; |
345 | 322 | ||
346 | return selector; | 323 | return selector; |
@@ -373,15 +350,13 @@ static int s5m8767_set_voltage_sel(struct regulator_dev *rdev, | |||
373 | { | 350 | { |
374 | struct s5m8767_info *s5m8767 = rdev_get_drvdata(rdev); | 351 | struct s5m8767_info *s5m8767 = rdev_get_drvdata(rdev); |
375 | int reg_id = rdev_get_id(rdev); | 352 | int reg_id = rdev_get_id(rdev); |
376 | int reg, mask, ret = 0, old_index, index = 0; | 353 | int old_index, index = 0; |
377 | u8 *buck234_vol = NULL; | 354 | u8 *buck234_vol = NULL; |
378 | 355 | ||
379 | switch (reg_id) { | 356 | switch (reg_id) { |
380 | case S5M8767_LDO1 ... S5M8767_LDO28: | 357 | case S5M8767_LDO1 ... S5M8767_LDO28: |
381 | mask = 0x3f; | ||
382 | break; | 358 | break; |
383 | case S5M8767_BUCK1 ... S5M8767_BUCK6: | 359 | case S5M8767_BUCK1 ... S5M8767_BUCK6: |
384 | mask = 0xff; | ||
385 | if (reg_id == S5M8767_BUCK2 && s5m8767->buck2_gpiodvs) | 360 | if (reg_id == S5M8767_BUCK2 && s5m8767->buck2_gpiodvs) |
386 | buck234_vol = &s5m8767->buck2_vol[0]; | 361 | buck234_vol = &s5m8767->buck2_vol[0]; |
387 | else if (reg_id == S5M8767_BUCK3 && s5m8767->buck3_gpiodvs) | 362 | else if (reg_id == S5M8767_BUCK3 && s5m8767->buck3_gpiodvs) |
@@ -392,7 +367,6 @@ static int s5m8767_set_voltage_sel(struct regulator_dev *rdev, | |||
392 | case S5M8767_BUCK7 ... S5M8767_BUCK8: | 367 | case S5M8767_BUCK7 ... S5M8767_BUCK8: |
393 | return -EINVAL; | 368 | return -EINVAL; |
394 | case S5M8767_BUCK9: | 369 | case S5M8767_BUCK9: |
395 | mask = 0xff; | ||
396 | break; | 370 | break; |
397 | default: | 371 | default: |
398 | return -EINVAL; | 372 | return -EINVAL; |
@@ -412,11 +386,7 @@ static int s5m8767_set_voltage_sel(struct regulator_dev *rdev, | |||
412 | else | 386 | else |
413 | return s5m8767_set_low(s5m8767); | 387 | return s5m8767_set_low(s5m8767); |
414 | } else { | 388 | } else { |
415 | ret = s5m8767_get_voltage_register(rdev, ®); | 389 | return regulator_set_voltage_sel_regmap(rdev, selector); |
416 | if (ret) | ||
417 | return ret; | ||
418 | |||
419 | return sec_reg_update(s5m8767->iodev, reg, selector, mask); | ||
420 | } | 390 | } |
421 | } | 391 | } |
422 | 392 | ||
@@ -441,7 +411,7 @@ static struct regulator_ops s5m8767_ops = { | |||
441 | .is_enabled = s5m8767_reg_is_enabled, | 411 | .is_enabled = s5m8767_reg_is_enabled, |
442 | .enable = s5m8767_reg_enable, | 412 | .enable = s5m8767_reg_enable, |
443 | .disable = s5m8767_reg_disable, | 413 | .disable = s5m8767_reg_disable, |
444 | .get_voltage_sel = s5m8767_get_voltage_sel, | 414 | .get_voltage_sel = regulator_get_voltage_sel_regmap, |
445 | .set_voltage_sel = s5m8767_set_voltage_sel, | 415 | .set_voltage_sel = s5m8767_set_voltage_sel, |
446 | .set_voltage_time_sel = s5m8767_set_voltage_time_sel, | 416 | .set_voltage_time_sel = s5m8767_set_voltage_time_sel, |
447 | }; | 417 | }; |
@@ -508,10 +478,182 @@ static struct regulator_desc regulators[] = { | |||
508 | s5m8767_regulator_desc(BUCK9), | 478 | s5m8767_regulator_desc(BUCK9), |
509 | }; | 479 | }; |
510 | 480 | ||
481 | #ifdef CONFIG_OF | ||
482 | static int s5m8767_pmic_dt_parse_dvs_gpio(struct sec_pmic_dev *iodev, | ||
483 | struct sec_platform_data *pdata, | ||
484 | struct device_node *pmic_np) | ||
485 | { | ||
486 | int i, gpio; | ||
487 | |||
488 | for (i = 0; i < 3; i++) { | ||
489 | gpio = of_get_named_gpio(pmic_np, | ||
490 | "s5m8767,pmic-buck-dvs-gpios", i); | ||
491 | if (!gpio_is_valid(gpio)) { | ||
492 | dev_err(iodev->dev, "invalid gpio[%d]: %d\n", i, gpio); | ||
493 | return -EINVAL; | ||
494 | } | ||
495 | pdata->buck_gpios[i] = gpio; | ||
496 | } | ||
497 | return 0; | ||
498 | } | ||
499 | |||
500 | static int s5m8767_pmic_dt_parse_ds_gpio(struct sec_pmic_dev *iodev, | ||
501 | struct sec_platform_data *pdata, | ||
502 | struct device_node *pmic_np) | ||
503 | { | ||
504 | int i, gpio; | ||
505 | |||
506 | for (i = 0; i < 3; i++) { | ||
507 | gpio = of_get_named_gpio(pmic_np, | ||
508 | "s5m8767,pmic-buck-ds-gpios", i); | ||
509 | if (!gpio_is_valid(gpio)) { | ||
510 | dev_err(iodev->dev, "invalid gpio[%d]: %d\n", i, gpio); | ||
511 | return -EINVAL; | ||
512 | } | ||
513 | pdata->buck_ds[i] = gpio; | ||
514 | } | ||
515 | return 0; | ||
516 | } | ||
517 | |||
518 | static int s5m8767_pmic_dt_parse_pdata(struct platform_device *pdev, | ||
519 | struct sec_platform_data *pdata) | ||
520 | { | ||
521 | struct sec_pmic_dev *iodev = dev_get_drvdata(pdev->dev.parent); | ||
522 | struct device_node *pmic_np, *regulators_np, *reg_np; | ||
523 | struct sec_regulator_data *rdata; | ||
524 | struct sec_opmode_data *rmode; | ||
525 | unsigned int i, dvs_voltage_nr = 1, ret; | ||
526 | |||
527 | pmic_np = iodev->dev->of_node; | ||
528 | if (!pmic_np) { | ||
529 | dev_err(iodev->dev, "could not find pmic sub-node\n"); | ||
530 | return -ENODEV; | ||
531 | } | ||
532 | |||
533 | regulators_np = of_find_node_by_name(pmic_np, "regulators"); | ||
534 | if (!regulators_np) { | ||
535 | dev_err(iodev->dev, "could not find regulators sub-node\n"); | ||
536 | return -EINVAL; | ||
537 | } | ||
538 | |||
539 | /* count the number of regulators to be supported in pmic */ | ||
540 | pdata->num_regulators = of_get_child_count(regulators_np); | ||
541 | |||
542 | rdata = devm_kzalloc(&pdev->dev, sizeof(*rdata) * | ||
543 | pdata->num_regulators, GFP_KERNEL); | ||
544 | if (!rdata) { | ||
545 | dev_err(iodev->dev, | ||
546 | "could not allocate memory for regulator data\n"); | ||
547 | return -ENOMEM; | ||
548 | } | ||
549 | |||
550 | rmode = devm_kzalloc(&pdev->dev, sizeof(*rmode) * | ||
551 | pdata->num_regulators, GFP_KERNEL); | ||
552 | if (!rdata) { | ||
553 | dev_err(iodev->dev, | ||
554 | "could not allocate memory for regulator mode\n"); | ||
555 | return -ENOMEM; | ||
556 | } | ||
557 | |||
558 | pdata->regulators = rdata; | ||
559 | pdata->opmode = rmode; | ||
560 | for_each_child_of_node(regulators_np, reg_np) { | ||
561 | for (i = 0; i < ARRAY_SIZE(regulators); i++) | ||
562 | if (!of_node_cmp(reg_np->name, regulators[i].name)) | ||
563 | break; | ||
564 | |||
565 | if (i == ARRAY_SIZE(regulators)) { | ||
566 | dev_warn(iodev->dev, | ||
567 | "don't know how to configure regulator %s\n", | ||
568 | reg_np->name); | ||
569 | continue; | ||
570 | } | ||
571 | |||
572 | rdata->id = i; | ||
573 | rdata->initdata = of_get_regulator_init_data( | ||
574 | &pdev->dev, reg_np); | ||
575 | rdata->reg_node = reg_np; | ||
576 | rdata++; | ||
577 | rmode->id = i; | ||
578 | if (of_property_read_u32(reg_np, "op_mode", | ||
579 | &rmode->mode)) { | ||
580 | dev_warn(iodev->dev, | ||
581 | "no op_mode property property at %s\n", | ||
582 | reg_np->full_name); | ||
583 | |||
584 | rmode->mode = S5M8767_OPMODE_NORMAL_MODE; | ||
585 | } | ||
586 | rmode++; | ||
587 | } | ||
588 | |||
589 | if (of_get_property(pmic_np, "s5m8767,pmic-buck2-uses-gpio-dvs", NULL)) | ||
590 | pdata->buck2_gpiodvs = true; | ||
591 | |||
592 | if (of_get_property(pmic_np, "s5m8767,pmic-buck3-uses-gpio-dvs", NULL)) | ||
593 | pdata->buck3_gpiodvs = true; | ||
594 | |||
595 | if (of_get_property(pmic_np, "s5m8767,pmic-buck4-uses-gpio-dvs", NULL)) | ||
596 | pdata->buck4_gpiodvs = true; | ||
597 | |||
598 | if (pdata->buck2_gpiodvs || pdata->buck3_gpiodvs || | ||
599 | pdata->buck4_gpiodvs) { | ||
600 | ret = s5m8767_pmic_dt_parse_dvs_gpio(iodev, pdata, pmic_np); | ||
601 | if (ret) | ||
602 | return -EINVAL; | ||
603 | |||
604 | if (of_property_read_u32(pmic_np, | ||
605 | "s5m8767,pmic-buck-default-dvs-idx", | ||
606 | &pdata->buck_default_idx)) { | ||
607 | pdata->buck_default_idx = 0; | ||
608 | } else { | ||
609 | if (pdata->buck_default_idx >= 8) { | ||
610 | pdata->buck_default_idx = 0; | ||
611 | dev_info(iodev->dev, | ||
612 | "invalid value for default dvs index, use 0\n"); | ||
613 | } | ||
614 | } | ||
615 | dvs_voltage_nr = 8; | ||
616 | } | ||
617 | |||
618 | ret = s5m8767_pmic_dt_parse_ds_gpio(iodev, pdata, pmic_np); | ||
619 | if (ret) | ||
620 | return -EINVAL; | ||
621 | |||
622 | if (of_property_read_u32_array(pmic_np, | ||
623 | "s5m8767,pmic-buck2-dvs-voltage", | ||
624 | pdata->buck2_voltage, dvs_voltage_nr)) { | ||
625 | dev_err(iodev->dev, "buck2 voltages not specified\n"); | ||
626 | return -EINVAL; | ||
627 | } | ||
628 | |||
629 | if (of_property_read_u32_array(pmic_np, | ||
630 | "s5m8767,pmic-buck3-dvs-voltage", | ||
631 | pdata->buck3_voltage, dvs_voltage_nr)) { | ||
632 | dev_err(iodev->dev, "buck3 voltages not specified\n"); | ||
633 | return -EINVAL; | ||
634 | } | ||
635 | |||
636 | if (of_property_read_u32_array(pmic_np, | ||
637 | "s5m8767,pmic-buck4-dvs-voltage", | ||
638 | pdata->buck4_voltage, dvs_voltage_nr)) { | ||
639 | dev_err(iodev->dev, "buck4 voltages not specified\n"); | ||
640 | return -EINVAL; | ||
641 | } | ||
642 | |||
643 | return 0; | ||
644 | } | ||
645 | #else | ||
646 | static int s5m8767_pmic_dt_parse_pdata(struct platform_device *pdev, | ||
647 | struct sec_platform_data *pdata) | ||
648 | { | ||
649 | return 0; | ||
650 | } | ||
651 | #endif /* CONFIG_OF */ | ||
652 | |||
511 | static int s5m8767_pmic_probe(struct platform_device *pdev) | 653 | static int s5m8767_pmic_probe(struct platform_device *pdev) |
512 | { | 654 | { |
513 | struct sec_pmic_dev *iodev = dev_get_drvdata(pdev->dev.parent); | 655 | struct sec_pmic_dev *iodev = dev_get_drvdata(pdev->dev.parent); |
514 | struct sec_platform_data *pdata = dev_get_platdata(iodev->dev); | 656 | struct sec_platform_data *pdata = iodev->pdata; |
515 | struct regulator_config config = { }; | 657 | struct regulator_config config = { }; |
516 | struct regulator_dev **rdev; | 658 | struct regulator_dev **rdev; |
517 | struct s5m8767_info *s5m8767; | 659 | struct s5m8767_info *s5m8767; |
@@ -522,6 +664,12 @@ static int s5m8767_pmic_probe(struct platform_device *pdev) | |||
522 | return -ENODEV; | 664 | return -ENODEV; |
523 | } | 665 | } |
524 | 666 | ||
667 | if (iodev->dev->of_node) { | ||
668 | ret = s5m8767_pmic_dt_parse_pdata(pdev, pdata); | ||
669 | if (ret) | ||
670 | return ret; | ||
671 | } | ||
672 | |||
525 | if (pdata->buck2_gpiodvs) { | 673 | if (pdata->buck2_gpiodvs) { |
526 | if (pdata->buck3_gpiodvs || pdata->buck4_gpiodvs) { | 674 | if (pdata->buck3_gpiodvs || pdata->buck4_gpiodvs) { |
527 | dev_err(&pdev->dev, "S5M8767 GPIO DVS NOT VALID\n"); | 675 | dev_err(&pdev->dev, "S5M8767 GPIO DVS NOT VALID\n"); |
@@ -577,23 +725,17 @@ static int s5m8767_pmic_probe(struct platform_device *pdev) | |||
577 | s5m8767->opmode = pdata->opmode; | 725 | s5m8767->opmode = pdata->opmode; |
578 | 726 | ||
579 | buck_init = s5m8767_convert_voltage_to_sel(&buck_voltage_val2, | 727 | buck_init = s5m8767_convert_voltage_to_sel(&buck_voltage_val2, |
580 | pdata->buck2_init, | 728 | pdata->buck2_init); |
581 | pdata->buck2_init + | ||
582 | buck_voltage_val2.step); | ||
583 | 729 | ||
584 | sec_reg_write(s5m8767->iodev, S5M8767_REG_BUCK2DVS2, buck_init); | 730 | sec_reg_write(s5m8767->iodev, S5M8767_REG_BUCK2DVS2, buck_init); |
585 | 731 | ||
586 | buck_init = s5m8767_convert_voltage_to_sel(&buck_voltage_val2, | 732 | buck_init = s5m8767_convert_voltage_to_sel(&buck_voltage_val2, |
587 | pdata->buck3_init, | 733 | pdata->buck3_init); |
588 | pdata->buck3_init + | ||
589 | buck_voltage_val2.step); | ||
590 | 734 | ||
591 | sec_reg_write(s5m8767->iodev, S5M8767_REG_BUCK3DVS2, buck_init); | 735 | sec_reg_write(s5m8767->iodev, S5M8767_REG_BUCK3DVS2, buck_init); |
592 | 736 | ||
593 | buck_init = s5m8767_convert_voltage_to_sel(&buck_voltage_val2, | 737 | buck_init = s5m8767_convert_voltage_to_sel(&buck_voltage_val2, |
594 | pdata->buck4_init, | 738 | pdata->buck4_init); |
595 | pdata->buck4_init + | ||
596 | buck_voltage_val2.step); | ||
597 | 739 | ||
598 | sec_reg_write(s5m8767->iodev, S5M8767_REG_BUCK4DVS2, buck_init); | 740 | sec_reg_write(s5m8767->iodev, S5M8767_REG_BUCK4DVS2, buck_init); |
599 | 741 | ||
@@ -602,27 +744,21 @@ static int s5m8767_pmic_probe(struct platform_device *pdev) | |||
602 | s5m8767->buck2_vol[i] = | 744 | s5m8767->buck2_vol[i] = |
603 | s5m8767_convert_voltage_to_sel( | 745 | s5m8767_convert_voltage_to_sel( |
604 | &buck_voltage_val2, | 746 | &buck_voltage_val2, |
605 | pdata->buck2_voltage[i], | 747 | pdata->buck2_voltage[i]); |
606 | pdata->buck2_voltage[i] + | ||
607 | buck_voltage_val2.step); | ||
608 | } | 748 | } |
609 | 749 | ||
610 | if (s5m8767->buck3_gpiodvs) { | 750 | if (s5m8767->buck3_gpiodvs) { |
611 | s5m8767->buck3_vol[i] = | 751 | s5m8767->buck3_vol[i] = |
612 | s5m8767_convert_voltage_to_sel( | 752 | s5m8767_convert_voltage_to_sel( |
613 | &buck_voltage_val2, | 753 | &buck_voltage_val2, |
614 | pdata->buck3_voltage[i], | 754 | pdata->buck3_voltage[i]); |
615 | pdata->buck3_voltage[i] + | ||
616 | buck_voltage_val2.step); | ||
617 | } | 755 | } |
618 | 756 | ||
619 | if (s5m8767->buck4_gpiodvs) { | 757 | if (s5m8767->buck4_gpiodvs) { |
620 | s5m8767->buck4_vol[i] = | 758 | s5m8767->buck4_vol[i] = |
621 | s5m8767_convert_voltage_to_sel( | 759 | s5m8767_convert_voltage_to_sel( |
622 | &buck_voltage_val2, | 760 | &buck_voltage_val2, |
623 | pdata->buck4_voltage[i], | 761 | pdata->buck4_voltage[i]); |
624 | pdata->buck4_voltage[i] + | ||
625 | buck_voltage_val2.step); | ||
626 | } | 762 | } |
627 | } | 763 | } |
628 | 764 | ||
@@ -760,11 +896,19 @@ static int s5m8767_pmic_probe(struct platform_device *pdev) | |||
760 | (desc->max - desc->min) / desc->step + 1; | 896 | (desc->max - desc->min) / desc->step + 1; |
761 | regulators[id].min_uV = desc->min; | 897 | regulators[id].min_uV = desc->min; |
762 | regulators[id].uV_step = desc->step; | 898 | regulators[id].uV_step = desc->step; |
899 | regulators[id].vsel_reg = | ||
900 | s5m8767_get_vsel_reg(id, s5m8767); | ||
901 | if (id < S5M8767_BUCK1) | ||
902 | regulators[id].vsel_mask = 0x3f; | ||
903 | else | ||
904 | regulators[id].vsel_mask = 0xff; | ||
763 | } | 905 | } |
764 | 906 | ||
765 | config.dev = s5m8767->dev; | 907 | config.dev = s5m8767->dev; |
766 | config.init_data = pdata->regulators[i].initdata; | 908 | config.init_data = pdata->regulators[i].initdata; |
767 | config.driver_data = s5m8767; | 909 | config.driver_data = s5m8767; |
910 | config.regmap = iodev->regmap; | ||
911 | config.of_node = pdata->regulators[i].reg_node; | ||
768 | 912 | ||
769 | rdev[i] = regulator_register(®ulators[id], &config); | 913 | rdev[i] = regulator_register(®ulators[id], &config); |
770 | if (IS_ERR(rdev[i])) { | 914 | if (IS_ERR(rdev[i])) { |
diff --git a/include/linux/mfd/samsung/core.h b/include/linux/mfd/samsung/core.h index b50c38f8bc48..f0f4de3b4ccc 100644 --- a/include/linux/mfd/samsung/core.h +++ b/include/linux/mfd/samsung/core.h | |||
@@ -26,6 +26,7 @@ enum sec_device_type { | |||
26 | /** | 26 | /** |
27 | * struct sec_pmic_dev - s5m87xx master device for sub-drivers | 27 | * struct sec_pmic_dev - s5m87xx master device for sub-drivers |
28 | * @dev: master device of the chip (can be used to access platform data) | 28 | * @dev: master device of the chip (can be used to access platform data) |
29 | * @pdata: pointer to private data used to pass platform data to child | ||
29 | * @i2c: i2c client private data for regulator | 30 | * @i2c: i2c client private data for regulator |
30 | * @rtc: i2c client private data for rtc | 31 | * @rtc: i2c client private data for rtc |
31 | * @iolock: mutex for serializing io access | 32 | * @iolock: mutex for serializing io access |
@@ -39,6 +40,7 @@ enum sec_device_type { | |||
39 | */ | 40 | */ |
40 | struct sec_pmic_dev { | 41 | struct sec_pmic_dev { |
41 | struct device *dev; | 42 | struct device *dev; |
43 | struct sec_platform_data *pdata; | ||
42 | struct regmap *regmap; | 44 | struct regmap *regmap; |
43 | struct i2c_client *i2c; | 45 | struct i2c_client *i2c; |
44 | struct i2c_client *rtc; | 46 | struct i2c_client *rtc; |
@@ -82,11 +84,11 @@ struct sec_platform_data { | |||
82 | 84 | ||
83 | int buck_gpios[3]; | 85 | int buck_gpios[3]; |
84 | int buck_ds[3]; | 86 | int buck_ds[3]; |
85 | int buck2_voltage[8]; | 87 | unsigned int buck2_voltage[8]; |
86 | bool buck2_gpiodvs; | 88 | bool buck2_gpiodvs; |
87 | int buck3_voltage[8]; | 89 | unsigned int buck3_voltage[8]; |
88 | bool buck3_gpiodvs; | 90 | bool buck3_gpiodvs; |
89 | int buck4_voltage[8]; | 91 | unsigned int buck4_voltage[8]; |
90 | bool buck4_gpiodvs; | 92 | bool buck4_gpiodvs; |
91 | 93 | ||
92 | int buck_set1; | 94 | int buck_set1; |
@@ -127,6 +129,7 @@ struct sec_platform_data { | |||
127 | struct sec_regulator_data { | 129 | struct sec_regulator_data { |
128 | int id; | 130 | int id; |
129 | struct regulator_init_data *initdata; | 131 | struct regulator_init_data *initdata; |
132 | struct device_node *reg_node; | ||
130 | }; | 133 | }; |
131 | 134 | ||
132 | /* | 135 | /* |
@@ -136,7 +139,7 @@ struct sec_regulator_data { | |||
136 | */ | 139 | */ |
137 | struct sec_opmode_data { | 140 | struct sec_opmode_data { |
138 | int id; | 141 | int id; |
139 | int mode; | 142 | unsigned int mode; |
140 | }; | 143 | }; |
141 | 144 | ||
142 | /* | 145 | /* |