diff options
Diffstat (limited to 'drivers/regulator/s5m8767.c')
-rw-r--r-- | drivers/regulator/s5m8767.c | 175 |
1 files changed, 106 insertions, 69 deletions
diff --git a/drivers/regulator/s5m8767.c b/drivers/regulator/s5m8767.c index d7164bb75d3e..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 | { |
@@ -535,7 +554,7 @@ static int s5m8767_pmic_dt_parse_pdata(struct platform_device *pdev, | |||
535 | return -ENODEV; | 554 | return -ENODEV; |
536 | } | 555 | } |
537 | 556 | ||
538 | regulators_np = of_find_node_by_name(pmic_np, "regulators"); | 557 | regulators_np = of_get_child_by_name(pmic_np, "regulators"); |
539 | if (!regulators_np) { | 558 | if (!regulators_np) { |
540 | dev_err(iodev->dev, "could not find regulators sub-node\n"); | 559 | dev_err(iodev->dev, "could not find regulators sub-node\n"); |
541 | return -EINVAL; | 560 | return -EINVAL; |
@@ -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); |
@@ -591,6 +606,8 @@ static int s5m8767_pmic_dt_parse_pdata(struct platform_device *pdev, | |||
591 | rmode++; | 606 | rmode++; |
592 | } | 607 | } |
593 | 608 | ||
609 | of_node_put(regulators_np); | ||
610 | |||
594 | if (of_get_property(pmic_np, "s5m8767,pmic-buck2-uses-gpio-dvs", NULL)) { | 611 | if (of_get_property(pmic_np, "s5m8767,pmic-buck2-uses-gpio-dvs", NULL)) { |
595 | pdata->buck2_gpiodvs = true; | 612 | pdata->buck2_gpiodvs = true; |
596 | 613 | ||
@@ -920,6 +937,7 @@ static int s5m8767_pmic_probe(struct platform_device *pdev) | |||
920 | for (i = 0; i < pdata->num_regulators; i++) { | 937 | for (i = 0; i < pdata->num_regulators; i++) { |
921 | const struct sec_voltage_desc *desc; | 938 | const struct sec_voltage_desc *desc; |
922 | int id = pdata->regulators[i].id; | 939 | int id = pdata->regulators[i].id; |
940 | int enable_reg, enable_val; | ||
923 | 941 | ||
924 | desc = reg_voltage_map[id]; | 942 | desc = reg_voltage_map[id]; |
925 | if (desc) { | 943 | if (desc) { |
@@ -933,6 +951,12 @@ static int s5m8767_pmic_probe(struct platform_device *pdev) | |||
933 | regulators[id].vsel_mask = 0x3f; | 951 | regulators[id].vsel_mask = 0x3f; |
934 | else | 952 | else |
935 | 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; | ||
936 | } | 960 | } |
937 | 961 | ||
938 | config.dev = s5m8767->dev; | 962 | config.dev = s5m8767->dev; |
@@ -940,6 +964,9 @@ static int s5m8767_pmic_probe(struct platform_device *pdev) | |||
940 | config.driver_data = s5m8767; | 964 | config.driver_data = s5m8767; |
941 | config.regmap = iodev->regmap_pmic; | 965 | config.regmap = iodev->regmap_pmic; |
942 | 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); | ||
943 | 970 | ||
944 | rdev[i] = devm_regulator_register(&pdev->dev, ®ulators[id], | 971 | rdev[i] = devm_regulator_register(&pdev->dev, ®ulators[id], |
945 | &config); | 972 | &config); |
@@ -949,6 +976,16 @@ static int s5m8767_pmic_probe(struct platform_device *pdev) | |||
949 | id); | 976 | id); |
950 | return ret; | 977 | return ret; |
951 | } | 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 | } | ||
952 | } | 989 | } |
953 | 990 | ||
954 | return 0; | 991 | return 0; |