diff options
-rw-r--r-- | Documentation/devicetree/bindings/regulator/s5m8767-regulator.txt | 13 | ||||
-rw-r--r-- | Documentation/devicetree/bindings/regulator/ti-abb-regulator.txt | 6 | ||||
-rw-r--r-- | drivers/regulator/Kconfig | 6 | ||||
-rw-r--r-- | drivers/regulator/Makefile | 1 | ||||
-rw-r--r-- | drivers/regulator/s5m8767.c | 171 | ||||
-rw-r--r-- | drivers/regulator/st-pwm.c | 190 | ||||
-rw-r--r-- | drivers/regulator/ti-abb-regulator.c | 140 | ||||
-rw-r--r-- | drivers/regulator/tps51632-regulator.c | 8 | ||||
-rw-r--r-- | drivers/regulator/tps62360-regulator.c | 9 | ||||
-rw-r--r-- | drivers/regulator/tps6507x-regulator.c | 29 | ||||
-rw-r--r-- | drivers/regulator/tps65090-regulator.c | 13 | ||||
-rw-r--r-- | drivers/regulator/tps65217-regulator.c | 17 | ||||
-rw-r--r-- | include/linux/mfd/samsung/core.h | 3 | ||||
-rw-r--r-- | include/linux/mfd/samsung/s5m8767.h | 7 |
14 files changed, 426 insertions, 187 deletions
diff --git a/Documentation/devicetree/bindings/regulator/s5m8767-regulator.txt b/Documentation/devicetree/bindings/regulator/s5m8767-regulator.txt index fc6b38f035bd..d290988ed975 100644 --- a/Documentation/devicetree/bindings/regulator/s5m8767-regulator.txt +++ b/Documentation/devicetree/bindings/regulator/s5m8767-regulator.txt | |||
@@ -69,13 +69,16 @@ sub-node should be of the format as listed below. | |||
69 | }; | 69 | }; |
70 | }; | 70 | }; |
71 | The above regulator entries are defined in regulator bindings documentation | 71 | The above regulator entries are defined in regulator bindings documentation |
72 | except op_mode description. | 72 | except these properties: |
73 | - op_mode: describes the different operating modes of the LDO's with | 73 | - op_mode: describes the different operating modes of the LDO's with |
74 | power mode change in SOC. The different possible values are, | 74 | power mode change in SOC. The different possible values are, |
75 | 0 - always off mode | 75 | 0 - always off mode |
76 | 1 - on in normal mode | 76 | 1 - on in normal mode |
77 | 2 - low power mode | 77 | 2 - low power mode |
78 | 3 - suspend mode | 78 | 3 - suspend mode |
79 | - s5m8767,pmic-ext-control-gpios: (optional) GPIO specifier for one | ||
80 | GPIO controlling this regulator (enable/disable); This is | ||
81 | valid only for buck9. | ||
79 | 82 | ||
80 | The following are the names of the regulators that the s5m8767 pmic block | 83 | 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 | 84 | supports. Note: The 'n' in LDOn and BUCKn represents the LDO or BUCK number |
@@ -148,5 +151,13 @@ Example: | |||
148 | regulator-always-on; | 151 | regulator-always-on; |
149 | regulator-boot-on; | 152 | regulator-boot-on; |
150 | }; | 153 | }; |
154 | |||
155 | vemmc_reg: BUCK9 { | ||
156 | regulator-name = "VMEM_VDD_2.8V"; | ||
157 | regulator-min-microvolt = <2800000>; | ||
158 | regulator-max-microvolt = <2800000>; | ||
159 | op_mode = <3>; /* Standby Mode */ | ||
160 | s5m8767,pmic-ext-control-gpios = <&gpk0 2 0>; | ||
161 | }; | ||
151 | }; | 162 | }; |
152 | }; | 163 | }; |
diff --git a/Documentation/devicetree/bindings/regulator/ti-abb-regulator.txt b/Documentation/devicetree/bindings/regulator/ti-abb-regulator.txt index 2e57a33e9029..c58db75f959e 100644 --- a/Documentation/devicetree/bindings/regulator/ti-abb-regulator.txt +++ b/Documentation/devicetree/bindings/regulator/ti-abb-regulator.txt | |||
@@ -4,10 +4,14 @@ Required Properties: | |||
4 | - compatible: Should be one of: | 4 | - compatible: Should be one of: |
5 | - "ti,abb-v1" for older SoCs like OMAP3 | 5 | - "ti,abb-v1" for older SoCs like OMAP3 |
6 | - "ti,abb-v2" for newer SoCs like OMAP4, OMAP5 | 6 | - "ti,abb-v2" for newer SoCs like OMAP4, OMAP5 |
7 | - "ti,abb-v3" for a generic definition where setup and control registers are | ||
8 | provided (example: DRA7) | ||
7 | - reg: Address and length of the register set for the device. It contains | 9 | - reg: Address and length of the register set for the device. It contains |
8 | the information of registers in the same order as described by reg-names | 10 | the information of registers in the same order as described by reg-names |
9 | - reg-names: Should contain the reg names | 11 | - reg-names: Should contain the reg names |
10 | - "base-address" - contains base address of ABB module | 12 | - "base-address" - contains base address of ABB module (ti,abb-v1,ti,abb-v2) |
13 | - "control-address" - contains control register address of ABB module (ti,abb-v3) | ||
14 | - "setup-address" - contains setup register address of ABB module (ti,abb-v3) | ||
11 | - "int-address" - contains address of interrupt register for ABB module | 15 | - "int-address" - contains address of interrupt register for ABB module |
12 | (also see Optional properties) | 16 | (also see Optional properties) |
13 | - #address-cell: should be 0 | 17 | - #address-cell: should be 0 |
diff --git a/drivers/regulator/Kconfig b/drivers/regulator/Kconfig index e5e4017b1011..8f3866c44a3f 100644 --- a/drivers/regulator/Kconfig +++ b/drivers/regulator/Kconfig | |||
@@ -448,6 +448,12 @@ config REGULATOR_S5M8767 | |||
448 | via I2C bus. S5M8767A have 9 Bucks and 28 LDOs output and | 448 | via I2C bus. S5M8767A have 9 Bucks and 28 LDOs output and |
449 | supports DVS mode with 8bits of output voltage control. | 449 | supports DVS mode with 8bits of output voltage control. |
450 | 450 | ||
451 | config REGULATOR_ST_PWM | ||
452 | tristate "STMicroelectronics PWM voltage regulator" | ||
453 | depends on ARCH_STI | ||
454 | help | ||
455 | This driver supports ST's PWM controlled voltage regulators. | ||
456 | |||
451 | config REGULATOR_TI_ABB | 457 | config REGULATOR_TI_ABB |
452 | tristate "TI Adaptive Body Bias on-chip LDO" | 458 | tristate "TI Adaptive Body Bias on-chip LDO" |
453 | depends on ARCH_OMAP | 459 | depends on ARCH_OMAP |
diff --git a/drivers/regulator/Makefile b/drivers/regulator/Makefile index c3416728c14d..0cfca37941ec 100644 --- a/drivers/regulator/Makefile +++ b/drivers/regulator/Makefile | |||
@@ -61,6 +61,7 @@ obj-$(CONFIG_REGULATOR_RC5T583) += rc5t583-regulator.o | |||
61 | obj-$(CONFIG_REGULATOR_S2MPA01) += s2mpa01.o | 61 | obj-$(CONFIG_REGULATOR_S2MPA01) += s2mpa01.o |
62 | obj-$(CONFIG_REGULATOR_S2MPS11) += s2mps11.o | 62 | obj-$(CONFIG_REGULATOR_S2MPS11) += s2mps11.o |
63 | obj-$(CONFIG_REGULATOR_S5M8767) += s5m8767.o | 63 | obj-$(CONFIG_REGULATOR_S5M8767) += s5m8767.o |
64 | obj-$(CONFIG_REGULATOR_ST_PWM) += st-pwm.o | ||
64 | obj-$(CONFIG_REGULATOR_STW481X_VMMC) += stw481x-vmmc.o | 65 | obj-$(CONFIG_REGULATOR_STW481X_VMMC) += stw481x-vmmc.o |
65 | obj-$(CONFIG_REGULATOR_TI_ABB) += ti-abb-regulator.o | 66 | obj-$(CONFIG_REGULATOR_TI_ABB) += ti-abb-regulator.o |
66 | obj-$(CONFIG_REGULATOR_TPS6105X) += tps6105x-regulator.o | 67 | obj-$(CONFIG_REGULATOR_TPS6105X) += tps6105x-regulator.o |
diff --git a/drivers/regulator/s5m8767.c b/drivers/regulator/s5m8767.c index d958dfa05125..f05badabd69e 100644 --- a/drivers/regulator/s5m8767.c +++ b/drivers/regulator/s5m8767.c | |||
@@ -11,11 +11,8 @@ | |||
11 | * | 11 | * |
12 | */ | 12 | */ |
13 | 13 | ||
14 | #include <linux/bug.h> | ||
15 | #include <linux/err.h> | 14 | #include <linux/err.h> |
16 | #include <linux/gpio.h> | ||
17 | #include <linux/of_gpio.h> | 15 | #include <linux/of_gpio.h> |
18 | #include <linux/slab.h> | ||
19 | #include <linux/module.h> | 16 | #include <linux/module.h> |
20 | #include <linux/platform_device.h> | 17 | #include <linux/platform_device.h> |
21 | #include <linux/regulator/driver.h> | 18 | #include <linux/regulator/driver.h> |
@@ -170,12 +167,11 @@ static unsigned int s5m8767_opmode_reg[][4] = { | |||
170 | {0x0, 0x3, 0x1, 0x1}, /* BUCK9 */ | 167 | {0x0, 0x3, 0x1, 0x1}, /* BUCK9 */ |
171 | }; | 168 | }; |
172 | 169 | ||
173 | static int s5m8767_get_register(struct regulator_dev *rdev, int *reg, | 170 | static int s5m8767_get_register(struct s5m8767_info *s5m8767, int reg_id, |
174 | int *enable_ctrl) | 171 | int *reg, int *enable_ctrl) |
175 | { | 172 | { |
176 | int i, reg_id = rdev_get_id(rdev); | 173 | int i; |
177 | unsigned int mode; | 174 | unsigned int mode; |
178 | struct s5m8767_info *s5m8767 = rdev_get_drvdata(rdev); | ||
179 | 175 | ||
180 | switch (reg_id) { | 176 | switch (reg_id) { |
181 | case S5M8767_LDO1 ... S5M8767_LDO2: | 177 | case S5M8767_LDO1 ... S5M8767_LDO2: |
@@ -214,53 +210,6 @@ static int s5m8767_get_register(struct regulator_dev *rdev, int *reg, | |||
214 | return 0; | 210 | return 0; |
215 | } | 211 | } |
216 | 212 | ||
217 | static int s5m8767_reg_is_enabled(struct regulator_dev *rdev) | ||
218 | { | ||
219 | struct s5m8767_info *s5m8767 = rdev_get_drvdata(rdev); | ||
220 | int ret, reg; | ||
221 | int enable_ctrl; | ||
222 | unsigned int val; | ||
223 | |||
224 | ret = s5m8767_get_register(rdev, ®, &enable_ctrl); | ||
225 | if (ret == -EINVAL) | ||
226 | return 1; | ||
227 | else if (ret) | ||
228 | return ret; | ||
229 | |||
230 | ret = regmap_read(s5m8767->iodev->regmap_pmic, reg, &val); | ||
231 | if (ret) | ||
232 | return ret; | ||
233 | |||
234 | return (val & S5M8767_ENCTRL_MASK) == enable_ctrl; | ||
235 | } | ||
236 | |||
237 | static int s5m8767_reg_enable(struct regulator_dev *rdev) | ||
238 | { | ||
239 | struct s5m8767_info *s5m8767 = rdev_get_drvdata(rdev); | ||
240 | int ret, reg; | ||
241 | int enable_ctrl; | ||
242 | |||
243 | ret = s5m8767_get_register(rdev, ®, &enable_ctrl); | ||
244 | if (ret) | ||
245 | return ret; | ||
246 | |||
247 | return regmap_update_bits(s5m8767->iodev->regmap_pmic, reg, | ||
248 | S5M8767_ENCTRL_MASK, enable_ctrl); | ||
249 | } | ||
250 | |||
251 | static int s5m8767_reg_disable(struct regulator_dev *rdev) | ||
252 | { | ||
253 | struct s5m8767_info *s5m8767 = rdev_get_drvdata(rdev); | ||
254 | int ret, reg, enable_ctrl; | ||
255 | |||
256 | ret = s5m8767_get_register(rdev, ®, &enable_ctrl); | ||
257 | if (ret) | ||
258 | return ret; | ||
259 | |||
260 | return regmap_update_bits(s5m8767->iodev->regmap_pmic, reg, | ||
261 | S5M8767_ENCTRL_MASK, ~S5M8767_ENCTRL_MASK); | ||
262 | } | ||
263 | |||
264 | static int s5m8767_get_vsel_reg(int reg_id, struct s5m8767_info *s5m8767) | 213 | static int s5m8767_get_vsel_reg(int reg_id, struct s5m8767_info *s5m8767) |
265 | { | 214 | { |
266 | int reg; | 215 | int reg; |
@@ -410,9 +359,9 @@ static int s5m8767_set_voltage_time_sel(struct regulator_dev *rdev, | |||
410 | 359 | ||
411 | static struct regulator_ops s5m8767_ops = { | 360 | static struct regulator_ops s5m8767_ops = { |
412 | .list_voltage = regulator_list_voltage_linear, | 361 | .list_voltage = regulator_list_voltage_linear, |
413 | .is_enabled = s5m8767_reg_is_enabled, | 362 | .is_enabled = regulator_is_enabled_regmap, |
414 | .enable = s5m8767_reg_enable, | 363 | .enable = regulator_enable_regmap, |
415 | .disable = s5m8767_reg_disable, | 364 | .disable = regulator_disable_regmap, |
416 | .get_voltage_sel = regulator_get_voltage_sel_regmap, | 365 | .get_voltage_sel = regulator_get_voltage_sel_regmap, |
417 | .set_voltage_sel = s5m8767_set_voltage_sel, | 366 | .set_voltage_sel = s5m8767_set_voltage_sel, |
418 | .set_voltage_time_sel = s5m8767_set_voltage_time_sel, | 367 | .set_voltage_time_sel = s5m8767_set_voltage_time_sel, |
@@ -420,9 +369,9 @@ static struct regulator_ops s5m8767_ops = { | |||
420 | 369 | ||
421 | static struct regulator_ops s5m8767_buck78_ops = { | 370 | static struct regulator_ops s5m8767_buck78_ops = { |
422 | .list_voltage = regulator_list_voltage_linear, | 371 | .list_voltage = regulator_list_voltage_linear, |
423 | .is_enabled = s5m8767_reg_is_enabled, | 372 | .is_enabled = regulator_is_enabled_regmap, |
424 | .enable = s5m8767_reg_enable, | 373 | .enable = regulator_enable_regmap, |
425 | .disable = s5m8767_reg_disable, | 374 | .disable = regulator_disable_regmap, |
426 | .get_voltage_sel = regulator_get_voltage_sel_regmap, | 375 | .get_voltage_sel = regulator_get_voltage_sel_regmap, |
427 | .set_voltage_sel = regulator_set_voltage_sel_regmap, | 376 | .set_voltage_sel = regulator_set_voltage_sel_regmap, |
428 | }; | 377 | }; |
@@ -483,6 +432,66 @@ static struct regulator_desc regulators[] = { | |||
483 | s5m8767_regulator_desc(BUCK9), | 432 | s5m8767_regulator_desc(BUCK9), |
484 | }; | 433 | }; |
485 | 434 | ||
435 | /* | ||
436 | * Enable GPIO control over BUCK9 in regulator_config for that regulator. | ||
437 | */ | ||
438 | static void s5m8767_regulator_config_ext_control(struct s5m8767_info *s5m8767, | ||
439 | struct sec_regulator_data *rdata, | ||
440 | struct regulator_config *config) | ||
441 | { | ||
442 | int i, mode = 0; | ||
443 | |||
444 | if (rdata->id != S5M8767_BUCK9) | ||
445 | return; | ||
446 | |||
447 | /* Check if opmode for regulator matches S5M8767_ENCTRL_USE_GPIO */ | ||
448 | for (i = 0; i < s5m8767->num_regulators; i++) { | ||
449 | const struct sec_opmode_data *opmode = &s5m8767->opmode[i]; | ||
450 | if (opmode->id == rdata->id) { | ||
451 | mode = s5m8767_opmode_reg[rdata->id][opmode->mode]; | ||
452 | break; | ||
453 | } | ||
454 | } | ||
455 | if (mode != S5M8767_ENCTRL_USE_GPIO) { | ||
456 | dev_warn(s5m8767->dev, | ||
457 | "ext-control for %s: mismatched op_mode (%x), ignoring\n", | ||
458 | rdata->reg_node->name, mode); | ||
459 | return; | ||
460 | } | ||
461 | |||
462 | if (!gpio_is_valid(rdata->ext_control_gpio)) { | ||
463 | dev_warn(s5m8767->dev, | ||
464 | "ext-control for %s: GPIO not valid, ignoring\n", | ||
465 | rdata->reg_node->name); | ||
466 | return; | ||
467 | } | ||
468 | |||
469 | config->ena_gpio = rdata->ext_control_gpio; | ||
470 | config->ena_gpio_flags = GPIOF_OUT_INIT_HIGH; | ||
471 | } | ||
472 | |||
473 | /* | ||
474 | * Turn on GPIO control over BUCK9. | ||
475 | */ | ||
476 | static int s5m8767_enable_ext_control(struct s5m8767_info *s5m8767, | ||
477 | struct regulator_dev *rdev) | ||
478 | { | ||
479 | int id = rdev_get_id(rdev); | ||
480 | int ret, reg, enable_ctrl; | ||
481 | |||
482 | if (id != S5M8767_BUCK9) | ||
483 | return -EINVAL; | ||
484 | |||
485 | ret = s5m8767_get_register(s5m8767, id, ®, &enable_ctrl); | ||
486 | if (ret) | ||
487 | return ret; | ||
488 | |||
489 | return regmap_update_bits(s5m8767->iodev->regmap_pmic, | ||
490 | reg, S5M8767_ENCTRL_MASK, | ||
491 | S5M8767_ENCTRL_USE_GPIO << S5M8767_ENCTRL_SHIFT); | ||
492 | } | ||
493 | |||
494 | |||
486 | #ifdef CONFIG_OF | 495 | #ifdef CONFIG_OF |
487 | static int s5m8767_pmic_dt_parse_dvs_gpio(struct sec_pmic_dev *iodev, | 496 | static int s5m8767_pmic_dt_parse_dvs_gpio(struct sec_pmic_dev *iodev, |
488 | struct sec_platform_data *pdata, | 497 | struct sec_platform_data *pdata, |
@@ -520,6 +529,16 @@ static int s5m8767_pmic_dt_parse_ds_gpio(struct sec_pmic_dev *iodev, | |||
520 | return 0; | 529 | return 0; |
521 | } | 530 | } |
522 | 531 | ||
532 | static void s5m8767_pmic_dt_parse_ext_control_gpio(struct sec_pmic_dev *iodev, | ||
533 | struct sec_regulator_data *rdata, | ||
534 | struct device_node *reg_np) | ||
535 | { | ||
536 | rdata->ext_control_gpio = of_get_named_gpio(reg_np, | ||
537 | "s5m8767,pmic-ext-control-gpios", 0); | ||
538 | if (!gpio_is_valid(rdata->ext_control_gpio)) | ||
539 | rdata->ext_control_gpio = 0; | ||
540 | } | ||
541 | |||
523 | static int s5m8767_pmic_dt_parse_pdata(struct platform_device *pdev, | 542 | static int s5m8767_pmic_dt_parse_pdata(struct platform_device *pdev, |
524 | struct sec_platform_data *pdata) | 543 | struct sec_platform_data *pdata) |
525 | { | 544 | { |
@@ -546,19 +565,13 @@ static int s5m8767_pmic_dt_parse_pdata(struct platform_device *pdev, | |||
546 | 565 | ||
547 | rdata = devm_kzalloc(&pdev->dev, sizeof(*rdata) * | 566 | rdata = devm_kzalloc(&pdev->dev, sizeof(*rdata) * |
548 | pdata->num_regulators, GFP_KERNEL); | 567 | pdata->num_regulators, GFP_KERNEL); |
549 | if (!rdata) { | 568 | if (!rdata) |
550 | dev_err(iodev->dev, | ||
551 | "could not allocate memory for regulator data\n"); | ||
552 | return -ENOMEM; | 569 | return -ENOMEM; |
553 | } | ||
554 | 570 | ||
555 | rmode = devm_kzalloc(&pdev->dev, sizeof(*rmode) * | 571 | rmode = devm_kzalloc(&pdev->dev, sizeof(*rmode) * |
556 | pdata->num_regulators, GFP_KERNEL); | 572 | pdata->num_regulators, GFP_KERNEL); |
557 | if (!rmode) { | 573 | if (!rmode) |
558 | dev_err(iodev->dev, | ||
559 | "could not allocate memory for regulator mode\n"); | ||
560 | return -ENOMEM; | 574 | return -ENOMEM; |
561 | } | ||
562 | 575 | ||
563 | pdata->regulators = rdata; | 576 | pdata->regulators = rdata; |
564 | pdata->opmode = rmode; | 577 | pdata->opmode = rmode; |
@@ -574,6 +587,8 @@ static int s5m8767_pmic_dt_parse_pdata(struct platform_device *pdev, | |||
574 | continue; | 587 | continue; |
575 | } | 588 | } |
576 | 589 | ||
590 | s5m8767_pmic_dt_parse_ext_control_gpio(iodev, rdata, reg_np); | ||
591 | |||
577 | rdata->id = i; | 592 | rdata->id = i; |
578 | rdata->initdata = of_get_regulator_init_data( | 593 | rdata->initdata = of_get_regulator_init_data( |
579 | &pdev->dev, reg_np); | 594 | &pdev->dev, reg_np); |
@@ -922,6 +937,7 @@ static int s5m8767_pmic_probe(struct platform_device *pdev) | |||
922 | for (i = 0; i < pdata->num_regulators; i++) { | 937 | for (i = 0; i < pdata->num_regulators; i++) { |
923 | const struct sec_voltage_desc *desc; | 938 | const struct sec_voltage_desc *desc; |
924 | int id = pdata->regulators[i].id; | 939 | int id = pdata->regulators[i].id; |
940 | int enable_reg, enable_val; | ||
925 | 941 | ||
926 | desc = reg_voltage_map[id]; | 942 | desc = reg_voltage_map[id]; |
927 | if (desc) { | 943 | if (desc) { |
@@ -935,6 +951,12 @@ static int s5m8767_pmic_probe(struct platform_device *pdev) | |||
935 | regulators[id].vsel_mask = 0x3f; | 951 | regulators[id].vsel_mask = 0x3f; |
936 | else | 952 | else |
937 | regulators[id].vsel_mask = 0xff; | 953 | regulators[id].vsel_mask = 0xff; |
954 | |||
955 | s5m8767_get_register(s5m8767, id, &enable_reg, | ||
956 | &enable_val); | ||
957 | regulators[id].enable_reg = enable_reg; | ||
958 | regulators[id].enable_mask = S5M8767_ENCTRL_MASK; | ||
959 | regulators[id].enable_val = enable_val; | ||
938 | } | 960 | } |
939 | 961 | ||
940 | config.dev = s5m8767->dev; | 962 | config.dev = s5m8767->dev; |
@@ -942,6 +964,9 @@ static int s5m8767_pmic_probe(struct platform_device *pdev) | |||
942 | config.driver_data = s5m8767; | 964 | config.driver_data = s5m8767; |
943 | config.regmap = iodev->regmap_pmic; | 965 | config.regmap = iodev->regmap_pmic; |
944 | config.of_node = pdata->regulators[i].reg_node; | 966 | config.of_node = pdata->regulators[i].reg_node; |
967 | if (pdata->regulators[i].ext_control_gpio) | ||
968 | s5m8767_regulator_config_ext_control(s5m8767, | ||
969 | &pdata->regulators[i], &config); | ||
945 | 970 | ||
946 | rdev[i] = devm_regulator_register(&pdev->dev, ®ulators[id], | 971 | rdev[i] = devm_regulator_register(&pdev->dev, ®ulators[id], |
947 | &config); | 972 | &config); |
@@ -951,6 +976,16 @@ static int s5m8767_pmic_probe(struct platform_device *pdev) | |||
951 | id); | 976 | id); |
952 | return ret; | 977 | return ret; |
953 | } | 978 | } |
979 | |||
980 | if (pdata->regulators[i].ext_control_gpio) { | ||
981 | ret = s5m8767_enable_ext_control(s5m8767, rdev[i]); | ||
982 | if (ret < 0) { | ||
983 | dev_err(s5m8767->dev, | ||
984 | "failed to enable gpio control over %s: %d\n", | ||
985 | rdev[i]->desc->name, ret); | ||
986 | return ret; | ||
987 | } | ||
988 | } | ||
954 | } | 989 | } |
955 | 990 | ||
956 | return 0; | 991 | return 0; |
diff --git a/drivers/regulator/st-pwm.c b/drivers/regulator/st-pwm.c new file mode 100644 index 000000000000..e367af1c5f9d --- /dev/null +++ b/drivers/regulator/st-pwm.c | |||
@@ -0,0 +1,190 @@ | |||
1 | /* | ||
2 | * Regulator driver for ST's PWM Regulators | ||
3 | * | ||
4 | * Copyright (C) 2014 - STMicroelectronics Inc. | ||
5 | * | ||
6 | * Author: Lee Jones <lee.jones@linaro.org> | ||
7 | * | ||
8 | * This program is free software; you can redistribute it and/or modify | ||
9 | * it under the terms of the GNU General Public License version 2 as | ||
10 | * published by the Free Software Foundation. | ||
11 | */ | ||
12 | |||
13 | #include <linux/module.h> | ||
14 | #include <linux/init.h> | ||
15 | #include <linux/err.h> | ||
16 | #include <linux/regulator/driver.h> | ||
17 | #include <linux/regulator/machine.h> | ||
18 | #include <linux/regulator/of_regulator.h> | ||
19 | #include <linux/of.h> | ||
20 | #include <linux/of_device.h> | ||
21 | #include <linux/pwm.h> | ||
22 | |||
23 | #define ST_PWM_REG_PERIOD 8448 | ||
24 | |||
25 | struct st_pwm_regulator_pdata { | ||
26 | const struct regulator_desc *desc; | ||
27 | struct st_pwm_voltages *duty_cycle_table; | ||
28 | }; | ||
29 | |||
30 | struct st_pwm_regulator_data { | ||
31 | const struct st_pwm_regulator_pdata *pdata; | ||
32 | struct pwm_device *pwm; | ||
33 | bool enabled; | ||
34 | int state; | ||
35 | }; | ||
36 | |||
37 | struct st_pwm_voltages { | ||
38 | unsigned int uV; | ||
39 | unsigned int dutycycle; | ||
40 | }; | ||
41 | |||
42 | static int st_pwm_regulator_get_voltage_sel(struct regulator_dev *dev) | ||
43 | { | ||
44 | struct st_pwm_regulator_data *drvdata = rdev_get_drvdata(dev); | ||
45 | |||
46 | return drvdata->state; | ||
47 | } | ||
48 | |||
49 | static int st_pwm_regulator_set_voltage_sel(struct regulator_dev *dev, | ||
50 | unsigned selector) | ||
51 | { | ||
52 | struct st_pwm_regulator_data *drvdata = rdev_get_drvdata(dev); | ||
53 | int dutycycle; | ||
54 | int ret; | ||
55 | |||
56 | dutycycle = (ST_PWM_REG_PERIOD / 100) * | ||
57 | drvdata->pdata->duty_cycle_table[selector].dutycycle; | ||
58 | |||
59 | ret = pwm_config(drvdata->pwm, dutycycle, ST_PWM_REG_PERIOD); | ||
60 | if (ret) { | ||
61 | dev_err(&dev->dev, "Failed to configure PWM\n"); | ||
62 | return ret; | ||
63 | } | ||
64 | |||
65 | drvdata->state = selector; | ||
66 | |||
67 | if (!drvdata->enabled) { | ||
68 | ret = pwm_enable(drvdata->pwm); | ||
69 | if (ret) { | ||
70 | dev_err(&dev->dev, "Failed to enable PWM\n"); | ||
71 | return ret; | ||
72 | } | ||
73 | drvdata->enabled = true; | ||
74 | } | ||
75 | |||
76 | return 0; | ||
77 | } | ||
78 | |||
79 | static int st_pwm_regulator_list_voltage(struct regulator_dev *dev, | ||
80 | unsigned selector) | ||
81 | { | ||
82 | struct st_pwm_regulator_data *drvdata = rdev_get_drvdata(dev); | ||
83 | |||
84 | if (selector >= dev->desc->n_voltages) | ||
85 | return -EINVAL; | ||
86 | |||
87 | return drvdata->pdata->duty_cycle_table[selector].uV; | ||
88 | } | ||
89 | |||
90 | static struct regulator_ops st_pwm_regulator_voltage_ops = { | ||
91 | .set_voltage_sel = st_pwm_regulator_set_voltage_sel, | ||
92 | .get_voltage_sel = st_pwm_regulator_get_voltage_sel, | ||
93 | .list_voltage = st_pwm_regulator_list_voltage, | ||
94 | .map_voltage = regulator_map_voltage_iterate, | ||
95 | }; | ||
96 | |||
97 | static struct st_pwm_voltages b2105_duty_cycle_table[] = { | ||
98 | { .uV = 1114000, .dutycycle = 0, }, | ||
99 | { .uV = 1095000, .dutycycle = 10, }, | ||
100 | { .uV = 1076000, .dutycycle = 20, }, | ||
101 | { .uV = 1056000, .dutycycle = 30, }, | ||
102 | { .uV = 1036000, .dutycycle = 40, }, | ||
103 | { .uV = 1016000, .dutycycle = 50, }, | ||
104 | /* WARNING: Values above 50% duty-cycle cause boot failures. */ | ||
105 | }; | ||
106 | |||
107 | static const struct regulator_desc b2105_desc = { | ||
108 | .name = "b2105-pwm-regulator", | ||
109 | .ops = &st_pwm_regulator_voltage_ops, | ||
110 | .type = REGULATOR_VOLTAGE, | ||
111 | .owner = THIS_MODULE, | ||
112 | .n_voltages = ARRAY_SIZE(b2105_duty_cycle_table), | ||
113 | .supply_name = "pwm", | ||
114 | }; | ||
115 | |||
116 | static const struct st_pwm_regulator_pdata b2105_info = { | ||
117 | .desc = &b2105_desc, | ||
118 | .duty_cycle_table = b2105_duty_cycle_table, | ||
119 | }; | ||
120 | |||
121 | static struct of_device_id st_pwm_of_match[] = { | ||
122 | { .compatible = "st,b2105-pwm-regulator", .data = &b2105_info, }, | ||
123 | { }, | ||
124 | }; | ||
125 | MODULE_DEVICE_TABLE(of, st_pwm_of_match); | ||
126 | |||
127 | static int st_pwm_regulator_probe(struct platform_device *pdev) | ||
128 | { | ||
129 | struct st_pwm_regulator_data *drvdata; | ||
130 | struct regulator_dev *regulator; | ||
131 | struct regulator_config config = { }; | ||
132 | struct device_node *np = pdev->dev.of_node; | ||
133 | const struct of_device_id *of_match; | ||
134 | |||
135 | if (!np) { | ||
136 | dev_err(&pdev->dev, "Device Tree node missing\n"); | ||
137 | return -EINVAL; | ||
138 | } | ||
139 | |||
140 | drvdata = devm_kzalloc(&pdev->dev, sizeof(*drvdata), GFP_KERNEL); | ||
141 | if (!drvdata) | ||
142 | return -ENOMEM; | ||
143 | |||
144 | of_match = of_match_device(st_pwm_of_match, &pdev->dev); | ||
145 | if (!of_match) { | ||
146 | dev_err(&pdev->dev, "failed to match of device\n"); | ||
147 | return -ENODEV; | ||
148 | } | ||
149 | drvdata->pdata = of_match->data; | ||
150 | |||
151 | config.init_data = of_get_regulator_init_data(&pdev->dev, np); | ||
152 | if (!config.init_data) | ||
153 | return -ENOMEM; | ||
154 | |||
155 | config.of_node = np; | ||
156 | config.dev = &pdev->dev; | ||
157 | config.driver_data = drvdata; | ||
158 | |||
159 | drvdata->pwm = devm_pwm_get(&pdev->dev, NULL); | ||
160 | if (IS_ERR(drvdata->pwm)) { | ||
161 | dev_err(&pdev->dev, "Failed to get PWM\n"); | ||
162 | return PTR_ERR(drvdata->pwm); | ||
163 | } | ||
164 | |||
165 | regulator = devm_regulator_register(&pdev->dev, | ||
166 | drvdata->pdata->desc, &config); | ||
167 | if (IS_ERR(regulator)) { | ||
168 | dev_err(&pdev->dev, "Failed to register regulator %s\n", | ||
169 | drvdata->pdata->desc->name); | ||
170 | return PTR_ERR(regulator); | ||
171 | } | ||
172 | |||
173 | return 0; | ||
174 | } | ||
175 | |||
176 | static struct platform_driver st_pwm_regulator_driver = { | ||
177 | .driver = { | ||
178 | .name = "st-pwm-regulator", | ||
179 | .owner = THIS_MODULE, | ||
180 | .of_match_table = of_match_ptr(st_pwm_of_match), | ||
181 | }, | ||
182 | .probe = st_pwm_regulator_probe, | ||
183 | }; | ||
184 | |||
185 | module_platform_driver(st_pwm_regulator_driver); | ||
186 | |||
187 | MODULE_LICENSE("GPL"); | ||
188 | MODULE_AUTHOR("Lee Jones <lee.jones@linaro.org>"); | ||
189 | MODULE_DESCRIPTION("ST PWM Regulator Driver"); | ||
190 | MODULE_ALIAS("platform:st_pwm-regulator"); | ||
diff --git a/drivers/regulator/ti-abb-regulator.c b/drivers/regulator/ti-abb-regulator.c index b187b6bba7ad..a2dabb575b97 100644 --- a/drivers/regulator/ti-abb-regulator.c +++ b/drivers/regulator/ti-abb-regulator.c | |||
@@ -54,8 +54,8 @@ struct ti_abb_info { | |||
54 | 54 | ||
55 | /** | 55 | /** |
56 | * struct ti_abb_reg - Register description for ABB block | 56 | * struct ti_abb_reg - Register description for ABB block |
57 | * @setup_reg: setup register offset from base | 57 | * @setup_off: setup register offset from base |
58 | * @control_reg: control register offset from base | 58 | * @control_off: control register offset from base |
59 | * @sr2_wtcnt_value_mask: setup register- sr2_wtcnt_value mask | 59 | * @sr2_wtcnt_value_mask: setup register- sr2_wtcnt_value mask |
60 | * @fbb_sel_mask: setup register- FBB sel mask | 60 | * @fbb_sel_mask: setup register- FBB sel mask |
61 | * @rbb_sel_mask: setup register- RBB sel mask | 61 | * @rbb_sel_mask: setup register- RBB sel mask |
@@ -64,8 +64,8 @@ struct ti_abb_info { | |||
64 | * @opp_sel_mask: control register - mask for mode to operate | 64 | * @opp_sel_mask: control register - mask for mode to operate |
65 | */ | 65 | */ |
66 | struct ti_abb_reg { | 66 | struct ti_abb_reg { |
67 | u32 setup_reg; | 67 | u32 setup_off; |
68 | u32 control_reg; | 68 | u32 control_off; |
69 | 69 | ||
70 | /* Setup register fields */ | 70 | /* Setup register fields */ |
71 | u32 sr2_wtcnt_value_mask; | 71 | u32 sr2_wtcnt_value_mask; |
@@ -83,6 +83,8 @@ struct ti_abb_reg { | |||
83 | * @rdesc: regulator descriptor | 83 | * @rdesc: regulator descriptor |
84 | * @clk: clock(usually sysclk) supplying ABB block | 84 | * @clk: clock(usually sysclk) supplying ABB block |
85 | * @base: base address of ABB block | 85 | * @base: base address of ABB block |
86 | * @setup_reg: setup register of ABB block | ||
87 | * @control_reg: control register of ABB block | ||
86 | * @int_base: interrupt register base address | 88 | * @int_base: interrupt register base address |
87 | * @efuse_base: (optional) efuse base address for ABB modes | 89 | * @efuse_base: (optional) efuse base address for ABB modes |
88 | * @ldo_base: (optional) LDOVBB vset override base address | 90 | * @ldo_base: (optional) LDOVBB vset override base address |
@@ -99,6 +101,8 @@ struct ti_abb { | |||
99 | struct regulator_desc rdesc; | 101 | struct regulator_desc rdesc; |
100 | struct clk *clk; | 102 | struct clk *clk; |
101 | void __iomem *base; | 103 | void __iomem *base; |
104 | void __iomem *setup_reg; | ||
105 | void __iomem *control_reg; | ||
102 | void __iomem *int_base; | 106 | void __iomem *int_base; |
103 | void __iomem *efuse_base; | 107 | void __iomem *efuse_base; |
104 | void __iomem *ldo_base; | 108 | void __iomem *ldo_base; |
@@ -118,20 +122,18 @@ struct ti_abb { | |||
118 | * ti_abb_rmw() - handy wrapper to set specific register bits | 122 | * ti_abb_rmw() - handy wrapper to set specific register bits |
119 | * @mask: mask for register field | 123 | * @mask: mask for register field |
120 | * @value: value shifted to mask location and written | 124 | * @value: value shifted to mask location and written |
121 | * @offset: offset of register | 125 | * @reg: register address |
122 | * @base: base address | ||
123 | * | 126 | * |
124 | * Return: final register value (may be unused) | 127 | * Return: final register value (may be unused) |
125 | */ | 128 | */ |
126 | static inline u32 ti_abb_rmw(u32 mask, u32 value, u32 offset, | 129 | static inline u32 ti_abb_rmw(u32 mask, u32 value, void __iomem *reg) |
127 | void __iomem *base) | ||
128 | { | 130 | { |
129 | u32 val; | 131 | u32 val; |
130 | 132 | ||
131 | val = readl(base + offset); | 133 | val = readl(reg); |
132 | val &= ~mask; | 134 | val &= ~mask; |
133 | val |= (value << __ffs(mask)) & mask; | 135 | val |= (value << __ffs(mask)) & mask; |
134 | writel(val, base + offset); | 136 | writel(val, reg); |
135 | 137 | ||
136 | return val; | 138 | return val; |
137 | } | 139 | } |
@@ -263,21 +265,19 @@ static int ti_abb_set_opp(struct regulator_dev *rdev, struct ti_abb *abb, | |||
263 | if (ret) | 265 | if (ret) |
264 | goto out; | 266 | goto out; |
265 | 267 | ||
266 | ti_abb_rmw(regs->fbb_sel_mask | regs->rbb_sel_mask, 0, regs->setup_reg, | 268 | ti_abb_rmw(regs->fbb_sel_mask | regs->rbb_sel_mask, 0, abb->setup_reg); |
267 | abb->base); | ||
268 | 269 | ||
269 | switch (info->opp_sel) { | 270 | switch (info->opp_sel) { |
270 | case TI_ABB_SLOW_OPP: | 271 | case TI_ABB_SLOW_OPP: |
271 | ti_abb_rmw(regs->rbb_sel_mask, 1, regs->setup_reg, abb->base); | 272 | ti_abb_rmw(regs->rbb_sel_mask, 1, abb->setup_reg); |
272 | break; | 273 | break; |
273 | case TI_ABB_FAST_OPP: | 274 | case TI_ABB_FAST_OPP: |
274 | ti_abb_rmw(regs->fbb_sel_mask, 1, regs->setup_reg, abb->base); | 275 | ti_abb_rmw(regs->fbb_sel_mask, 1, abb->setup_reg); |
275 | break; | 276 | break; |
276 | } | 277 | } |
277 | 278 | ||
278 | /* program next state of ABB ldo */ | 279 | /* program next state of ABB ldo */ |
279 | ti_abb_rmw(regs->opp_sel_mask, info->opp_sel, regs->control_reg, | 280 | ti_abb_rmw(regs->opp_sel_mask, info->opp_sel, abb->control_reg); |
280 | abb->base); | ||
281 | 281 | ||
282 | /* | 282 | /* |
283 | * program LDO VBB vset override if needed for !bypass mode | 283 | * program LDO VBB vset override if needed for !bypass mode |
@@ -288,7 +288,7 @@ static int ti_abb_set_opp(struct regulator_dev *rdev, struct ti_abb *abb, | |||
288 | ti_abb_program_ldovbb(dev, abb, info); | 288 | ti_abb_program_ldovbb(dev, abb, info); |
289 | 289 | ||
290 | /* Initiate ABB ldo change */ | 290 | /* Initiate ABB ldo change */ |
291 | ti_abb_rmw(regs->opp_change_mask, 1, regs->control_reg, abb->base); | 291 | ti_abb_rmw(regs->opp_change_mask, 1, abb->control_reg); |
292 | 292 | ||
293 | /* Wait for ABB LDO to complete transition to new Bias setting */ | 293 | /* Wait for ABB LDO to complete transition to new Bias setting */ |
294 | ret = ti_abb_wait_txdone(dev, abb); | 294 | ret = ti_abb_wait_txdone(dev, abb); |
@@ -490,8 +490,7 @@ static int ti_abb_init_timings(struct device *dev, struct ti_abb *abb) | |||
490 | dev_dbg(dev, "%s: Clk_rate=%ld, sr2_cnt=0x%08x\n", __func__, | 490 | dev_dbg(dev, "%s: Clk_rate=%ld, sr2_cnt=0x%08x\n", __func__, |
491 | clk_get_rate(abb->clk), sr2_wt_cnt_val); | 491 | clk_get_rate(abb->clk), sr2_wt_cnt_val); |
492 | 492 | ||
493 | ti_abb_rmw(regs->sr2_wtcnt_value_mask, sr2_wt_cnt_val, regs->setup_reg, | 493 | ti_abb_rmw(regs->sr2_wtcnt_value_mask, sr2_wt_cnt_val, abb->setup_reg); |
494 | abb->base); | ||
495 | 494 | ||
496 | return 0; | 495 | return 0; |
497 | } | 496 | } |
@@ -508,32 +507,24 @@ static int ti_abb_init_table(struct device *dev, struct ti_abb *abb, | |||
508 | struct regulator_init_data *rinit_data) | 507 | struct regulator_init_data *rinit_data) |
509 | { | 508 | { |
510 | struct ti_abb_info *info; | 509 | struct ti_abb_info *info; |
511 | const struct property *prop; | ||
512 | const __be32 *abb_info; | ||
513 | const u32 num_values = 6; | 510 | const u32 num_values = 6; |
514 | char *pname = "ti,abb_info"; | 511 | char *pname = "ti,abb_info"; |
515 | u32 num_entries, i; | 512 | u32 i; |
516 | unsigned int *volt_table; | 513 | unsigned int *volt_table; |
517 | int min_uV = INT_MAX, max_uV = 0; | 514 | int num_entries, min_uV = INT_MAX, max_uV = 0; |
518 | struct regulation_constraints *c = &rinit_data->constraints; | 515 | struct regulation_constraints *c = &rinit_data->constraints; |
519 | 516 | ||
520 | prop = of_find_property(dev->of_node, pname, NULL); | ||
521 | if (!prop) { | ||
522 | dev_err(dev, "No '%s' property?\n", pname); | ||
523 | return -ENODEV; | ||
524 | } | ||
525 | |||
526 | if (!prop->value) { | ||
527 | dev_err(dev, "Empty '%s' property?\n", pname); | ||
528 | return -ENODATA; | ||
529 | } | ||
530 | |||
531 | /* | 517 | /* |
532 | * Each abb_info is a set of n-tuple, where n is num_values, consisting | 518 | * Each abb_info is a set of n-tuple, where n is num_values, consisting |
533 | * of voltage and a set of detection logic for ABB information for that | 519 | * of voltage and a set of detection logic for ABB information for that |
534 | * voltage to apply. | 520 | * voltage to apply. |
535 | */ | 521 | */ |
536 | num_entries = prop->length / sizeof(u32); | 522 | num_entries = of_property_count_u32_elems(dev->of_node, pname); |
523 | if (num_entries < 0) { | ||
524 | dev_err(dev, "No '%s' property?\n", pname); | ||
525 | return num_entries; | ||
526 | } | ||
527 | |||
537 | if (!num_entries || (num_entries % num_values)) { | 528 | if (!num_entries || (num_entries % num_values)) { |
538 | dev_err(dev, "All '%s' list entries need %d vals\n", pname, | 529 | dev_err(dev, "All '%s' list entries need %d vals\n", pname, |
539 | num_values); | 530 | num_values); |
@@ -542,38 +533,38 @@ static int ti_abb_init_table(struct device *dev, struct ti_abb *abb, | |||
542 | num_entries /= num_values; | 533 | num_entries /= num_values; |
543 | 534 | ||
544 | info = devm_kzalloc(dev, sizeof(*info) * num_entries, GFP_KERNEL); | 535 | info = devm_kzalloc(dev, sizeof(*info) * num_entries, GFP_KERNEL); |
545 | if (!info) { | 536 | if (!info) |
546 | dev_err(dev, "Can't allocate info table for '%s' property\n", | ||
547 | pname); | ||
548 | return -ENOMEM; | 537 | return -ENOMEM; |
549 | } | 538 | |
550 | abb->info = info; | 539 | abb->info = info; |
551 | 540 | ||
552 | volt_table = devm_kzalloc(dev, sizeof(unsigned int) * num_entries, | 541 | volt_table = devm_kzalloc(dev, sizeof(unsigned int) * num_entries, |
553 | GFP_KERNEL); | 542 | GFP_KERNEL); |
554 | if (!volt_table) { | 543 | if (!volt_table) |
555 | dev_err(dev, "Can't allocate voltage table for '%s' property\n", | ||
556 | pname); | ||
557 | return -ENOMEM; | 544 | return -ENOMEM; |
558 | } | ||
559 | 545 | ||
560 | abb->rdesc.n_voltages = num_entries; | 546 | abb->rdesc.n_voltages = num_entries; |
561 | abb->rdesc.volt_table = volt_table; | 547 | abb->rdesc.volt_table = volt_table; |
562 | /* We do not know where the OPP voltage is at the moment */ | 548 | /* We do not know where the OPP voltage is at the moment */ |
563 | abb->current_info_idx = -EINVAL; | 549 | abb->current_info_idx = -EINVAL; |
564 | 550 | ||
565 | abb_info = prop->value; | ||
566 | for (i = 0; i < num_entries; i++, info++, volt_table++) { | 551 | for (i = 0; i < num_entries; i++, info++, volt_table++) { |
567 | u32 efuse_offset, rbb_mask, fbb_mask, vset_mask; | 552 | u32 efuse_offset, rbb_mask, fbb_mask, vset_mask; |
568 | u32 efuse_val; | 553 | u32 efuse_val; |
569 | 554 | ||
570 | /* NOTE: num_values should equal to entries picked up here */ | 555 | /* NOTE: num_values should equal to entries picked up here */ |
571 | *volt_table = be32_to_cpup(abb_info++); | 556 | of_property_read_u32_index(dev->of_node, pname, i * num_values, |
572 | info->opp_sel = be32_to_cpup(abb_info++); | 557 | volt_table); |
573 | efuse_offset = be32_to_cpup(abb_info++); | 558 | of_property_read_u32_index(dev->of_node, pname, |
574 | rbb_mask = be32_to_cpup(abb_info++); | 559 | i * num_values + 1, &info->opp_sel); |
575 | fbb_mask = be32_to_cpup(abb_info++); | 560 | of_property_read_u32_index(dev->of_node, pname, |
576 | vset_mask = be32_to_cpup(abb_info++); | 561 | i * num_values + 2, &efuse_offset); |
562 | of_property_read_u32_index(dev->of_node, pname, | ||
563 | i * num_values + 3, &rbb_mask); | ||
564 | of_property_read_u32_index(dev->of_node, pname, | ||
565 | i * num_values + 4, &fbb_mask); | ||
566 | of_property_read_u32_index(dev->of_node, pname, | ||
567 | i * num_values + 5, &vset_mask); | ||
577 | 568 | ||
578 | dev_dbg(dev, | 569 | dev_dbg(dev, |
579 | "[%d]v=%d ABB=%d ef=0x%x rbb=0x%x fbb=0x%x vset=0x%x\n", | 570 | "[%d]v=%d ABB=%d ef=0x%x rbb=0x%x fbb=0x%x vset=0x%x\n", |
@@ -648,8 +639,8 @@ static struct regulator_ops ti_abb_reg_ops = { | |||
648 | /* Default ABB block offsets, IF this changes in future, create new one */ | 639 | /* Default ABB block offsets, IF this changes in future, create new one */ |
649 | static const struct ti_abb_reg abb_regs_v1 = { | 640 | static const struct ti_abb_reg abb_regs_v1 = { |
650 | /* WARNING: registers are wrongly documented in TRM */ | 641 | /* WARNING: registers are wrongly documented in TRM */ |
651 | .setup_reg = 0x04, | 642 | .setup_off = 0x04, |
652 | .control_reg = 0x00, | 643 | .control_off = 0x00, |
653 | 644 | ||
654 | .sr2_wtcnt_value_mask = (0xff << 8), | 645 | .sr2_wtcnt_value_mask = (0xff << 8), |
655 | .fbb_sel_mask = (0x01 << 2), | 646 | .fbb_sel_mask = (0x01 << 2), |
@@ -661,8 +652,8 @@ static const struct ti_abb_reg abb_regs_v1 = { | |||
661 | }; | 652 | }; |
662 | 653 | ||
663 | static const struct ti_abb_reg abb_regs_v2 = { | 654 | static const struct ti_abb_reg abb_regs_v2 = { |
664 | .setup_reg = 0x00, | 655 | .setup_off = 0x00, |
665 | .control_reg = 0x04, | 656 | .control_off = 0x04, |
666 | 657 | ||
667 | .sr2_wtcnt_value_mask = (0xff << 8), | 658 | .sr2_wtcnt_value_mask = (0xff << 8), |
668 | .fbb_sel_mask = (0x01 << 2), | 659 | .fbb_sel_mask = (0x01 << 2), |
@@ -673,9 +664,20 @@ static const struct ti_abb_reg abb_regs_v2 = { | |||
673 | .opp_sel_mask = (0x03 << 0), | 664 | .opp_sel_mask = (0x03 << 0), |
674 | }; | 665 | }; |
675 | 666 | ||
667 | static const struct ti_abb_reg abb_regs_generic = { | ||
668 | .sr2_wtcnt_value_mask = (0xff << 8), | ||
669 | .fbb_sel_mask = (0x01 << 2), | ||
670 | .rbb_sel_mask = (0x01 << 1), | ||
671 | .sr2_en_mask = (0x01 << 0), | ||
672 | |||
673 | .opp_change_mask = (0x01 << 2), | ||
674 | .opp_sel_mask = (0x03 << 0), | ||
675 | }; | ||
676 | |||
676 | static const struct of_device_id ti_abb_of_match[] = { | 677 | static const struct of_device_id ti_abb_of_match[] = { |
677 | {.compatible = "ti,abb-v1", .data = &abb_regs_v1}, | 678 | {.compatible = "ti,abb-v1", .data = &abb_regs_v1}, |
678 | {.compatible = "ti,abb-v2", .data = &abb_regs_v2}, | 679 | {.compatible = "ti,abb-v2", .data = &abb_regs_v2}, |
680 | {.compatible = "ti,abb-v3", .data = &abb_regs_generic}, | ||
679 | { }, | 681 | { }, |
680 | }; | 682 | }; |
681 | 683 | ||
@@ -722,11 +724,29 @@ static int ti_abb_probe(struct platform_device *pdev) | |||
722 | abb->regs = match->data; | 724 | abb->regs = match->data; |
723 | 725 | ||
724 | /* Map ABB resources */ | 726 | /* Map ABB resources */ |
725 | pname = "base-address"; | 727 | if (abb->regs->setup_off || abb->regs->control_off) { |
726 | res = platform_get_resource_byname(pdev, IORESOURCE_MEM, pname); | 728 | pname = "base-address"; |
727 | abb->base = devm_ioremap_resource(dev, res); | 729 | res = platform_get_resource_byname(pdev, IORESOURCE_MEM, pname); |
728 | if (IS_ERR(abb->base)) | 730 | abb->base = devm_ioremap_resource(dev, res); |
729 | return PTR_ERR(abb->base); | 731 | if (IS_ERR(abb->base)) |
732 | return PTR_ERR(abb->base); | ||
733 | |||
734 | abb->setup_reg = abb->base + abb->regs->setup_off; | ||
735 | abb->control_reg = abb->base + abb->regs->control_off; | ||
736 | |||
737 | } else { | ||
738 | pname = "control-address"; | ||
739 | res = platform_get_resource_byname(pdev, IORESOURCE_MEM, pname); | ||
740 | abb->control_reg = devm_ioremap_resource(dev, res); | ||
741 | if (IS_ERR(abb->control_reg)) | ||
742 | return PTR_ERR(abb->control_reg); | ||
743 | |||
744 | pname = "setup-address"; | ||
745 | res = platform_get_resource_byname(pdev, IORESOURCE_MEM, pname); | ||
746 | abb->setup_reg = devm_ioremap_resource(dev, res); | ||
747 | if (IS_ERR(abb->setup_reg)) | ||
748 | return PTR_ERR(abb->setup_reg); | ||
749 | } | ||
730 | 750 | ||
731 | pname = "int-address"; | 751 | pname = "int-address"; |
732 | res = platform_get_resource_byname(pdev, IORESOURCE_MEM, pname); | 752 | res = platform_get_resource_byname(pdev, IORESOURCE_MEM, pname); |
@@ -860,7 +880,7 @@ skip_opt: | |||
860 | platform_set_drvdata(pdev, rdev); | 880 | platform_set_drvdata(pdev, rdev); |
861 | 881 | ||
862 | /* Enable the ldo if not already done by bootloader */ | 882 | /* Enable the ldo if not already done by bootloader */ |
863 | ti_abb_rmw(abb->regs->sr2_en_mask, 1, abb->regs->setup_reg, abb->base); | 883 | ti_abb_rmw(abb->regs->sr2_en_mask, 1, abb->setup_reg); |
864 | 884 | ||
865 | return 0; | 885 | return 0; |
866 | } | 886 | } |
diff --git a/drivers/regulator/tps51632-regulator.c b/drivers/regulator/tps51632-regulator.c index b3764f594ee9..f31f22e3e1bd 100644 --- a/drivers/regulator/tps51632-regulator.c +++ b/drivers/regulator/tps51632-regulator.c | |||
@@ -227,10 +227,8 @@ static struct tps51632_regulator_platform_data * | |||
227 | struct device_node *np = dev->of_node; | 227 | struct device_node *np = dev->of_node; |
228 | 228 | ||
229 | pdata = devm_kzalloc(dev, sizeof(*pdata), GFP_KERNEL); | 229 | pdata = devm_kzalloc(dev, sizeof(*pdata), GFP_KERNEL); |
230 | if (!pdata) { | 230 | if (!pdata) |
231 | dev_err(dev, "Memory alloc failed for platform data\n"); | ||
232 | return NULL; | 231 | return NULL; |
233 | } | ||
234 | 232 | ||
235 | pdata->reg_init_data = of_get_regulator_init_data(dev, dev->of_node); | 233 | pdata->reg_init_data = of_get_regulator_init_data(dev, dev->of_node); |
236 | if (!pdata->reg_init_data) { | 234 | if (!pdata->reg_init_data) { |
@@ -299,10 +297,8 @@ static int tps51632_probe(struct i2c_client *client, | |||
299 | } | 297 | } |
300 | 298 | ||
301 | tps = devm_kzalloc(&client->dev, sizeof(*tps), GFP_KERNEL); | 299 | tps = devm_kzalloc(&client->dev, sizeof(*tps), GFP_KERNEL); |
302 | if (!tps) { | 300 | if (!tps) |
303 | dev_err(&client->dev, "Memory allocation failed\n"); | ||
304 | return -ENOMEM; | 301 | return -ENOMEM; |
305 | } | ||
306 | 302 | ||
307 | tps->dev = &client->dev; | 303 | tps->dev = &client->dev; |
308 | tps->desc.name = client->name; | 304 | tps->desc.name = client->name; |
diff --git a/drivers/regulator/tps62360-regulator.c b/drivers/regulator/tps62360-regulator.c index c3fa15a299b1..a1672044e519 100644 --- a/drivers/regulator/tps62360-regulator.c +++ b/drivers/regulator/tps62360-regulator.c | |||
@@ -299,10 +299,8 @@ static struct tps62360_regulator_platform_data * | |||
299 | struct device_node *np = dev->of_node; | 299 | struct device_node *np = dev->of_node; |
300 | 300 | ||
301 | pdata = devm_kzalloc(dev, sizeof(*pdata), GFP_KERNEL); | 301 | pdata = devm_kzalloc(dev, sizeof(*pdata), GFP_KERNEL); |
302 | if (!pdata) { | 302 | if (!pdata) |
303 | dev_err(dev, "Memory alloc failed for platform data\n"); | ||
304 | return NULL; | 303 | return NULL; |
305 | } | ||
306 | 304 | ||
307 | pdata->reg_init_data = of_get_regulator_init_data(dev, dev->of_node); | 305 | pdata->reg_init_data = of_get_regulator_init_data(dev, dev->of_node); |
308 | if (!pdata->reg_init_data) { | 306 | if (!pdata->reg_init_data) { |
@@ -377,11 +375,8 @@ static int tps62360_probe(struct i2c_client *client, | |||
377 | } | 375 | } |
378 | 376 | ||
379 | tps = devm_kzalloc(&client->dev, sizeof(*tps), GFP_KERNEL); | 377 | tps = devm_kzalloc(&client->dev, sizeof(*tps), GFP_KERNEL); |
380 | if (!tps) { | 378 | if (!tps) |
381 | dev_err(&client->dev, "%s(): Memory allocation failed\n", | ||
382 | __func__); | ||
383 | return -ENOMEM; | 379 | return -ENOMEM; |
384 | } | ||
385 | 380 | ||
386 | tps->en_discharge = pdata->en_discharge; | 381 | tps->en_discharge = pdata->en_discharge; |
387 | tps->en_internal_pulldn = pdata->en_internal_pulldn; | 382 | tps->en_internal_pulldn = pdata->en_internal_pulldn; |
diff --git a/drivers/regulator/tps6507x-regulator.c b/drivers/regulator/tps6507x-regulator.c index 162a0fae20b3..98e66ce26723 100644 --- a/drivers/regulator/tps6507x-regulator.c +++ b/drivers/regulator/tps6507x-regulator.c | |||
@@ -359,7 +359,6 @@ static struct regulator_ops tps6507x_pmic_ops = { | |||
359 | .map_voltage = regulator_map_voltage_ascend, | 359 | .map_voltage = regulator_map_voltage_ascend, |
360 | }; | 360 | }; |
361 | 361 | ||
362 | #ifdef CONFIG_OF | ||
363 | static struct of_regulator_match tps6507x_matches[] = { | 362 | static struct of_regulator_match tps6507x_matches[] = { |
364 | { .name = "VDCDC1"}, | 363 | { .name = "VDCDC1"}, |
365 | { .name = "VDCDC2"}, | 364 | { .name = "VDCDC2"}, |
@@ -381,12 +380,10 @@ static struct tps6507x_board *tps6507x_parse_dt_reg_data( | |||
381 | 380 | ||
382 | tps_board = devm_kzalloc(&pdev->dev, sizeof(*tps_board), | 381 | tps_board = devm_kzalloc(&pdev->dev, sizeof(*tps_board), |
383 | GFP_KERNEL); | 382 | GFP_KERNEL); |
384 | if (!tps_board) { | 383 | if (!tps_board) |
385 | dev_err(&pdev->dev, "Failure to alloc pdata for regulators.\n"); | ||
386 | return NULL; | 384 | return NULL; |
387 | } | ||
388 | 385 | ||
389 | regulators = of_find_node_by_name(np, "regulators"); | 386 | regulators = of_get_child_by_name(np, "regulators"); |
390 | if (!regulators) { | 387 | if (!regulators) { |
391 | dev_err(&pdev->dev, "regulator node not found\n"); | 388 | dev_err(&pdev->dev, "regulator node not found\n"); |
392 | return NULL; | 389 | return NULL; |
@@ -396,6 +393,7 @@ static struct tps6507x_board *tps6507x_parse_dt_reg_data( | |||
396 | matches = tps6507x_matches; | 393 | matches = tps6507x_matches; |
397 | 394 | ||
398 | ret = of_regulator_match(&pdev->dev, regulators, matches, count); | 395 | ret = of_regulator_match(&pdev->dev, regulators, matches, count); |
396 | of_node_put(regulators); | ||
399 | if (ret < 0) { | 397 | if (ret < 0) { |
400 | dev_err(&pdev->dev, "Error parsing regulator init data: %d\n", | 398 | dev_err(&pdev->dev, "Error parsing regulator init data: %d\n", |
401 | ret); | 399 | ret); |
@@ -406,10 +404,8 @@ static struct tps6507x_board *tps6507x_parse_dt_reg_data( | |||
406 | 404 | ||
407 | reg_data = devm_kzalloc(&pdev->dev, (sizeof(struct regulator_init_data) | 405 | reg_data = devm_kzalloc(&pdev->dev, (sizeof(struct regulator_init_data) |
408 | * TPS6507X_NUM_REGULATOR), GFP_KERNEL); | 406 | * TPS6507X_NUM_REGULATOR), GFP_KERNEL); |
409 | if (!reg_data) { | 407 | if (!reg_data) |
410 | dev_err(&pdev->dev, "Failure to alloc init data for regulators.\n"); | ||
411 | return NULL; | 408 | return NULL; |
412 | } | ||
413 | 409 | ||
414 | tps_board->tps6507x_pmic_init_data = reg_data; | 410 | tps_board->tps6507x_pmic_init_data = reg_data; |
415 | 411 | ||
@@ -424,15 +420,7 @@ static struct tps6507x_board *tps6507x_parse_dt_reg_data( | |||
424 | 420 | ||
425 | return tps_board; | 421 | return tps_board; |
426 | } | 422 | } |
427 | #else | 423 | |
428 | static inline struct tps6507x_board *tps6507x_parse_dt_reg_data( | ||
429 | struct platform_device *pdev, | ||
430 | struct of_regulator_match **tps6507x_reg_matches) | ||
431 | { | ||
432 | *tps6507x_reg_matches = NULL; | ||
433 | return NULL; | ||
434 | } | ||
435 | #endif | ||
436 | static int tps6507x_pmic_probe(struct platform_device *pdev) | 424 | static int tps6507x_pmic_probe(struct platform_device *pdev) |
437 | { | 425 | { |
438 | struct tps6507x_dev *tps6507x_dev = dev_get_drvdata(pdev->dev.parent); | 426 | struct tps6507x_dev *tps6507x_dev = dev_get_drvdata(pdev->dev.parent); |
@@ -453,9 +441,10 @@ static int tps6507x_pmic_probe(struct platform_device *pdev) | |||
453 | */ | 441 | */ |
454 | 442 | ||
455 | tps_board = dev_get_platdata(tps6507x_dev->dev); | 443 | tps_board = dev_get_platdata(tps6507x_dev->dev); |
456 | if (!tps_board && tps6507x_dev->dev->of_node) | 444 | if (IS_ENABLED(CONFIG_OF) && !tps_board && |
445 | tps6507x_dev->dev->of_node) | ||
457 | tps_board = tps6507x_parse_dt_reg_data(pdev, | 446 | tps_board = tps6507x_parse_dt_reg_data(pdev, |
458 | &tps6507x_reg_matches); | 447 | &tps6507x_reg_matches); |
459 | if (!tps_board) | 448 | if (!tps_board) |
460 | return -EINVAL; | 449 | return -EINVAL; |
461 | 450 | ||
@@ -481,7 +470,7 @@ static int tps6507x_pmic_probe(struct platform_device *pdev) | |||
481 | tps->info[i] = info; | 470 | tps->info[i] = info; |
482 | if (init_data->driver_data) { | 471 | if (init_data->driver_data) { |
483 | struct tps6507x_reg_platform_data *data = | 472 | struct tps6507x_reg_platform_data *data = |
484 | init_data->driver_data; | 473 | init_data->driver_data; |
485 | tps->info[i]->defdcdc_default = data->defdcdc_default; | 474 | tps->info[i]->defdcdc_default = data->defdcdc_default; |
486 | } | 475 | } |
487 | 476 | ||
diff --git a/drivers/regulator/tps65090-regulator.c b/drivers/regulator/tps65090-regulator.c index 676f75548f00..2e92ef68574d 100644 --- a/drivers/regulator/tps65090-regulator.c +++ b/drivers/regulator/tps65090-regulator.c | |||
@@ -168,17 +168,13 @@ static struct tps65090_platform_data *tps65090_parse_dt_reg_data( | |||
168 | 168 | ||
169 | tps65090_pdata = devm_kzalloc(&pdev->dev, sizeof(*tps65090_pdata), | 169 | tps65090_pdata = devm_kzalloc(&pdev->dev, sizeof(*tps65090_pdata), |
170 | GFP_KERNEL); | 170 | GFP_KERNEL); |
171 | if (!tps65090_pdata) { | 171 | if (!tps65090_pdata) |
172 | dev_err(&pdev->dev, "Memory alloc for tps65090_pdata failed\n"); | ||
173 | return ERR_PTR(-ENOMEM); | 172 | return ERR_PTR(-ENOMEM); |
174 | } | ||
175 | 173 | ||
176 | reg_pdata = devm_kzalloc(&pdev->dev, TPS65090_REGULATOR_MAX * | 174 | reg_pdata = devm_kzalloc(&pdev->dev, TPS65090_REGULATOR_MAX * |
177 | sizeof(*reg_pdata), GFP_KERNEL); | 175 | sizeof(*reg_pdata), GFP_KERNEL); |
178 | if (!reg_pdata) { | 176 | if (!reg_pdata) |
179 | dev_err(&pdev->dev, "Memory alloc for reg_pdata failed\n"); | ||
180 | return ERR_PTR(-ENOMEM); | 177 | return ERR_PTR(-ENOMEM); |
181 | } | ||
182 | 178 | ||
183 | regulators = of_get_child_by_name(np, "regulators"); | 179 | regulators = of_get_child_by_name(np, "regulators"); |
184 | if (!regulators) { | 180 | if (!regulators) { |
@@ -188,6 +184,7 @@ static struct tps65090_platform_data *tps65090_parse_dt_reg_data( | |||
188 | 184 | ||
189 | ret = of_regulator_match(&pdev->dev, regulators, tps65090_matches, | 185 | ret = of_regulator_match(&pdev->dev, regulators, tps65090_matches, |
190 | ARRAY_SIZE(tps65090_matches)); | 186 | ARRAY_SIZE(tps65090_matches)); |
187 | of_node_put(regulators); | ||
191 | if (ret < 0) { | 188 | if (ret < 0) { |
192 | dev_err(&pdev->dev, | 189 | dev_err(&pdev->dev, |
193 | "Error parsing regulator init data: %d\n", ret); | 190 | "Error parsing regulator init data: %d\n", ret); |
@@ -252,10 +249,8 @@ static int tps65090_regulator_probe(struct platform_device *pdev) | |||
252 | 249 | ||
253 | pmic = devm_kzalloc(&pdev->dev, TPS65090_REGULATOR_MAX * sizeof(*pmic), | 250 | pmic = devm_kzalloc(&pdev->dev, TPS65090_REGULATOR_MAX * sizeof(*pmic), |
254 | GFP_KERNEL); | 251 | GFP_KERNEL); |
255 | if (!pmic) { | 252 | if (!pmic) |
256 | dev_err(&pdev->dev, "mem alloc for pmic failed\n"); | ||
257 | return -ENOMEM; | 253 | return -ENOMEM; |
258 | } | ||
259 | 254 | ||
260 | for (num = 0; num < TPS65090_REGULATOR_MAX; num++) { | 255 | for (num = 0; num < TPS65090_REGULATOR_MAX; num++) { |
261 | tps_pdata = tps65090_pdata->reg_pdata[num]; | 256 | tps_pdata = tps65090_pdata->reg_pdata[num]; |
diff --git a/drivers/regulator/tps65217-regulator.c b/drivers/regulator/tps65217-regulator.c index 9ea1bf26bd13..10b78d2b766a 100644 --- a/drivers/regulator/tps65217-regulator.c +++ b/drivers/regulator/tps65217-regulator.c | |||
@@ -187,7 +187,7 @@ static struct tps65217_board *tps65217_parse_dt(struct platform_device *pdev) | |||
187 | struct device_node *regs; | 187 | struct device_node *regs; |
188 | int i, count; | 188 | int i, count; |
189 | 189 | ||
190 | regs = of_find_node_by_name(node, "regulators"); | 190 | regs = of_get_child_by_name(node, "regulators"); |
191 | if (!regs) | 191 | if (!regs) |
192 | return NULL; | 192 | return NULL; |
193 | 193 | ||
@@ -202,7 +202,7 @@ static struct tps65217_board *tps65217_parse_dt(struct platform_device *pdev) | |||
202 | return NULL; | 202 | return NULL; |
203 | 203 | ||
204 | for (i = 0; i < count; i++) { | 204 | for (i = 0; i < count; i++) { |
205 | if (!reg_matches[i].init_data || !reg_matches[i].of_node) | 205 | if (!reg_matches[i].of_node) |
206 | continue; | 206 | continue; |
207 | 207 | ||
208 | pdata->tps65217_init_data[i] = reg_matches[i].init_data; | 208 | pdata->tps65217_init_data[i] = reg_matches[i].init_data; |
@@ -222,7 +222,6 @@ static int tps65217_regulator_probe(struct platform_device *pdev) | |||
222 | { | 222 | { |
223 | struct tps65217 *tps = dev_get_drvdata(pdev->dev.parent); | 223 | struct tps65217 *tps = dev_get_drvdata(pdev->dev.parent); |
224 | struct tps65217_board *pdata = dev_get_platdata(tps->dev); | 224 | struct tps65217_board *pdata = dev_get_platdata(tps->dev); |
225 | struct regulator_init_data *reg_data; | ||
226 | struct regulator_dev *rdev; | 225 | struct regulator_dev *rdev; |
227 | struct regulator_config config = { }; | 226 | struct regulator_config config = { }; |
228 | int i; | 227 | int i; |
@@ -243,19 +242,9 @@ static int tps65217_regulator_probe(struct platform_device *pdev) | |||
243 | platform_set_drvdata(pdev, tps); | 242 | platform_set_drvdata(pdev, tps); |
244 | 243 | ||
245 | for (i = 0; i < TPS65217_NUM_REGULATOR; i++) { | 244 | for (i = 0; i < TPS65217_NUM_REGULATOR; i++) { |
246 | |||
247 | reg_data = pdata->tps65217_init_data[i]; | ||
248 | |||
249 | /* | ||
250 | * Regulator API handles empty constraints but not NULL | ||
251 | * constraints | ||
252 | */ | ||
253 | if (!reg_data) | ||
254 | continue; | ||
255 | |||
256 | /* Register the regulators */ | 245 | /* Register the regulators */ |
257 | config.dev = tps->dev; | 246 | config.dev = tps->dev; |
258 | config.init_data = reg_data; | 247 | config.init_data = pdata->tps65217_init_data[i]; |
259 | config.driver_data = tps; | 248 | config.driver_data = tps; |
260 | config.regmap = tps->regmap; | 249 | config.regmap = tps->regmap; |
261 | if (tps->dev->of_node) | 250 | if (tps->dev->of_node) |
diff --git a/include/linux/mfd/samsung/core.h b/include/linux/mfd/samsung/core.h index 900bc9e1888b..157e32b6ca28 100644 --- a/include/linux/mfd/samsung/core.h +++ b/include/linux/mfd/samsung/core.h | |||
@@ -126,7 +126,8 @@ struct sec_platform_data { | |||
126 | struct sec_regulator_data { | 126 | struct sec_regulator_data { |
127 | int id; | 127 | int id; |
128 | struct regulator_init_data *initdata; | 128 | struct regulator_init_data *initdata; |
129 | struct device_node *reg_node; | 129 | struct device_node *reg_node; |
130 | int ext_control_gpio; | ||
130 | }; | 131 | }; |
131 | 132 | ||
132 | /* | 133 | /* |
diff --git a/include/linux/mfd/samsung/s5m8767.h b/include/linux/mfd/samsung/s5m8767.h index 2ab0b0f03641..243b58fec33d 100644 --- a/include/linux/mfd/samsung/s5m8767.h +++ b/include/linux/mfd/samsung/s5m8767.h | |||
@@ -183,10 +183,17 @@ enum s5m8767_regulators { | |||
183 | S5M8767_REG_MAX, | 183 | S5M8767_REG_MAX, |
184 | }; | 184 | }; |
185 | 185 | ||
186 | /* LDO_EN/BUCK_EN field in registers */ | ||
186 | #define S5M8767_ENCTRL_SHIFT 6 | 187 | #define S5M8767_ENCTRL_SHIFT 6 |
187 | #define S5M8767_ENCTRL_MASK (0x3 << S5M8767_ENCTRL_SHIFT) | 188 | #define S5M8767_ENCTRL_MASK (0x3 << S5M8767_ENCTRL_SHIFT) |
188 | 189 | ||
189 | /* | 190 | /* |
191 | * LDO_EN/BUCK_EN register value for controlling this Buck or LDO | ||
192 | * by GPIO (PWREN, BUCKEN). | ||
193 | */ | ||
194 | #define S5M8767_ENCTRL_USE_GPIO 0x1 | ||
195 | |||
196 | /* | ||
190 | * Values for BUCK_RAMP field in DVS_RAMP register, matching raw values | 197 | * Values for BUCK_RAMP field in DVS_RAMP register, matching raw values |
191 | * in mV/us. | 198 | * in mV/us. |
192 | */ | 199 | */ |