From 8b61a28d616a34beaa425873acd37a8b12929455 Mon Sep 17 00:00:00 2001 From: Adam Thomson Date: Thu, 6 Feb 2014 18:03:13 +0000 Subject: [PATCH 01/19] regulator: da9055: Add DT support Signed-off-by: Adam Thomson Signed-off-by: Mark Brown --- drivers/regulator/da9055-regulator.c | 69 ++++++++++++++++++++++++++-- 1 file changed, 65 insertions(+), 4 deletions(-) diff --git a/drivers/regulator/da9055-regulator.c b/drivers/regulator/da9055-regulator.c index 7f340206d329..d90f785829c4 100644 --- a/drivers/regulator/da9055-regulator.c +++ b/drivers/regulator/da9055-regulator.c @@ -19,6 +19,8 @@ #include #include #include +#include +#include #include #include @@ -446,6 +448,9 @@ static int da9055_gpio_init(struct da9055_regulator *regulator, struct da9055_regulator_info *info = regulator->info; int ret = 0; + if (!pdata) + return 0; + if (pdata->gpio_ren && pdata->gpio_ren[id]) { char name[18]; int gpio_mux = pdata->gpio_ren[id]; @@ -530,6 +535,59 @@ static inline struct da9055_regulator_info *find_regulator_info(int id) return NULL; } +#ifdef CONFIG_OF +static struct of_regulator_match da9055_reg_matches[] = { + { .name = "BUCK1", }, + { .name = "BUCK2", }, + { .name = "LDO1", }, + { .name = "LDO2", }, + { .name = "LDO3", }, + { .name = "LDO4", }, + { .name = "LDO5", }, + { .name = "LDO6", }, +}; + +static int da9055_regulator_dt_init(struct platform_device *pdev, + struct da9055_regulator *regulator, + struct regulator_config *config, + int regid) +{ + struct device_node *nproot, *np; + int ret; + + nproot = of_node_get(pdev->dev.parent->of_node); + if (!nproot) + return -ENODEV; + + np = of_find_node_by_name(nproot, "regulators"); + if (!np) + return -ENODEV; + + ret = of_regulator_match(&pdev->dev, np, &da9055_reg_matches[regid], 1); + of_node_put(nproot); + if (ret < 0) { + dev_err(&pdev->dev, "Error matching regulator: %d\n", ret); + return -ENODEV; + } + + config->init_data = da9055_reg_matches[regid].init_data; + config->of_node = da9055_reg_matches[regid].of_node; + + if (!config->of_node) + return -ENODEV; + + return 0; +} +#else +static inline da9055_regulator_dt_init(struct platform_device *pdev, + struct da9055_regulator *regulator, + struct regulator_config *config, + int regid) +{ + return -ENODEV; +} +#endif /* CONFIG_OF */ + static int da9055_regulator_probe(struct platform_device *pdev) { struct regulator_config config = { }; @@ -538,9 +596,6 @@ static int da9055_regulator_probe(struct platform_device *pdev) struct da9055_pdata *pdata = dev_get_platdata(da9055->dev); int ret, irq; - if (pdata == NULL || pdata->regulators[pdev->id] == NULL) - return -ENODEV; - regulator = devm_kzalloc(&pdev->dev, sizeof(struct da9055_regulator), GFP_KERNEL); if (!regulator) @@ -557,8 +612,14 @@ static int da9055_regulator_probe(struct platform_device *pdev) config.driver_data = regulator; config.regmap = da9055->regmap; - if (pdata && pdata->regulators) + if (pdata && pdata->regulators) { config.init_data = pdata->regulators[pdev->id]; + } else { + ret = da9055_regulator_dt_init(pdev, regulator, &config, + pdev->id); + if (ret < 0) + return ret; + } ret = da9055_gpio_init(regulator, &config, pdata, pdev->id); if (ret < 0) From dae6cdb422ba9708f152f313046dfc98a9336235 Mon Sep 17 00:00:00 2001 From: SeongJae Park Date: Wed, 12 Feb 2014 14:11:07 +0900 Subject: [PATCH 02/19] regulator: da9055: declare return type of inline function exclusively MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit da9055_regulator_dt_init does not declare return type and it cause following build warning. drivers/regulator/da9055-regulator.c:582:15: warning: return type defaults to ‘int’ [-Wreturn-type] static inline da9055_regulator_dt_init(struct platform_device *pdev, ^ Fix the warning by declare return type as int exclusively. Signed-off-by: SeongJae Park Signed-off-by: Mark Brown --- drivers/regulator/da9055-regulator.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/regulator/da9055-regulator.c b/drivers/regulator/da9055-regulator.c index d90f785829c4..3f334ea23c95 100644 --- a/drivers/regulator/da9055-regulator.c +++ b/drivers/regulator/da9055-regulator.c @@ -579,7 +579,7 @@ static int da9055_regulator_dt_init(struct platform_device *pdev, return 0; } #else -static inline da9055_regulator_dt_init(struct platform_device *pdev, +static inline int da9055_regulator_dt_init(struct platform_device *pdev, struct da9055_regulator *regulator, struct regulator_config *config, int regid) From b327bcc0accf6003fab7177790f0bcafc7a49618 Mon Sep 17 00:00:00 2001 From: Sachin Kamat Date: Fri, 14 Feb 2014 17:19:56 +0530 Subject: [PATCH 03/19] regulator: da9052: Use of_get_child_by_name of_find_node_by_name walks the allnodes list, and can thus walk outside of the parent node. Use of_get_child_by_name instead. Signed-off-by: Sachin Kamat Signed-off-by: Mark Brown --- drivers/regulator/da9052-regulator.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/regulator/da9052-regulator.c b/drivers/regulator/da9052-regulator.c index 3adeaeffc485..889c7c9b9f15 100644 --- a/drivers/regulator/da9052-regulator.c +++ b/drivers/regulator/da9052-regulator.c @@ -401,7 +401,7 @@ static int da9052_regulator_probe(struct platform_device *pdev) if (!nproot) return -ENODEV; - nproot = of_find_node_by_name(nproot, "regulators"); + nproot = of_get_child_by_name(nproot, "regulators"); if (!nproot) return -ENODEV; From a4b4e66aadd05b1b8d2492ab914186359a11d0ec Mon Sep 17 00:00:00 2001 From: Sachin Kamat Date: Fri, 14 Feb 2014 17:19:57 +0530 Subject: [PATCH 04/19] regulator: da9055: Use of_get_child_by_name of_find_node_by_name walks the allnodes list, and can thus walk outside of the parent node. Use of_get_child_by_name instead. Signed-off-by: Sachin Kamat Signed-off-by: Mark Brown --- drivers/regulator/da9055-regulator.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/regulator/da9055-regulator.c b/drivers/regulator/da9055-regulator.c index 3f334ea23c95..604a6f7c9cbf 100644 --- a/drivers/regulator/da9055-regulator.c +++ b/drivers/regulator/da9055-regulator.c @@ -559,7 +559,7 @@ static int da9055_regulator_dt_init(struct platform_device *pdev, if (!nproot) return -ENODEV; - np = of_find_node_by_name(nproot, "regulators"); + np = of_get_child_by_name(nproot, "regulators"); if (!np) return -ENODEV; From 25cc275a8b5f298b28775682163a11a656d1a7eb Mon Sep 17 00:00:00 2001 From: Sachin Kamat Date: Fri, 14 Feb 2014 17:19:58 +0530 Subject: [PATCH 05/19] regulator: da9063: Use of_get_child_by_name of_find_node_by_name walks the allnodes list, and can thus walk outside of the parent node. Use of_get_child_by_name instead. Signed-off-by: Sachin Kamat Signed-off-by: Mark Brown --- drivers/regulator/da9063-regulator.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/regulator/da9063-regulator.c b/drivers/regulator/da9063-regulator.c index 56727eb745df..cee856c43d88 100644 --- a/drivers/regulator/da9063-regulator.c +++ b/drivers/regulator/da9063-regulator.c @@ -664,7 +664,7 @@ static struct da9063_regulators_pdata *da9063_parse_regulators_dt( struct device_node *node; int i, n, num; - node = of_find_node_by_name(pdev->dev.parent->of_node, "regulators"); + node = of_get_child_by_name(pdev->dev.parent->of_node, "regulators"); if (!node) { dev_err(&pdev->dev, "Regulators device node not found\n"); return ERR_PTR(-ENODEV); From 2da8215ce2ca123d9d6a33e4fda3cd154192acc8 Mon Sep 17 00:00:00 2001 From: Sachin Kamat Date: Mon, 17 Feb 2014 14:33:31 +0530 Subject: [PATCH 06/19] regulator: da9063: Add missing of_node_put Add of_node_put to decrement the ref count. Signed-off-by: Sachin Kamat Signed-off-by: Mark Brown --- drivers/regulator/da9063-regulator.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/regulator/da9063-regulator.c b/drivers/regulator/da9063-regulator.c index cee856c43d88..f5d1ca9ab7dd 100644 --- a/drivers/regulator/da9063-regulator.c +++ b/drivers/regulator/da9063-regulator.c @@ -672,6 +672,7 @@ static struct da9063_regulators_pdata *da9063_parse_regulators_dt( num = of_regulator_match(&pdev->dev, node, da9063_matches, ARRAY_SIZE(da9063_matches)); + of_node_put(node); if (num < 0) { dev_err(&pdev->dev, "Failed to match regulators\n"); return ERR_PTR(-EINVAL); From 5c99a7b1f0dd460140f229b9c5a89e6d5880aa81 Mon Sep 17 00:00:00 2001 From: Philipp Zabel Date: Thu, 6 Feb 2014 15:35:21 +0100 Subject: [PATCH 07/19] regulator: da9052: Add ramp speed information for the DVC regulators MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Some LDOs and DCDCs have a fixed ramp speed of 6.25 mV/µs. This patch adds the set_voltage_time_sel function to let consumers know about this. Signed-off-by: Philipp Zabel Signed-off-by: Mark Brown --- drivers/regulator/da9052-regulator.c | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/drivers/regulator/da9052-regulator.c b/drivers/regulator/da9052-regulator.c index 889c7c9b9f15..fdb6ea8ae7e6 100644 --- a/drivers/regulator/da9052-regulator.c +++ b/drivers/regulator/da9052-regulator.c @@ -240,6 +240,31 @@ static int da9052_regulator_set_voltage_sel(struct regulator_dev *rdev, return ret; } +static int da9052_regulator_set_voltage_time_sel(struct regulator_dev *rdev, + unsigned int old_sel, + unsigned int new_sel) +{ + struct da9052_regulator *regulator = rdev_get_drvdata(rdev); + struct da9052_regulator_info *info = regulator->info; + int id = rdev_get_id(rdev); + int ret = 0; + + /* The DVC controlled LDOs and DCDCs ramp with 6.25mV/µs after enabling + * the activate bit. + */ + switch (id) { + case DA9052_ID_BUCK1: + case DA9052_ID_BUCK2: + case DA9052_ID_BUCK3: + case DA9052_ID_LDO2: + case DA9052_ID_LDO3: + ret = (new_sel - old_sel) * info->step_uV / 6250; + break; + } + + return ret; +} + static struct regulator_ops da9052_dcdc_ops = { .get_current_limit = da9052_dcdc_get_current_limit, .set_current_limit = da9052_dcdc_set_current_limit, @@ -248,6 +273,7 @@ static struct regulator_ops da9052_dcdc_ops = { .map_voltage = da9052_map_voltage, .get_voltage_sel = regulator_get_voltage_sel_regmap, .set_voltage_sel = da9052_regulator_set_voltage_sel, + .set_voltage_time_sel = da9052_regulator_set_voltage_time_sel, .is_enabled = regulator_is_enabled_regmap, .enable = regulator_enable_regmap, .disable = regulator_disable_regmap, @@ -258,6 +284,7 @@ static struct regulator_ops da9052_ldo_ops = { .map_voltage = da9052_map_voltage, .get_voltage_sel = regulator_get_voltage_sel_regmap, .set_voltage_sel = da9052_regulator_set_voltage_sel, + .set_voltage_time_sel = da9052_regulator_set_voltage_time_sel, .is_enabled = regulator_is_enabled_regmap, .enable = regulator_enable_regmap, .disable = regulator_disable_regmap, From 8a7963d55b58aa95f45928dec229380c28d921ed Mon Sep 17 00:00:00 2001 From: Sachin Kamat Date: Tue, 18 Feb 2014 16:11:05 +0530 Subject: [PATCH 08/19] regulator: da9063: Do not hardcode return values Propagate the error values returned by the function instead. Signed-off-by: Sachin Kamat Signed-off-by: Mark Brown --- drivers/regulator/da9063-regulator.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/regulator/da9063-regulator.c b/drivers/regulator/da9063-regulator.c index f5d1ca9ab7dd..3c65644f3007 100644 --- a/drivers/regulator/da9063-regulator.c +++ b/drivers/regulator/da9063-regulator.c @@ -363,7 +363,7 @@ static int da9063_set_suspend_voltage(struct regulator_dev *rdev, int uV) sel = regulator_map_voltage_linear(rdev, uV, uV); if (sel < 0) - return -EINVAL; + return sel; sel <<= ffs(rdev->desc->vsel_mask) - 1; @@ -755,7 +755,7 @@ static int da9063_regulator_probe(struct platform_device *pdev) if (ret < 0) { dev_err(&pdev->dev, "Error while reading BUCKs configuration\n"); - return -EIO; + return ret; } bcores_merged = val & DA9063_BCORE_MERGE; bmem_bio_merged = val & DA9063_BUCK_MERGE; From fe2eb7221870ed30da06a64ddc0eac0501eb615f Mon Sep 17 00:00:00 2001 From: Sachin Kamat Date: Tue, 18 Feb 2014 16:11:06 +0530 Subject: [PATCH 09/19] regulator: da9055: Do not hardcode return value Propagate the error value returned by the function instead. Signed-off-by: Sachin Kamat Signed-off-by: Mark Brown --- drivers/regulator/da9055-regulator.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/regulator/da9055-regulator.c b/drivers/regulator/da9055-regulator.c index 604a6f7c9cbf..8812855f2b33 100644 --- a/drivers/regulator/da9055-regulator.c +++ b/drivers/regulator/da9055-regulator.c @@ -567,7 +567,7 @@ static int da9055_regulator_dt_init(struct platform_device *pdev, of_node_put(nproot); if (ret < 0) { dev_err(&pdev->dev, "Error matching regulator: %d\n", ret); - return -ENODEV; + return ret; } config->init_data = da9055_reg_matches[regid].init_data; From 8b5baa56f27369af57a755e364d02c02efed611b Mon Sep 17 00:00:00 2001 From: Sachin Kamat Date: Thu, 20 Feb 2014 14:23:01 +0530 Subject: [PATCH 10/19] regulator: da9063: Remove redundant error message kzalloc prints its own OOM message upon failure. Signed-off-by: Sachin Kamat Signed-off-by: Mark Brown --- drivers/regulator/da9063-regulator.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/drivers/regulator/da9063-regulator.c b/drivers/regulator/da9063-regulator.c index 3c65644f3007..4c09f759d05d 100644 --- a/drivers/regulator/da9063-regulator.c +++ b/drivers/regulator/da9063-regulator.c @@ -774,10 +774,8 @@ static int da9063_regulator_probe(struct platform_device *pdev) size = sizeof(struct da9063_regulators) + n_regulators * sizeof(struct da9063_regulator); regulators = devm_kzalloc(&pdev->dev, size, GFP_KERNEL); - if (!regulators) { - dev_err(&pdev->dev, "No memory for regulators\n"); + if (!regulators) return -ENOMEM; - } regulators->n_regulators = n_regulators; platform_set_drvdata(pdev, regulators); From 6c48acfb2affa8b2aed810bb67888e0d1720a884 Mon Sep 17 00:00:00 2001 From: Sachin Kamat Date: Thu, 20 Feb 2014 14:23:02 +0530 Subject: [PATCH 11/19] regulator: da9210: Remove redundant error message kzalloc prints its own OOM message upon failure. Signed-off-by: Sachin Kamat Signed-off-by: Mark Brown --- drivers/regulator/da9210-regulator.c | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/drivers/regulator/da9210-regulator.c b/drivers/regulator/da9210-regulator.c index 6f5ecbe1132e..7a320dd11c46 100644 --- a/drivers/regulator/da9210-regulator.c +++ b/drivers/regulator/da9210-regulator.c @@ -134,11 +134,8 @@ static int da9210_i2c_probe(struct i2c_client *i2c, int error; chip = devm_kzalloc(&i2c->dev, sizeof(struct da9210), GFP_KERNEL); - if (NULL == chip) { - dev_err(&i2c->dev, - "Cannot kzalloc memory for regulator structure\n"); + if (!chip) return -ENOMEM; - } chip->regmap = devm_regmap_init_i2c(i2c, &da9210_regmap_config); if (IS_ERR(chip->regmap)) { From cb487c5c0ed3da63b04d9f866fa085a88ce2d0eb Mon Sep 17 00:00:00 2001 From: Sachin Kamat Date: Thu, 20 Feb 2014 14:23:03 +0530 Subject: [PATCH 12/19] regulator: dbx500: Remove redundant error message kzalloc prints its own OOM message upon failure. Signed-off-by: Sachin Kamat Signed-off-by: Mark Brown --- drivers/regulator/dbx500-prcmu.c | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/drivers/regulator/dbx500-prcmu.c b/drivers/regulator/dbx500-prcmu.c index ce89f7848a57..f111dfb8d2d7 100644 --- a/drivers/regulator/dbx500-prcmu.c +++ b/drivers/regulator/dbx500-prcmu.c @@ -202,18 +202,12 @@ ux500_regulator_debug_init(struct platform_device *pdev, rdebug.num_regulators = num_regulators; rdebug.state_before_suspend = kzalloc(num_regulators, GFP_KERNEL); - if (!rdebug.state_before_suspend) { - dev_err(&pdev->dev, - "could not allocate memory for saving state\n"); + if (!rdebug.state_before_suspend) goto exit_destroy_power_state; - } rdebug.state_after_suspend = kzalloc(num_regulators, GFP_KERNEL); - if (!rdebug.state_after_suspend) { - dev_err(&pdev->dev, - "could not allocate memory for saving state\n"); + if (!rdebug.state_after_suspend) goto exit_free; - } dbx500_regulator_testcase(regulator_info, num_regulators); return 0; From 462c9fc5cb1daa30ebcb50d3a5341af3e0941a42 Mon Sep 17 00:00:00 2001 From: Matt Porter Date: Tue, 11 Mar 2014 11:46:13 -0400 Subject: [PATCH 13/19] regulator: add bcm590xx regulator driver Add a regulator driver for the BCM590xx PMU voltage regulators. The driver supports LDOs and DCDCs in normal mode only. There is no support for low-power mode or power sequencing. Signed-off-by: Matt Porter Reviewed-by: Tim Kryger Reviewed-by: Markus Mayer Signed-off-by: Mark Brown --- drivers/regulator/Kconfig | 8 + drivers/regulator/Makefile | 1 + drivers/regulator/bcm590xx-regulator.c | 413 +++++++++++++++++++++++++ 3 files changed, 422 insertions(+) create mode 100644 drivers/regulator/bcm590xx-regulator.c diff --git a/drivers/regulator/Kconfig b/drivers/regulator/Kconfig index 6a7932822e37..1169a42519d5 100644 --- a/drivers/regulator/Kconfig +++ b/drivers/regulator/Kconfig @@ -139,6 +139,14 @@ config REGULATOR_AS3722 AS3722 PMIC. This will enable support for all the software controllable DCDC/LDO regulators. +config REGULATOR_BCM590XX + tristate "Broadcom BCM590xx PMU Regulators" + depends on MFD_BCM590XX + help + This driver provides support for the voltage regulators on the + BCM590xx PMUs. This will enable support for the software + controllable LDO/Switching regulators. + config REGULATOR_DA903X tristate "Dialog Semiconductor DA9030/DA9034 regulators" depends on PMIC_DA903X diff --git a/drivers/regulator/Makefile b/drivers/regulator/Makefile index 979f9ddcf259..e1ab514f03c5 100644 --- a/drivers/regulator/Makefile +++ b/drivers/regulator/Makefile @@ -20,6 +20,7 @@ obj-$(CONFIG_REGULATOR_ANATOP) += anatop-regulator.o obj-$(CONFIG_REGULATOR_ARIZONA) += arizona-micsupp.o arizona-ldo1.o obj-$(CONFIG_REGULATOR_AS3711) += as3711-regulator.o obj-$(CONFIG_REGULATOR_AS3722) += as3722-regulator.o +obj-$(CONFIG_REGULATOR_BCM590XX) += bcm590xx-regulator.o obj-$(CONFIG_REGULATOR_DA903X) += da903x.o obj-$(CONFIG_REGULATOR_DA9052) += da9052-regulator.o obj-$(CONFIG_REGULATOR_DA9055) += da9055-regulator.o diff --git a/drivers/regulator/bcm590xx-regulator.c b/drivers/regulator/bcm590xx-regulator.c new file mode 100644 index 000000000000..e6b2e8e08c41 --- /dev/null +++ b/drivers/regulator/bcm590xx-regulator.c @@ -0,0 +1,413 @@ +/* + * Broadcom BCM590xx regulator driver + * + * Copyright 2014 Linaro Limited + * Author: Matt Porter + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* Register defs */ +#define BCM590XX_RFLDOPMCTRL1 0x60 +#define BCM590XX_IOSR1PMCTRL1 0x7a +#define BCM590XX_IOSR2PMCTRL1 0x7c +#define BCM590XX_CSRPMCTRL1 0x7e +#define BCM590XX_SDSR1PMCTRL1 0x82 +#define BCM590XX_SDSR2PMCTRL1 0x86 +#define BCM590XX_MSRPMCTRL1 0x8a +#define BCM590XX_VSRPMCTRL1 0x8e +#define BCM590XX_REG_ENABLE BIT(7) + +#define BCM590XX_RFLDOCTRL 0x96 +#define BCM590XX_CSRVOUT1 0xc0 +#define BCM590XX_LDO_VSEL_MASK GENMASK(5, 3) +#define BCM590XX_SR_VSEL_MASK GENMASK(5, 0) + +/* LDO regulator IDs */ +#define BCM590XX_REG_RFLDO 0 +#define BCM590XX_REG_CAMLDO1 1 +#define BCM590XX_REG_CAMLDO2 2 +#define BCM590XX_REG_SIMLDO1 3 +#define BCM590XX_REG_SIMLDO2 4 +#define BCM590XX_REG_SDLDO 5 +#define BCM590XX_REG_SDXLDO 6 +#define BCM590XX_REG_MMCLDO1 7 +#define BCM590XX_REG_MMCLDO2 8 +#define BCM590XX_REG_AUDLDO 9 +#define BCM590XX_REG_MICLDO 10 +#define BCM590XX_REG_USBLDO 11 +#define BCM590XX_REG_VIBLDO 12 + +/* DCDC regulator IDs */ +#define BCM590XX_REG_CSR 13 +#define BCM590XX_REG_IOSR1 14 +#define BCM590XX_REG_IOSR2 15 +#define BCM590XX_REG_MSR 16 +#define BCM590XX_REG_SDSR1 17 +#define BCM590XX_REG_SDSR2 18 +#define BCM590XX_REG_VSR 19 + +#define BCM590XX_NUM_REGS 20 + +#define BCM590XX_REG_IS_LDO(n) (n < BCM590XX_REG_CSR) + +struct bcm590xx_board { + struct regulator_init_data *bcm590xx_pmu_init_data[BCM590XX_NUM_REGS]; +}; + +/* LDO group A: supported voltages in microvolts */ +static const unsigned int ldo_a_table[] = { + 1200000, 1800000, 2500000, 2700000, 2800000, + 2900000, 3000000, 3300000, +}; + +/* LDO group C: supported voltages in microvolts */ +static const unsigned int ldo_c_table[] = { + 3100000, 1800000, 2500000, 2700000, 2800000, + 2900000, 3000000, 3300000, +}; + +/* DCDC group CSR: supported voltages in microvolts */ +static const struct regulator_linear_range dcdc_csr_ranges[] = { + REGULATOR_LINEAR_RANGE(860000, 2, 50, 10000), + REGULATOR_LINEAR_RANGE(1360000, 51, 55, 20000), + REGULATOR_LINEAR_RANGE(900000, 56, 63, 0), +}; + +/* DCDC group IOSR1: supported voltages in microvolts */ +static const struct regulator_linear_range dcdc_iosr1_ranges[] = { + REGULATOR_LINEAR_RANGE(860000, 2, 51, 10000), + REGULATOR_LINEAR_RANGE(1500000, 52, 52, 0), + REGULATOR_LINEAR_RANGE(1800000, 53, 53, 0), + REGULATOR_LINEAR_RANGE(900000, 54, 63, 0), +}; + +/* DCDC group SDSR1: supported voltages in microvolts */ +static const struct regulator_linear_range dcdc_sdsr1_ranges[] = { + REGULATOR_LINEAR_RANGE(860000, 2, 50, 10000), + REGULATOR_LINEAR_RANGE(1340000, 51, 51, 0), + REGULATOR_LINEAR_RANGE(900000, 52, 63, 0), +}; + +struct bcm590xx_info { + const char *name; + const char *vin_name; + u8 n_voltages; + const unsigned int *volt_table; + u8 n_linear_ranges; + const struct regulator_linear_range *linear_ranges; +}; + +#define BCM590XX_REG_TABLE(_name, _table) \ + { \ + .name = #_name, \ + .n_voltages = ARRAY_SIZE(_table), \ + .volt_table = _table, \ + } + +#define BCM590XX_REG_RANGES(_name, _ranges) \ + { \ + .name = #_name, \ + .n_linear_ranges = ARRAY_SIZE(_ranges), \ + .linear_ranges = _ranges, \ + } + +static struct bcm590xx_info bcm590xx_regs[] = { + BCM590XX_REG_TABLE(rfldo, ldo_a_table), + BCM590XX_REG_TABLE(camldo1, ldo_c_table), + BCM590XX_REG_TABLE(camldo2, ldo_c_table), + BCM590XX_REG_TABLE(simldo1, ldo_a_table), + BCM590XX_REG_TABLE(simldo2, ldo_a_table), + BCM590XX_REG_TABLE(sdldo, ldo_c_table), + BCM590XX_REG_TABLE(sdxldo, ldo_a_table), + BCM590XX_REG_TABLE(mmcldo1, ldo_a_table), + BCM590XX_REG_TABLE(mmcldo2, ldo_a_table), + BCM590XX_REG_TABLE(audldo, ldo_a_table), + BCM590XX_REG_TABLE(micldo, ldo_a_table), + BCM590XX_REG_TABLE(usbldo, ldo_a_table), + BCM590XX_REG_TABLE(vibldo, ldo_c_table), + BCM590XX_REG_RANGES(csr, dcdc_csr_ranges), + BCM590XX_REG_RANGES(iosr1, dcdc_iosr1_ranges), + BCM590XX_REG_RANGES(iosr2, dcdc_iosr1_ranges), + BCM590XX_REG_RANGES(msr, dcdc_iosr1_ranges), + BCM590XX_REG_RANGES(sdsr1, dcdc_sdsr1_ranges), + BCM590XX_REG_RANGES(sdsr2, dcdc_iosr1_ranges), + BCM590XX_REG_RANGES(vsr, dcdc_iosr1_ranges), +}; + +struct bcm590xx_reg { + struct regulator_desc *desc; + struct bcm590xx *mfd; + struct regulator_dev **rdev; + struct bcm590xx_info **info; +}; + +static int bcm590xx_get_vsel_register(int id) +{ + if (BCM590XX_REG_IS_LDO(id)) + return BCM590XX_RFLDOCTRL + id; + else + return BCM590XX_CSRVOUT1 + (id - BCM590XX_REG_CSR) * 3; +} + +static int bcm590xx_get_enable_register(int id) +{ + int reg = 0; + + if (BCM590XX_REG_IS_LDO(id)) + reg = BCM590XX_RFLDOPMCTRL1 + id * 2; + else + switch (id) { + case BCM590XX_REG_CSR: + reg = BCM590XX_CSRPMCTRL1; + break; + case BCM590XX_REG_IOSR1: + reg = BCM590XX_IOSR1PMCTRL1; + break; + case BCM590XX_REG_IOSR2: + reg = BCM590XX_IOSR2PMCTRL1; + break; + case BCM590XX_REG_MSR: + reg = BCM590XX_MSRPMCTRL1; + break; + case BCM590XX_REG_SDSR1: + reg = BCM590XX_SDSR1PMCTRL1; + break; + case BCM590XX_REG_SDSR2: + reg = BCM590XX_SDSR2PMCTRL1; + break; + }; + + return reg; +} + +static struct regulator_ops bcm590xx_ops_ldo = { + .is_enabled = regulator_is_enabled_regmap, + .enable = regulator_enable_regmap, + .disable = regulator_disable_regmap, + .get_voltage_sel = regulator_get_voltage_sel_regmap, + .set_voltage_sel = regulator_set_voltage_sel_regmap, + .list_voltage = regulator_list_voltage_table, + .map_voltage = regulator_map_voltage_iterate, +}; + +static struct regulator_ops bcm590xx_ops_dcdc = { + .is_enabled = regulator_is_enabled_regmap, + .enable = regulator_enable_regmap, + .disable = regulator_disable_regmap, + .get_voltage_sel = regulator_get_voltage_sel_regmap, + .set_voltage_sel = regulator_set_voltage_sel_regmap, + .list_voltage = regulator_list_voltage_linear_range, + .map_voltage = regulator_map_voltage_linear_range, +}; + +#define BCM590XX_MATCH(_name, _id) \ + { \ + .name = #_name, \ + .driver_data = (void *)&bcm590xx_regs[BCM590XX_REG_##_id], \ + } + +static struct of_regulator_match bcm590xx_matches[] = { + BCM590XX_MATCH(rfldo, RFLDO), + BCM590XX_MATCH(camldo1, CAMLDO1), + BCM590XX_MATCH(camldo2, CAMLDO2), + BCM590XX_MATCH(simldo1, SIMLDO1), + BCM590XX_MATCH(simldo2, SIMLDO2), + BCM590XX_MATCH(sdldo, SDLDO), + BCM590XX_MATCH(sdxldo, SDXLDO), + BCM590XX_MATCH(mmcldo1, MMCLDO1), + BCM590XX_MATCH(mmcldo2, MMCLDO2), + BCM590XX_MATCH(audldo, AUDLDO), + BCM590XX_MATCH(micldo, MICLDO), + BCM590XX_MATCH(usbldo, USBLDO), + BCM590XX_MATCH(vibldo, VIBLDO), + BCM590XX_MATCH(csr, CSR), + BCM590XX_MATCH(iosr1, IOSR1), + BCM590XX_MATCH(iosr2, IOSR2), + BCM590XX_MATCH(msr, MSR), + BCM590XX_MATCH(sdsr1, SDSR1), + BCM590XX_MATCH(sdsr2, SDSR2), + BCM590XX_MATCH(vsr, VSR), +}; + +static struct bcm590xx_board *bcm590xx_parse_dt_reg_data( + struct platform_device *pdev, + struct of_regulator_match **bcm590xx_reg_matches) +{ + struct bcm590xx_board *data; + struct device_node *np = pdev->dev.parent->of_node; + struct device_node *regulators; + struct of_regulator_match *matches = bcm590xx_matches; + int count = ARRAY_SIZE(bcm590xx_matches); + int idx = 0; + int ret; + + if (!np) { + dev_err(&pdev->dev, "of node not found\n"); + return NULL; + } + + data = devm_kzalloc(&pdev->dev, sizeof(*data), GFP_KERNEL); + if (!data) { + dev_err(&pdev->dev, "failed to allocate regulator board data\n"); + return NULL; + } + + np = of_node_get(np); + regulators = of_get_child_by_name(np, "regulators"); + if (!regulators) { + dev_warn(&pdev->dev, "regulator node not found\n"); + return NULL; + } + + ret = of_regulator_match(&pdev->dev, regulators, matches, count); + of_node_put(regulators); + if (ret < 0) { + dev_err(&pdev->dev, "Error parsing regulator init data: %d\n", + ret); + return NULL; + } + + *bcm590xx_reg_matches = matches; + + for (idx = 0; idx < count; idx++) { + if (!matches[idx].init_data || !matches[idx].of_node) + continue; + + data->bcm590xx_pmu_init_data[idx] = matches[idx].init_data; + } + + return data; +} + +static int bcm590xx_probe(struct platform_device *pdev) +{ + struct bcm590xx *bcm590xx = dev_get_drvdata(pdev->dev.parent); + struct bcm590xx_board *pmu_data = NULL; + struct bcm590xx_reg *pmu; + struct regulator_config config = { }; + struct bcm590xx_info *info; + struct regulator_init_data *reg_data; + struct regulator_dev *rdev; + struct of_regulator_match *bcm590xx_reg_matches = NULL; + int i; + + pmu_data = bcm590xx_parse_dt_reg_data(pdev, + &bcm590xx_reg_matches); + + pmu = devm_kzalloc(&pdev->dev, sizeof(*pmu), GFP_KERNEL); + if (!pmu) { + dev_err(&pdev->dev, "Memory allocation failed for pmu\n"); + return -ENOMEM; + } + + pmu->mfd = bcm590xx; + + platform_set_drvdata(pdev, pmu); + + pmu->desc = devm_kzalloc(&pdev->dev, BCM590XX_NUM_REGS * + sizeof(struct regulator_desc), GFP_KERNEL); + if (!pmu->desc) { + dev_err(&pdev->dev, "Memory alloc fails for desc\n"); + return -ENOMEM; + } + + pmu->info = devm_kzalloc(&pdev->dev, BCM590XX_NUM_REGS * + sizeof(struct bcm590xx_info *), GFP_KERNEL); + if (!pmu->info) { + dev_err(&pdev->dev, "Memory alloc fails for info\n"); + return -ENOMEM; + } + + pmu->rdev = devm_kzalloc(&pdev->dev, BCM590XX_NUM_REGS * + sizeof(struct regulator_dev *), GFP_KERNEL); + if (!pmu->rdev) { + dev_err(&pdev->dev, "Memory alloc fails for rdev\n"); + return -ENOMEM; + } + + info = bcm590xx_regs; + + for (i = 0; i < BCM590XX_NUM_REGS; i++, info++) { + if (pmu_data) + reg_data = pmu_data->bcm590xx_pmu_init_data[i]; + else + reg_data = NULL; + + /* Register the regulators */ + pmu->info[i] = info; + + pmu->desc[i].name = info->name; + pmu->desc[i].supply_name = info->vin_name; + pmu->desc[i].id = i; + pmu->desc[i].volt_table = info->volt_table; + pmu->desc[i].n_voltages = info->n_voltages; + pmu->desc[i].linear_ranges = info->linear_ranges; + pmu->desc[i].n_linear_ranges = info->n_linear_ranges; + + if (BCM590XX_REG_IS_LDO(i)) { + pmu->desc[i].ops = &bcm590xx_ops_ldo; + pmu->desc[i].vsel_mask = BCM590XX_LDO_VSEL_MASK; + } else { + pmu->desc[i].ops = &bcm590xx_ops_dcdc; + pmu->desc[i].vsel_mask = BCM590XX_SR_VSEL_MASK; + } + + pmu->desc[i].vsel_reg = bcm590xx_get_vsel_register(i); + pmu->desc[i].enable_is_inverted = true; + pmu->desc[i].enable_mask = BCM590XX_REG_ENABLE; + pmu->desc[i].enable_reg = bcm590xx_get_enable_register(i); + pmu->desc[i].type = REGULATOR_VOLTAGE; + pmu->desc[i].owner = THIS_MODULE; + + config.dev = bcm590xx->dev; + config.init_data = reg_data; + config.driver_data = pmu; + config.regmap = bcm590xx->regmap; + + if (bcm590xx_reg_matches) + config.of_node = bcm590xx_reg_matches[i].of_node; + + rdev = devm_regulator_register(&pdev->dev, &pmu->desc[i], + &config); + if (IS_ERR(rdev)) { + dev_err(bcm590xx->dev, + "failed to register %s regulator\n", + pdev->name); + return PTR_ERR(rdev); + } + + pmu->rdev[i] = rdev; + } + + return 0; +} + +static struct platform_driver bcm590xx_regulator_driver = { + .driver = { + .name = "bcm590xx-vregs", + .owner = THIS_MODULE, + }, + .probe = bcm590xx_probe, +}; +module_platform_driver(bcm590xx_regulator_driver); + +MODULE_AUTHOR("Matt Porter "); +MODULE_DESCRIPTION("BCM590xx voltage regulator driver"); +MODULE_LICENSE("GPL v2"); +MODULE_ALIAS("platform:bcm590xx-regulator"); From f377ed107b031fb0e67fa4a1d1096ab1c7818a84 Mon Sep 17 00:00:00 2001 From: Colin Ian King Date: Tue, 11 Mar 2014 11:25:09 +0000 Subject: [PATCH 14/19] regulator: da9063: fix assignment of da9063_reg_matches to NULL cppcheck detected an incorrect assignment: drivers/regulator/da9063-regulator.c:711]: (warning) Assignment of function parameter has no effect outside the function the original code didn't do anything, instead, *da9063_reg_matches needs to be set to NULL. Signed-off-by: Colin Ian King Signed-off-by: Mark Brown --- drivers/regulator/da9063-regulator.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/regulator/da9063-regulator.c b/drivers/regulator/da9063-regulator.c index 4c09f759d05d..6027bd5acc3e 100644 --- a/drivers/regulator/da9063-regulator.c +++ b/drivers/regulator/da9063-regulator.c @@ -709,7 +709,7 @@ static struct da9063_regulators_pdata *da9063_parse_regulators_dt( struct platform_device *pdev, struct of_regulator_match **da9063_reg_matches) { - da9063_reg_matches = NULL; + *da9063_reg_matches = NULL; return ERR_PTR(-ENODEV); } #endif From e77addc5975e935109a1530ff726d7b42b43392b Mon Sep 17 00:00:00 2001 From: Sachin Kamat Date: Tue, 18 Mar 2014 15:53:01 +0530 Subject: [PATCH 15/19] regulator: dbx500-prcmu: Silence checkpatch warnings Silences the following warning type: WARNING: Missing a blank line after declarations Signed-off-by: Sachin Kamat Signed-off-by: Mark Brown --- drivers/regulator/dbx500-prcmu.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/regulator/dbx500-prcmu.c b/drivers/regulator/dbx500-prcmu.c index f111dfb8d2d7..538478883ae2 100644 --- a/drivers/regulator/dbx500-prcmu.c +++ b/drivers/regulator/dbx500-prcmu.c @@ -78,6 +78,7 @@ static struct ux500_regulator_debug { void ux500_regulator_suspend_debug(void) { int i; + for (i = 0; i < rdebug.num_regulators; i++) rdebug.state_before_suspend[i] = rdebug.regulator_array[i].is_enabled; @@ -86,6 +87,7 @@ void ux500_regulator_suspend_debug(void) void ux500_regulator_resume_debug(void) { int i; + for (i = 0; i < rdebug.num_regulators; i++) rdebug.state_after_suspend[i] = rdebug.regulator_array[i].is_enabled; From 80c48e72f831bbfea4bf58d8e78ff2b18c90ec17 Mon Sep 17 00:00:00 2001 From: Jingoo Han Date: Wed, 19 Mar 2014 09:26:17 +0900 Subject: [PATCH 16/19] regulator: dbx500: use seq_puts() instead of seq_printf() For a constant format without additional arguments, use seq_puts() instead of seq_printf(). Also, it fixes the following checkpatch warning. WARNING: Prefer seq_puts to seq_printf Signed-off-by: Jingoo Han Signed-off-by: Mark Brown --- drivers/regulator/dbx500-prcmu.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/regulator/dbx500-prcmu.c b/drivers/regulator/dbx500-prcmu.c index 538478883ae2..2d16b9f16de7 100644 --- a/drivers/regulator/dbx500-prcmu.c +++ b/drivers/regulator/dbx500-prcmu.c @@ -129,9 +129,9 @@ static int ux500_regulator_status_print(struct seq_file *s, void *p) int i; /* print dump header */ - err = seq_printf(s, "ux500-regulator status:\n"); + err = seq_puts(s, "ux500-regulator status:\n"); if (err < 0) - dev_err(dev, "seq_printf overflow\n"); + dev_err(dev, "seq_puts overflow\n"); err = seq_printf(s, "%31s : %8s : %8s\n", "current", "before", "after"); From eced9d5e93d560443773b305e897c3698a21f1fa Mon Sep 17 00:00:00 2001 From: Ulf Hansson Date: Fri, 21 Mar 2014 13:14:11 +0100 Subject: [PATCH 17/19] regulator: db8500-prcmu: Set 1.8V as a fixed voltage for vsmps2 This regulator is used for system IO and is fixed to 1.8V. Let's give consumers the option to fetch the voltage level. Signed-off-by: Ulf Hansson Signed-off-by: Mark Brown --- drivers/regulator/db8500-prcmu.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/regulator/db8500-prcmu.c b/drivers/regulator/db8500-prcmu.c index 846acf240e48..617c1adca816 100644 --- a/drivers/regulator/db8500-prcmu.c +++ b/drivers/regulator/db8500-prcmu.c @@ -263,6 +263,8 @@ dbx500_regulator_info[DB8500_NUM_REGULATORS] = { .ops = &db8500_regulator_ops, .type = REGULATOR_VOLTAGE, .owner = THIS_MODULE, + .fixed_uV = 1800000, + .n_voltages = 1, }, .exclude_from_power_state = true, }, From c93474316d3a4bcdf23dde5d1b87577146dcec99 Mon Sep 17 00:00:00 2001 From: Axel Lin Date: Fri, 14 Mar 2014 09:57:54 +0800 Subject: [PATCH 18/19] regulator: bcm590xx: Make the modalias matches the driver name Signed-off-by: Axel Lin Signed-off-by: Mark Brown --- drivers/regulator/bcm590xx-regulator.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/regulator/bcm590xx-regulator.c b/drivers/regulator/bcm590xx-regulator.c index e6b2e8e08c41..d12d6d62ffa7 100644 --- a/drivers/regulator/bcm590xx-regulator.c +++ b/drivers/regulator/bcm590xx-regulator.c @@ -410,4 +410,4 @@ module_platform_driver(bcm590xx_regulator_driver); MODULE_AUTHOR("Matt Porter "); MODULE_DESCRIPTION("BCM590xx voltage regulator driver"); MODULE_LICENSE("GPL v2"); -MODULE_ALIAS("platform:bcm590xx-regulator"); +MODULE_ALIAS("platform:bcm590xx-vregs"); From 89ad288961c958dea7928ae4759ed00cc6ce5b3d Mon Sep 17 00:00:00 2001 From: Axel Lin Date: Fri, 14 Mar 2014 09:59:07 +0800 Subject: [PATCH 19/19] regulator: bcm590xx: Remove **rdev from struct bcm590xx_reg The **rdev of 'struct bcm590xx_reg' isn't used anywhere in the driver so remove it. Signed-off-by: Axel Lin Acked-by: Matt Porter Signed-off-by: Mark Brown --- drivers/regulator/bcm590xx-regulator.c | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/drivers/regulator/bcm590xx-regulator.c b/drivers/regulator/bcm590xx-regulator.c index d12d6d62ffa7..ab08ca7cfb08 100644 --- a/drivers/regulator/bcm590xx-regulator.c +++ b/drivers/regulator/bcm590xx-regulator.c @@ -153,7 +153,6 @@ static struct bcm590xx_info bcm590xx_regs[] = { struct bcm590xx_reg { struct regulator_desc *desc; struct bcm590xx *mfd; - struct regulator_dev **rdev; struct bcm590xx_info **info; }; @@ -334,13 +333,6 @@ static int bcm590xx_probe(struct platform_device *pdev) return -ENOMEM; } - pmu->rdev = devm_kzalloc(&pdev->dev, BCM590XX_NUM_REGS * - sizeof(struct regulator_dev *), GFP_KERNEL); - if (!pmu->rdev) { - dev_err(&pdev->dev, "Memory alloc fails for rdev\n"); - return -ENOMEM; - } - info = bcm590xx_regs; for (i = 0; i < BCM590XX_NUM_REGS; i++, info++) { @@ -391,8 +383,6 @@ static int bcm590xx_probe(struct platform_device *pdev) pdev->name); return PTR_ERR(rdev); } - - pmu->rdev[i] = rdev; } return 0;