aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/regulator/s5m8767.c
diff options
context:
space:
mode:
authorKrzysztof Kozlowski <k.kozlowski@samsung.com>2014-01-24 08:37:57 -0500
committerMark Brown <broonie@linaro.org>2014-01-27 15:24:17 -0500
commitee1e0994ab1bd302fd03432de79c07751df47ffa (patch)
tree04ecbe1f9b036da25496727fd2d4ced15f8f22dd /drivers/regulator/s5m8767.c
parent07b19808486054f356dbf3495a277f51af062b35 (diff)
regulator: s5m8767: Use GPIO for controlling Buck9/eMMC
Add support for GPIO control (enable/disable) over Buck9. The Buck9 Converter is used as a supply for eMMC Host Controller. BUCK9EN GPIO of S5M8767 chip may be used by application processor to enable or disable the Buck9. This has two benefits: - It is faster than toggling it over I2C bus. - It allows disabling the regulator during suspend to RAM; The AP will enable it during resume; Without the patch the regulator supplying eMMC must be defined as fixed-regulator. Signed-off-by: Krzysztof Kozlowski <k.kozlowski@samsung.com> Acked-by: Lee Jones <lee.jones@linaro.org> Signed-off-by: Mark Brown <broonie@linaro.org>
Diffstat (limited to 'drivers/regulator/s5m8767.c')
-rw-r--r--drivers/regulator/s5m8767.c87
1 files changed, 84 insertions, 3 deletions
diff --git a/drivers/regulator/s5m8767.c b/drivers/regulator/s5m8767.c
index d7164bb75d3e..6850a25a41c4 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>
@@ -483,6 +480,65 @@ static struct regulator_desc regulators[] = {
483 s5m8767_regulator_desc(BUCK9), 480 s5m8767_regulator_desc(BUCK9),
484}; 481};
485 482
483/*
484 * Enable GPIO control over BUCK9 in regulator_config for that regulator.
485 */
486static void s5m8767_regulator_config_ext_control(struct s5m8767_info *s5m8767,
487 struct sec_regulator_data *rdata,
488 struct regulator_config *config)
489{
490 int i, mode = 0;
491
492 if (rdata->id != S5M8767_BUCK9)
493 return;
494
495 /* Check if opmode for regulator matches S5M8767_ENCTRL_USE_GPIO */
496 for (i = 0; i < s5m8767->num_regulators; i++) {
497 const struct sec_opmode_data *opmode = &s5m8767->opmode[i];
498 if (opmode->id == rdata->id) {
499 mode = s5m8767_opmode_reg[rdata->id][opmode->mode];
500 break;
501 }
502 }
503 if (mode != S5M8767_ENCTRL_USE_GPIO) {
504 dev_warn(s5m8767->dev,
505 "ext-control for %s: mismatched op_mode (%x), ignoring\n",
506 rdata->reg_node->name, mode);
507 return;
508 }
509
510 if (!gpio_is_valid(rdata->ext_control_gpio)) {
511 dev_warn(s5m8767->dev,
512 "ext-control for %s: GPIO not valid, ignoring\n",
513 rdata->reg_node->name);
514 return;
515 }
516
517 config->ena_gpio = rdata->ext_control_gpio;
518 config->ena_gpio_flags = GPIOF_OUT_INIT_HIGH;
519}
520
521/*
522 * Turn on GPIO control over BUCK9.
523 */
524static int s5m8767_enable_ext_control(struct s5m8767_info *s5m8767,
525 struct regulator_dev *rdev)
526{
527 int ret, reg, enable_ctrl;
528
529 if (rdev_get_id(rdev) != S5M8767_BUCK9)
530 return -EINVAL;
531
532 ret = s5m8767_get_register(rdev, &reg, &enable_ctrl);
533 if (ret)
534 return ret;
535
536 return regmap_update_bits(s5m8767->iodev->regmap_pmic,
537 reg, S5M8767_ENCTRL_MASK,
538 S5M8767_ENCTRL_USE_GPIO << S5M8767_ENCTRL_SHIFT);
539}
540
541
486#ifdef CONFIG_OF 542#ifdef CONFIG_OF
487static int s5m8767_pmic_dt_parse_dvs_gpio(struct sec_pmic_dev *iodev, 543static int s5m8767_pmic_dt_parse_dvs_gpio(struct sec_pmic_dev *iodev,
488 struct sec_platform_data *pdata, 544 struct sec_platform_data *pdata,
@@ -520,6 +576,16 @@ static int s5m8767_pmic_dt_parse_ds_gpio(struct sec_pmic_dev *iodev,
520 return 0; 576 return 0;
521} 577}
522 578
579static void s5m8767_pmic_dt_parse_ext_control_gpio(struct sec_pmic_dev *iodev,
580 struct sec_regulator_data *rdata,
581 struct device_node *reg_np)
582{
583 rdata->ext_control_gpio = of_get_named_gpio(reg_np,
584 "s5m8767,pmic-ext-control-gpios", 0);
585 if (!gpio_is_valid(rdata->ext_control_gpio))
586 rdata->ext_control_gpio = 0;
587}
588
523static int s5m8767_pmic_dt_parse_pdata(struct platform_device *pdev, 589static int s5m8767_pmic_dt_parse_pdata(struct platform_device *pdev,
524 struct sec_platform_data *pdata) 590 struct sec_platform_data *pdata)
525{ 591{
@@ -574,6 +640,8 @@ static int s5m8767_pmic_dt_parse_pdata(struct platform_device *pdev,
574 continue; 640 continue;
575 } 641 }
576 642
643 s5m8767_pmic_dt_parse_ext_control_gpio(iodev, rdata, reg_np);
644
577 rdata->id = i; 645 rdata->id = i;
578 rdata->initdata = of_get_regulator_init_data( 646 rdata->initdata = of_get_regulator_init_data(
579 &pdev->dev, reg_np); 647 &pdev->dev, reg_np);
@@ -940,6 +1008,9 @@ static int s5m8767_pmic_probe(struct platform_device *pdev)
940 config.driver_data = s5m8767; 1008 config.driver_data = s5m8767;
941 config.regmap = iodev->regmap_pmic; 1009 config.regmap = iodev->regmap_pmic;
942 config.of_node = pdata->regulators[i].reg_node; 1010 config.of_node = pdata->regulators[i].reg_node;
1011 if (pdata->regulators[i].ext_control_gpio)
1012 s5m8767_regulator_config_ext_control(s5m8767,
1013 &pdata->regulators[i], &config);
943 1014
944 rdev[i] = devm_regulator_register(&pdev->dev, &regulators[id], 1015 rdev[i] = devm_regulator_register(&pdev->dev, &regulators[id],
945 &config); 1016 &config);
@@ -949,6 +1020,16 @@ static int s5m8767_pmic_probe(struct platform_device *pdev)
949 id); 1020 id);
950 return ret; 1021 return ret;
951 } 1022 }
1023
1024 if (pdata->regulators[i].ext_control_gpio) {
1025 ret = s5m8767_enable_ext_control(s5m8767, rdev[i]);
1026 if (ret < 0) {
1027 dev_err(s5m8767->dev,
1028 "failed to enable gpio control over %s: %d\n",
1029 rdev[i]->desc->name, ret);
1030 return ret;
1031 }
1032 }
952 } 1033 }
953 1034
954 return 0; 1035 return 0;