diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2014-06-03 14:44:48 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2014-06-03 14:44:48 -0400 |
commit | 312c76f1a3989b8d0c0c13fee765bb2c41f2d114 (patch) | |
tree | c3aeb04e87ad51cbf060a475c123b80d679cd33a /drivers/regulator/s2mps11.c | |
parent | e13cccfd86481bd4c0499577f44c570d334da79b (diff) | |
parent | 978371cbabb4cb7a47751049d72f06dc8348cab2 (diff) |
Merge tag 'regulator-v3.16' of git://git.kernel.org/pub/scm/linux/kernel/git/broonie/regulator into next
Pull regulator updates from Mark Brown:
"The bulk of the changes for this release are a few new drivers however
there are a couple of noticable core changes and the usual stream of
cleanups and fixes:
- move disable of unused regulators later in init so it comes after
deferred probe has iterated making startup smoother.
- fixes to reference counting of the DT nodes for constraints from
Charles Keepax. This has little practical impact since all real
users of the regulator bindings use FDT which doesn't need the
reference counting.
- lots of cleanups, especially to the Samsung drivers.
- support for Linear Technologies LTC3589, Texas Instruments
TPS658640 and X-Powers AXP20x"
* tag 'regulator-v3.16' of git://git.kernel.org/pub/scm/linux/kernel/git/broonie/regulator: (64 commits)
regulator: pbias: remove unnecessary OOM messages
regulator: max8649: remove unnecessary OOM messages
regulator: core: Fix the init of DT defined fixed regulators
regulator: core: Disable unused regulators after deferred probing is done
regulator: Don't disable unused regulators we don't have permission for
regulator: axp20x: Use regulator_map_voltage_ascend for LDO4
regulator: use of_property_read_{bool|u32}()
regulator: Fix regulator_get_{optional,exclusive}() documentation
regulators: Add definition of regulator_set_voltage_time() for !CONFIG_REGULATOR
regulator: arizona-ldo1: add missing #include
regulator: pfuze100: Support enable/disable for fixed regulator
regulator: ltc3589: Remove ltc3589_list_voltage_fixed function
regulator: ltc3589: Fix module dependency
regulator: tps6586x: Remove unused to_tps6586x_dev() function
regulator: tps65218: Convert to use regulator_set_voltage_time_sel
regulator: tps6586x: Add support for the TPS658640
regulator: tps6586x: Prepare supporting fixed regulators
regulator: pfuze100: Don't allocate an invalid gpio
regulator: pfuze100: Support SWB enable/disable
regulator: fixed: use of_property_read_{bool|u32}()
...
Diffstat (limited to 'drivers/regulator/s2mps11.c')
-rw-r--r-- | drivers/regulator/s2mps11.c | 113 |
1 files changed, 96 insertions, 17 deletions
diff --git a/drivers/regulator/s2mps11.c b/drivers/regulator/s2mps11.c index e713c162fbd4..02e2fb2fca66 100644 --- a/drivers/regulator/s2mps11.c +++ b/drivers/regulator/s2mps11.c | |||
@@ -27,6 +27,7 @@ | |||
27 | #include <linux/regulator/driver.h> | 27 | #include <linux/regulator/driver.h> |
28 | #include <linux/regulator/machine.h> | 28 | #include <linux/regulator/machine.h> |
29 | #include <linux/regulator/of_regulator.h> | 29 | #include <linux/regulator/of_regulator.h> |
30 | #include <linux/of_gpio.h> | ||
30 | #include <linux/mfd/samsung/core.h> | 31 | #include <linux/mfd/samsung/core.h> |
31 | #include <linux/mfd/samsung/s2mps11.h> | 32 | #include <linux/mfd/samsung/s2mps11.h> |
32 | #include <linux/mfd/samsung/s2mps14.h> | 33 | #include <linux/mfd/samsung/s2mps14.h> |
@@ -44,6 +45,8 @@ struct s2mps11_info { | |||
44 | * was enabled. | 45 | * was enabled. |
45 | */ | 46 | */ |
46 | unsigned int s2mps14_suspend_state:30; | 47 | unsigned int s2mps14_suspend_state:30; |
48 | /* Array of size rdev_num with GPIO-s for external sleep control */ | ||
49 | int *ext_control_gpio; | ||
47 | }; | 50 | }; |
48 | 51 | ||
49 | static int get_ramp_delay(int ramp_delay) | 52 | static int get_ramp_delay(int ramp_delay) |
@@ -202,11 +205,16 @@ static int s2mps11_set_ramp_delay(struct regulator_dev *rdev, int ramp_delay) | |||
202 | if (!ramp_enable) | 205 | if (!ramp_enable) |
203 | goto ramp_disable; | 206 | goto ramp_disable; |
204 | 207 | ||
205 | ret = regmap_update_bits(rdev->regmap, S2MPS11_REG_RAMP, | 208 | /* Ramp delay can be enabled/disabled only for buck[2346] */ |
206 | 1 << enable_shift, 1 << enable_shift); | 209 | if ((rdev_get_id(rdev) >= S2MPS11_BUCK2 && |
207 | if (ret) { | 210 | rdev_get_id(rdev) <= S2MPS11_BUCK4) || |
208 | dev_err(&rdev->dev, "failed to enable ramp rate\n"); | 211 | rdev_get_id(rdev) == S2MPS11_BUCK6) { |
209 | return ret; | 212 | ret = regmap_update_bits(rdev->regmap, S2MPS11_REG_RAMP, |
213 | 1 << enable_shift, 1 << enable_shift); | ||
214 | if (ret) { | ||
215 | dev_err(&rdev->dev, "failed to enable ramp rate\n"); | ||
216 | return ret; | ||
217 | } | ||
210 | } | 218 | } |
211 | 219 | ||
212 | ramp_val = get_ramp_delay(ramp_delay); | 220 | ramp_val = get_ramp_delay(ramp_delay); |
@@ -409,6 +417,8 @@ static int s2mps14_regulator_enable(struct regulator_dev *rdev) | |||
409 | 417 | ||
410 | if (s2mps11->s2mps14_suspend_state & (1 << rdev_get_id(rdev))) | 418 | if (s2mps11->s2mps14_suspend_state & (1 << rdev_get_id(rdev))) |
411 | val = S2MPS14_ENABLE_SUSPEND; | 419 | val = S2MPS14_ENABLE_SUSPEND; |
420 | else if (gpio_is_valid(s2mps11->ext_control_gpio[rdev_get_id(rdev)])) | ||
421 | val = S2MPS14_ENABLE_EXT_CONTROL; | ||
412 | else | 422 | else |
413 | val = rdev->desc->enable_mask; | 423 | val = rdev->desc->enable_mask; |
414 | 424 | ||
@@ -565,12 +575,61 @@ static const struct regulator_desc s2mps14_regulators[] = { | |||
565 | regulator_desc_s2mps14_buck1235(5), | 575 | regulator_desc_s2mps14_buck1235(5), |
566 | }; | 576 | }; |
567 | 577 | ||
578 | static int s2mps14_pmic_enable_ext_control(struct s2mps11_info *s2mps11, | ||
579 | struct regulator_dev *rdev) | ||
580 | { | ||
581 | return regmap_update_bits(rdev->regmap, rdev->desc->enable_reg, | ||
582 | rdev->desc->enable_mask, S2MPS14_ENABLE_EXT_CONTROL); | ||
583 | } | ||
584 | |||
585 | static void s2mps14_pmic_dt_parse_ext_control_gpio(struct platform_device *pdev, | ||
586 | struct of_regulator_match *rdata, struct s2mps11_info *s2mps11) | ||
587 | { | ||
588 | int *gpio = s2mps11->ext_control_gpio; | ||
589 | unsigned int i; | ||
590 | unsigned int valid_regulators[3] = { S2MPS14_LDO10, S2MPS14_LDO11, | ||
591 | S2MPS14_LDO12 }; | ||
592 | |||
593 | for (i = 0; i < ARRAY_SIZE(valid_regulators); i++) { | ||
594 | unsigned int reg = valid_regulators[i]; | ||
595 | |||
596 | if (!rdata[reg].init_data || !rdata[reg].of_node) | ||
597 | continue; | ||
598 | |||
599 | gpio[reg] = of_get_named_gpio(rdata[reg].of_node, | ||
600 | "samsung,ext-control-gpios", 0); | ||
601 | if (gpio_is_valid(gpio[reg])) | ||
602 | dev_dbg(&pdev->dev, "Using GPIO %d for ext-control over %d/%s\n", | ||
603 | gpio[reg], reg, rdata[reg].name); | ||
604 | } | ||
605 | } | ||
606 | |||
607 | static int s2mps11_pmic_dt_parse(struct platform_device *pdev, | ||
608 | struct of_regulator_match *rdata, struct s2mps11_info *s2mps11, | ||
609 | enum sec_device_type dev_type) | ||
610 | { | ||
611 | struct device_node *reg_np; | ||
612 | |||
613 | reg_np = of_get_child_by_name(pdev->dev.parent->of_node, "regulators"); | ||
614 | if (!reg_np) { | ||
615 | dev_err(&pdev->dev, "could not find regulators sub-node\n"); | ||
616 | return -EINVAL; | ||
617 | } | ||
618 | |||
619 | of_regulator_match(&pdev->dev, reg_np, rdata, s2mps11->rdev_num); | ||
620 | if (dev_type == S2MPS14X) | ||
621 | s2mps14_pmic_dt_parse_ext_control_gpio(pdev, rdata, s2mps11); | ||
622 | |||
623 | of_node_put(reg_np); | ||
624 | |||
625 | return 0; | ||
626 | } | ||
627 | |||
568 | static int s2mps11_pmic_probe(struct platform_device *pdev) | 628 | static int s2mps11_pmic_probe(struct platform_device *pdev) |
569 | { | 629 | { |
570 | struct sec_pmic_dev *iodev = dev_get_drvdata(pdev->dev.parent); | 630 | struct sec_pmic_dev *iodev = dev_get_drvdata(pdev->dev.parent); |
571 | struct sec_platform_data *pdata = iodev->pdata; | 631 | struct sec_platform_data *pdata = NULL; |
572 | struct of_regulator_match *rdata = NULL; | 632 | struct of_regulator_match *rdata = NULL; |
573 | struct device_node *reg_np = NULL; | ||
574 | struct regulator_config config = { }; | 633 | struct regulator_config config = { }; |
575 | struct s2mps11_info *s2mps11; | 634 | struct s2mps11_info *s2mps11; |
576 | int i, ret = 0; | 635 | int i, ret = 0; |
@@ -597,8 +656,21 @@ static int s2mps11_pmic_probe(struct platform_device *pdev) | |||
597 | return -EINVAL; | 656 | return -EINVAL; |
598 | }; | 657 | }; |
599 | 658 | ||
659 | s2mps11->ext_control_gpio = devm_kzalloc(&pdev->dev, | ||
660 | sizeof(*s2mps11->ext_control_gpio) * s2mps11->rdev_num, | ||
661 | GFP_KERNEL); | ||
662 | if (!s2mps11->ext_control_gpio) | ||
663 | return -ENOMEM; | ||
664 | /* | ||
665 | * 0 is a valid GPIO so initialize all GPIO-s to negative value | ||
666 | * to indicate that external control won't be used for this regulator. | ||
667 | */ | ||
668 | for (i = 0; i < s2mps11->rdev_num; i++) | ||
669 | s2mps11->ext_control_gpio[i] = -EINVAL; | ||
670 | |||
600 | if (!iodev->dev->of_node) { | 671 | if (!iodev->dev->of_node) { |
601 | if (pdata) { | 672 | if (iodev->pdata) { |
673 | pdata = iodev->pdata; | ||
602 | goto common_reg; | 674 | goto common_reg; |
603 | } else { | 675 | } else { |
604 | dev_err(pdev->dev.parent, | 676 | dev_err(pdev->dev.parent, |
@@ -614,15 +686,9 @@ static int s2mps11_pmic_probe(struct platform_device *pdev) | |||
614 | for (i = 0; i < s2mps11->rdev_num; i++) | 686 | for (i = 0; i < s2mps11->rdev_num; i++) |
615 | rdata[i].name = regulators[i].name; | 687 | rdata[i].name = regulators[i].name; |
616 | 688 | ||
617 | reg_np = of_get_child_by_name(iodev->dev->of_node, "regulators"); | 689 | ret = s2mps11_pmic_dt_parse(pdev, rdata, s2mps11, dev_type); |
618 | if (!reg_np) { | 690 | if (ret) |
619 | dev_err(&pdev->dev, "could not find regulators sub-node\n"); | ||
620 | ret = -EINVAL; | ||
621 | goto out; | 691 | goto out; |
622 | } | ||
623 | |||
624 | of_regulator_match(&pdev->dev, reg_np, rdata, s2mps11->rdev_num); | ||
625 | of_node_put(reg_np); | ||
626 | 692 | ||
627 | common_reg: | 693 | common_reg: |
628 | platform_set_drvdata(pdev, s2mps11); | 694 | platform_set_drvdata(pdev, s2mps11); |
@@ -630,16 +696,18 @@ common_reg: | |||
630 | config.dev = &pdev->dev; | 696 | config.dev = &pdev->dev; |
631 | config.regmap = iodev->regmap_pmic; | 697 | config.regmap = iodev->regmap_pmic; |
632 | config.driver_data = s2mps11; | 698 | config.driver_data = s2mps11; |
699 | config.ena_gpio_flags = GPIOF_OUT_INIT_HIGH; | ||
633 | for (i = 0; i < s2mps11->rdev_num; i++) { | 700 | for (i = 0; i < s2mps11->rdev_num; i++) { |
634 | struct regulator_dev *regulator; | 701 | struct regulator_dev *regulator; |
635 | 702 | ||
636 | if (!reg_np) { | 703 | if (pdata) { |
637 | config.init_data = pdata->regulators[i].initdata; | 704 | config.init_data = pdata->regulators[i].initdata; |
638 | config.of_node = pdata->regulators[i].reg_node; | 705 | config.of_node = pdata->regulators[i].reg_node; |
639 | } else { | 706 | } else { |
640 | config.init_data = rdata[i].init_data; | 707 | config.init_data = rdata[i].init_data; |
641 | config.of_node = rdata[i].of_node; | 708 | config.of_node = rdata[i].of_node; |
642 | } | 709 | } |
710 | config.ena_gpio = s2mps11->ext_control_gpio[i]; | ||
643 | 711 | ||
644 | regulator = devm_regulator_register(&pdev->dev, | 712 | regulator = devm_regulator_register(&pdev->dev, |
645 | ®ulators[i], &config); | 713 | ®ulators[i], &config); |
@@ -649,6 +717,17 @@ common_reg: | |||
649 | i); | 717 | i); |
650 | goto out; | 718 | goto out; |
651 | } | 719 | } |
720 | |||
721 | if (gpio_is_valid(s2mps11->ext_control_gpio[i])) { | ||
722 | ret = s2mps14_pmic_enable_ext_control(s2mps11, | ||
723 | regulator); | ||
724 | if (ret < 0) { | ||
725 | dev_err(&pdev->dev, | ||
726 | "failed to enable GPIO control over %s: %d\n", | ||
727 | regulator->desc->name, ret); | ||
728 | goto out; | ||
729 | } | ||
730 | } | ||
652 | } | 731 | } |
653 | 732 | ||
654 | out: | 733 | out: |