diff options
Diffstat (limited to 'drivers/regulator')
-rw-r--r-- | drivers/regulator/arizona-ldo1.c | 57 | ||||
-rw-r--r-- | drivers/regulator/arizona-micsupp.c | 37 | ||||
-rw-r--r-- | drivers/regulator/core.c | 3 | ||||
-rw-r--r-- | drivers/regulator/of_regulator.c | 31 | ||||
-rw-r--r-- | drivers/regulator/pbias-regulator.c | 89 | ||||
-rw-r--r-- | drivers/regulator/s2mps11.c | 98 | ||||
-rw-r--r-- | drivers/regulator/s5m8767.c | 17 | ||||
-rw-r--r-- | drivers/regulator/tps65217-regulator.c | 4 |
8 files changed, 235 insertions, 101 deletions
diff --git a/drivers/regulator/arizona-ldo1.c b/drivers/regulator/arizona-ldo1.c index b1033d30b504..d3787e11f535 100644 --- a/drivers/regulator/arizona-ldo1.c +++ b/drivers/regulator/arizona-ldo1.c @@ -19,6 +19,7 @@ #include <linux/platform_device.h> #include <linux/regulator/driver.h> #include <linux/regulator/machine.h> +#include <linux/regulator/of_regulator.h> #include <linux/gpio.h> #include <linux/slab.h> @@ -178,6 +179,42 @@ static const struct regulator_init_data arizona_ldo1_default = { .num_consumer_supplies = 1, }; +static int arizona_ldo1_of_get_pdata(struct arizona *arizona, + struct regulator_config *config) +{ + struct arizona_pdata *pdata = &arizona->pdata; + struct arizona_ldo1 *ldo1 = config->driver_data; + struct device_node *init_node, *dcvdd_node; + struct regulator_init_data *init_data; + + pdata->ldoena = arizona_of_get_named_gpio(arizona, "wlf,ldoena", true); + + init_node = of_get_child_by_name(arizona->dev->of_node, "ldo1"); + dcvdd_node = of_parse_phandle(arizona->dev->of_node, "DCVDD-supply", 0); + + if (init_node) { + config->of_node = init_node; + + init_data = of_get_regulator_init_data(arizona->dev, init_node); + + if (init_data) { + init_data->consumer_supplies = &ldo1->supply; + init_data->num_consumer_supplies = 1; + + if (dcvdd_node && dcvdd_node != init_node) + arizona->external_dcvdd = true; + + pdata->ldo1 = init_data; + } + } else if (dcvdd_node) { + arizona->external_dcvdd = true; + } + + of_node_put(dcvdd_node); + + return 0; +} + static int arizona_ldo1_probe(struct platform_device *pdev) { struct arizona *arizona = dev_get_drvdata(pdev->dev.parent); @@ -186,6 +223,8 @@ static int arizona_ldo1_probe(struct platform_device *pdev) struct arizona_ldo1 *ldo1; int ret; + arizona->external_dcvdd = false; + ldo1 = devm_kzalloc(&pdev->dev, sizeof(*ldo1), GFP_KERNEL); if (!ldo1) return -ENOMEM; @@ -216,6 +255,15 @@ static int arizona_ldo1_probe(struct platform_device *pdev) config.dev = arizona->dev; config.driver_data = ldo1; config.regmap = arizona->regmap; + + if (IS_ENABLED(CONFIG_OF)) { + if (!dev_get_platdata(arizona->dev)) { + ret = arizona_ldo1_of_get_pdata(arizona, &config); + if (ret < 0) + return ret; + } + } + config.ena_gpio = arizona->pdata.ldoena; if (arizona->pdata.ldo1) @@ -223,6 +271,13 @@ static int arizona_ldo1_probe(struct platform_device *pdev) else config.init_data = &ldo1->init_data; + /* + * LDO1 can only be used to supply DCVDD so if it has no + * consumers then DCVDD is supplied externally. + */ + if (config.init_data->num_consumer_supplies == 0) + arizona->external_dcvdd = true; + ldo1->regulator = devm_regulator_register(&pdev->dev, desc, &config); if (IS_ERR(ldo1->regulator)) { ret = PTR_ERR(ldo1->regulator); @@ -231,6 +286,8 @@ static int arizona_ldo1_probe(struct platform_device *pdev) return ret; } + of_node_put(config.of_node); + platform_set_drvdata(pdev, ldo1); return 0; diff --git a/drivers/regulator/arizona-micsupp.c b/drivers/regulator/arizona-micsupp.c index 6fdd9bf6927f..b80ebbe88bac 100644 --- a/drivers/regulator/arizona-micsupp.c +++ b/drivers/regulator/arizona-micsupp.c @@ -19,6 +19,7 @@ #include <linux/platform_device.h> #include <linux/regulator/driver.h> #include <linux/regulator/machine.h> +#include <linux/regulator/of_regulator.h> #include <linux/gpio.h> #include <linux/slab.h> #include <linux/workqueue.h> @@ -195,6 +196,32 @@ static const struct regulator_init_data arizona_micsupp_ext_default = { .num_consumer_supplies = 1, }; +static int arizona_micsupp_of_get_pdata(struct arizona *arizona, + struct regulator_config *config) +{ + struct arizona_pdata *pdata = &arizona->pdata; + struct arizona_micsupp *micsupp = config->driver_data; + struct device_node *np; + struct regulator_init_data *init_data; + + np = of_get_child_by_name(arizona->dev->of_node, "micvdd"); + + if (np) { + config->of_node = np; + + init_data = of_get_regulator_init_data(arizona->dev, np); + + if (init_data) { + init_data->consumer_supplies = &micsupp->supply; + init_data->num_consumer_supplies = 1; + + pdata->micvdd = init_data; + } + } + + return 0; +} + static int arizona_micsupp_probe(struct platform_device *pdev) { struct arizona *arizona = dev_get_drvdata(pdev->dev.parent); @@ -234,6 +261,14 @@ static int arizona_micsupp_probe(struct platform_device *pdev) config.driver_data = micsupp; config.regmap = arizona->regmap; + if (IS_ENABLED(CONFIG_OF)) { + if (!dev_get_platdata(arizona->dev)) { + ret = arizona_micsupp_of_get_pdata(arizona, &config); + if (ret < 0) + return ret; + } + } + if (arizona->pdata.micvdd) config.init_data = arizona->pdata.micvdd; else @@ -253,6 +288,8 @@ static int arizona_micsupp_probe(struct platform_device *pdev) return ret; } + of_node_put(config.of_node); + platform_set_drvdata(pdev, micsupp); return 0; diff --git a/drivers/regulator/core.c b/drivers/regulator/core.c index 9a09f3cdbabb..b97ffd2365d3 100644 --- a/drivers/regulator/core.c +++ b/drivers/regulator/core.c @@ -3447,7 +3447,7 @@ regulator_register(const struct regulator_desc *regulator_desc, /* register with sysfs */ rdev->dev.class = ®ulator_class; - rdev->dev.of_node = config->of_node; + rdev->dev.of_node = of_node_get(config->of_node); rdev->dev.parent = dev; dev_set_name(&rdev->dev, "regulator.%d", atomic_inc_return(®ulator_no) - 1); @@ -3589,6 +3589,7 @@ void regulator_unregister(struct regulator_dev *rdev) list_del(&rdev->list); kfree(rdev->constraints); regulator_ena_gpio_free(rdev); + of_node_put(rdev->dev.of_node); device_unregister(&rdev->dev); mutex_unlock(®ulator_list_mutex); } diff --git a/drivers/regulator/of_regulator.c b/drivers/regulator/of_regulator.c index ea4f36f2cbe2..4672cd2f4632 100644 --- a/drivers/regulator/of_regulator.c +++ b/drivers/regulator/of_regulator.c @@ -106,6 +106,20 @@ struct regulator_init_data *of_get_regulator_init_data(struct device *dev, } EXPORT_SYMBOL_GPL(of_get_regulator_init_data); +struct devm_of_regulator_matches { + struct of_regulator_match *matches; + unsigned int num_matches; +}; + +static void devm_of_regulator_put_matches(struct device *dev, void *res) +{ + struct devm_of_regulator_matches *devm_matches = res; + int i; + + for (i = 0; i < devm_matches->num_matches; i++) + of_node_put(devm_matches->matches[i].of_node); +} + /** * of_regulator_match - extract multiple regulator init data from device tree. * @dev: device requesting the data @@ -119,7 +133,8 @@ EXPORT_SYMBOL_GPL(of_get_regulator_init_data); * regulator. The data parsed from a child node will be matched to a regulator * based on either the deprecated property regulator-compatible if present, * or otherwise the child node's name. Note that the match table is modified - * in place. + * in place and an additional of_node reference is taken for each matched + * regulator. * * Returns the number of matches found or a negative error code on failure. */ @@ -131,10 +146,22 @@ int of_regulator_match(struct device *dev, struct device_node *node, unsigned int i; const char *name; struct device_node *child; + struct devm_of_regulator_matches *devm_matches; if (!dev || !node) return -EINVAL; + devm_matches = devres_alloc(devm_of_regulator_put_matches, + sizeof(struct devm_of_regulator_matches), + GFP_KERNEL); + if (!devm_matches) + return -ENOMEM; + + devm_matches->matches = matches; + devm_matches->num_matches = num_matches; + + devres_add(dev, devm_matches); + for (i = 0; i < num_matches; i++) { struct of_regulator_match *match = &matches[i]; match->init_data = NULL; @@ -162,7 +189,7 @@ int of_regulator_match(struct device *dev, struct device_node *node, child->name); return -EINVAL; } - match->of_node = child; + match->of_node = of_node_get(child); count++; break; } diff --git a/drivers/regulator/pbias-regulator.c b/drivers/regulator/pbias-regulator.c index ded3b3574209..708ddbb83e29 100644 --- a/drivers/regulator/pbias-regulator.c +++ b/drivers/regulator/pbias-regulator.c @@ -38,85 +38,24 @@ struct pbias_reg_info { struct pbias_regulator_data { struct regulator_desc desc; void __iomem *pbias_addr; - unsigned int pbias_reg; struct regulator_dev *dev; struct regmap *syscon; const struct pbias_reg_info *info; int voltage; }; -static int pbias_regulator_set_voltage(struct regulator_dev *dev, - int min_uV, int max_uV, unsigned *selector) -{ - struct pbias_regulator_data *data = rdev_get_drvdata(dev); - const struct pbias_reg_info *info = data->info; - int ret, vmode; - - if (min_uV <= 1800000) - vmode = 0; - else if (min_uV > 1800000) - vmode = info->vmode; - - ret = regmap_update_bits(data->syscon, data->pbias_reg, - info->vmode, vmode); - - return ret; -} - -static int pbias_regulator_get_voltage(struct regulator_dev *rdev) -{ - struct pbias_regulator_data *data = rdev_get_drvdata(rdev); - const struct pbias_reg_info *info = data->info; - int value, voltage; - - regmap_read(data->syscon, data->pbias_reg, &value); - value &= info->vmode; - - voltage = value ? 3000000 : 1800000; - - return voltage; -} - -static int pbias_regulator_enable(struct regulator_dev *rdev) -{ - struct pbias_regulator_data *data = rdev_get_drvdata(rdev); - const struct pbias_reg_info *info = data->info; - int ret; - - ret = regmap_update_bits(data->syscon, data->pbias_reg, - info->enable_mask, info->enable); - - return ret; -} - -static int pbias_regulator_disable(struct regulator_dev *rdev) -{ - struct pbias_regulator_data *data = rdev_get_drvdata(rdev); - const struct pbias_reg_info *info = data->info; - int ret; - - ret = regmap_update_bits(data->syscon, data->pbias_reg, - info->enable_mask, 0); - return ret; -} - -static int pbias_regulator_is_enable(struct regulator_dev *rdev) -{ - struct pbias_regulator_data *data = rdev_get_drvdata(rdev); - const struct pbias_reg_info *info = data->info; - int value; - - regmap_read(data->syscon, data->pbias_reg, &value); - - return (value & info->enable_mask) == info->enable_mask; -} +static const unsigned int pbias_volt_table[] = { + 1800000, + 3000000 +}; static struct regulator_ops pbias_regulator_voltage_ops = { - .set_voltage = pbias_regulator_set_voltage, - .get_voltage = pbias_regulator_get_voltage, - .enable = pbias_regulator_enable, - .disable = pbias_regulator_disable, - .is_enabled = pbias_regulator_is_enable, + .list_voltage = regulator_list_voltage_table, + .get_voltage_sel = regulator_get_voltage_sel_regmap, + .set_voltage_sel = regulator_set_voltage_sel_regmap, + .enable = regulator_enable_regmap, + .disable = regulator_disable_regmap, + .is_enabled = regulator_is_enabled_regmap, }; static const struct pbias_reg_info pbias_mmc_omap2430 = { @@ -192,6 +131,7 @@ static int pbias_regulator_probe(struct platform_device *pdev) if (IS_ERR(syscon)) return PTR_ERR(syscon); + cfg.regmap = syscon; cfg.dev = &pdev->dev; for (idx = 0; idx < PBIAS_NUM_REGS && data_idx < count; idx++) { @@ -207,15 +147,20 @@ static int pbias_regulator_probe(struct platform_device *pdev) if (!res) return -EINVAL; - drvdata[data_idx].pbias_reg = res->start; drvdata[data_idx].syscon = syscon; drvdata[data_idx].info = info; drvdata[data_idx].desc.name = info->name; drvdata[data_idx].desc.owner = THIS_MODULE; drvdata[data_idx].desc.type = REGULATOR_VOLTAGE; drvdata[data_idx].desc.ops = &pbias_regulator_voltage_ops; + drvdata[data_idx].desc.volt_table = pbias_volt_table; drvdata[data_idx].desc.n_voltages = 2; drvdata[data_idx].desc.enable_time = info->enable_time; + drvdata[data_idx].desc.vsel_reg = res->start; + drvdata[data_idx].desc.vsel_mask = info->vmode; + drvdata[data_idx].desc.enable_reg = res->start; + drvdata[data_idx].desc.enable_mask = info->enable_mask; + drvdata[data_idx].desc.enable_val = info->enable; cfg.init_data = pbias_matches[idx].init_data; cfg.driver_data = &drvdata[data_idx]; diff --git a/drivers/regulator/s2mps11.c b/drivers/regulator/s2mps11.c index e713c162fbd4..6dad0aa74a47 100644 --- a/drivers/regulator/s2mps11.c +++ b/drivers/regulator/s2mps11.c @@ -27,6 +27,7 @@ #include <linux/regulator/driver.h> #include <linux/regulator/machine.h> #include <linux/regulator/of_regulator.h> +#include <linux/of_gpio.h> #include <linux/mfd/samsung/core.h> #include <linux/mfd/samsung/s2mps11.h> #include <linux/mfd/samsung/s2mps14.h> @@ -44,6 +45,8 @@ struct s2mps11_info { * was enabled. */ unsigned int s2mps14_suspend_state:30; + /* Array of size rdev_num with GPIO-s for external sleep control */ + int *ext_control_gpio; }; static int get_ramp_delay(int ramp_delay) @@ -409,6 +412,8 @@ static int s2mps14_regulator_enable(struct regulator_dev *rdev) if (s2mps11->s2mps14_suspend_state & (1 << rdev_get_id(rdev))) val = S2MPS14_ENABLE_SUSPEND; + else if (s2mps11->ext_control_gpio[rdev_get_id(rdev)]) + val = S2MPS14_ENABLE_EXT_CONTROL; else val = rdev->desc->enable_mask; @@ -565,12 +570,63 @@ static const struct regulator_desc s2mps14_regulators[] = { regulator_desc_s2mps14_buck1235(5), }; +static int s2mps14_pmic_enable_ext_control(struct s2mps11_info *s2mps11, + struct regulator_dev *rdev) +{ + return regmap_update_bits(rdev->regmap, rdev->desc->enable_reg, + rdev->desc->enable_mask, S2MPS14_ENABLE_EXT_CONTROL); +} + +static void s2mps14_pmic_dt_parse_ext_control_gpio(struct platform_device *pdev, + struct of_regulator_match *rdata, struct s2mps11_info *s2mps11) +{ + int *gpio = s2mps11->ext_control_gpio; + unsigned int i; + unsigned int valid_regulators[3] = { S2MPS14_LDO10, S2MPS14_LDO11, + S2MPS14_LDO12 }; + + for (i = 0; i < ARRAY_SIZE(valid_regulators); i++) { + unsigned int reg = valid_regulators[i]; + + if (!rdata[reg].init_data || !rdata[reg].of_node) + continue; + + gpio[reg] = of_get_named_gpio(rdata[reg].of_node, + "samsung,ext-control-gpios", 0); + if (!gpio_is_valid(gpio[reg])) + gpio[reg] = 0; + else + dev_dbg(&pdev->dev, "Using GPIO %d for ext-control over %d/%s\n", + gpio[reg], reg, rdata[reg].name); + } +} + +static int s2mps11_pmic_dt_parse(struct platform_device *pdev, + struct of_regulator_match *rdata, struct s2mps11_info *s2mps11, + enum sec_device_type dev_type) +{ + struct device_node *reg_np; + + reg_np = of_get_child_by_name(pdev->dev.parent->of_node, "regulators"); + if (!reg_np) { + dev_err(&pdev->dev, "could not find regulators sub-node\n"); + return -EINVAL; + } + + of_regulator_match(&pdev->dev, reg_np, rdata, s2mps11->rdev_num); + if (dev_type == S2MPS14X) + s2mps14_pmic_dt_parse_ext_control_gpio(pdev, rdata, s2mps11); + + of_node_put(reg_np); + + return 0; +} + static int s2mps11_pmic_probe(struct platform_device *pdev) { struct sec_pmic_dev *iodev = dev_get_drvdata(pdev->dev.parent); - struct sec_platform_data *pdata = iodev->pdata; + struct sec_platform_data *pdata = NULL; struct of_regulator_match *rdata = NULL; - struct device_node *reg_np = NULL; struct regulator_config config = { }; struct s2mps11_info *s2mps11; int i, ret = 0; @@ -597,8 +653,15 @@ static int s2mps11_pmic_probe(struct platform_device *pdev) return -EINVAL; }; + s2mps11->ext_control_gpio = devm_kzalloc(&pdev->dev, + sizeof(*s2mps11->ext_control_gpio) * s2mps11->rdev_num, + GFP_KERNEL); + if (!s2mps11->ext_control_gpio) + return -ENOMEM; + if (!iodev->dev->of_node) { - if (pdata) { + if (iodev->pdata) { + pdata = iodev->pdata; goto common_reg; } else { dev_err(pdev->dev.parent, @@ -614,15 +677,9 @@ static int s2mps11_pmic_probe(struct platform_device *pdev) for (i = 0; i < s2mps11->rdev_num; i++) rdata[i].name = regulators[i].name; - reg_np = of_get_child_by_name(iodev->dev->of_node, "regulators"); - if (!reg_np) { - dev_err(&pdev->dev, "could not find regulators sub-node\n"); - ret = -EINVAL; + ret = s2mps11_pmic_dt_parse(pdev, rdata, s2mps11, dev_type); + if (ret) goto out; - } - - of_regulator_match(&pdev->dev, reg_np, rdata, s2mps11->rdev_num); - of_node_put(reg_np); common_reg: platform_set_drvdata(pdev, s2mps11); @@ -633,7 +690,7 @@ common_reg: for (i = 0; i < s2mps11->rdev_num; i++) { struct regulator_dev *regulator; - if (!reg_np) { + if (pdata) { config.init_data = pdata->regulators[i].initdata; config.of_node = pdata->regulators[i].reg_node; } else { @@ -641,6 +698,12 @@ common_reg: config.of_node = rdata[i].of_node; } + if (s2mps11->ext_control_gpio[i]) { + config.ena_gpio = s2mps11->ext_control_gpio[i]; + config.ena_gpio_flags = GPIOF_OUT_INIT_HIGH; + } else + config.ena_gpio = config.ena_gpio_flags = 0; + regulator = devm_regulator_register(&pdev->dev, ®ulators[i], &config); if (IS_ERR(regulator)) { @@ -649,6 +712,17 @@ common_reg: i); goto out; } + + if (s2mps11->ext_control_gpio[i]) { + ret = s2mps14_pmic_enable_ext_control(s2mps11, + regulator); + if (ret < 0) { + dev_err(&pdev->dev, + "failed to enable GPIO control over %s: %d\n", + regulator->desc->name, ret); + goto out; + } + } } out: diff --git a/drivers/regulator/s5m8767.c b/drivers/regulator/s5m8767.c index 92f19a005dc3..5daa06626f16 100644 --- a/drivers/regulator/s5m8767.c +++ b/drivers/regulator/s5m8767.c @@ -28,7 +28,6 @@ struct s5m8767_info { struct device *dev; struct sec_pmic_dev *iodev; int num_regulators; - struct regulator_dev **rdev; struct sec_opmode_data *opmode; int ramp_delay; @@ -695,7 +694,6 @@ static int s5m8767_pmic_probe(struct platform_device *pdev) struct sec_pmic_dev *iodev = dev_get_drvdata(pdev->dev.parent); struct sec_platform_data *pdata = iodev->pdata; struct regulator_config config = { }; - struct regulator_dev **rdev; struct s5m8767_info *s5m8767; int i, ret, size, buck_init; @@ -737,11 +735,7 @@ static int s5m8767_pmic_probe(struct platform_device *pdev) return -ENOMEM; size = sizeof(struct regulator_dev *) * (S5M8767_REG_MAX - 2); - s5m8767->rdev = devm_kzalloc(&pdev->dev, size, GFP_KERNEL); - if (!s5m8767->rdev) - return -ENOMEM; - rdev = s5m8767->rdev; s5m8767->dev = &pdev->dev; s5m8767->iodev = iodev; s5m8767->num_regulators = pdata->num_regulators; @@ -938,6 +932,7 @@ static int s5m8767_pmic_probe(struct platform_device *pdev) const struct sec_voltage_desc *desc; int id = pdata->regulators[i].id; int enable_reg, enable_val; + struct regulator_dev *rdev; desc = reg_voltage_map[id]; if (desc) { @@ -969,21 +964,21 @@ static int s5m8767_pmic_probe(struct platform_device *pdev) s5m8767_regulator_config_ext_control(s5m8767, &pdata->regulators[i], &config); - rdev[i] = devm_regulator_register(&pdev->dev, ®ulators[id], + rdev = devm_regulator_register(&pdev->dev, ®ulators[id], &config); - if (IS_ERR(rdev[i])) { - ret = PTR_ERR(rdev[i]); + if (IS_ERR(rdev)) { + ret = PTR_ERR(rdev); dev_err(s5m8767->dev, "regulator init failed for %d\n", id); return ret; } if (pdata->regulators[i].ext_control_gpio) { - ret = s5m8767_enable_ext_control(s5m8767, rdev[i]); + ret = s5m8767_enable_ext_control(s5m8767, rdev); if (ret < 0) { dev_err(s5m8767->dev, "failed to enable gpio control over %s: %d\n", - rdev[i]->desc->name, ret); + rdev->desc->name, ret); return ret; } } diff --git a/drivers/regulator/tps65217-regulator.c b/drivers/regulator/tps65217-regulator.c index 10b78d2b766a..f7ed20a5a8b9 100644 --- a/drivers/regulator/tps65217-regulator.c +++ b/drivers/regulator/tps65217-regulator.c @@ -134,6 +134,7 @@ static struct regulator_ops tps65217_pmic_ldo1_ops = { .get_voltage_sel = regulator_get_voltage_sel_regmap, .set_voltage_sel = tps65217_pmic_set_voltage_sel, .list_voltage = regulator_list_voltage_table, + .map_voltage = regulator_map_voltage_ascend, }; static const struct regulator_desc regulators[] = { @@ -257,9 +258,6 @@ static int tps65217_regulator_probe(struct platform_device *pdev) pdev->name); return PTR_ERR(rdev); } - - /* Save regulator for cleanup */ - tps->rdev[i] = rdev; } return 0; } |