From 94d33c02c7186b69849c292e1216a08ad1c0d99d Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Tue, 2 Jul 2013 22:52:41 +0100 Subject: regulator: core: Add helpers for multiple linear ranges Many regulators have several linear ranges of selector with different step sizes, for example offering better resolution at lower voltages. Provide regulator_{map,list}_voltage_linear_range() allowing these regulators to use generic code. To do so a table of regulator_linear_range structs needs to be pointed to from the descriptor. This was inspired by similar code included in a driver submission from Chao Xie and Yi Zhang at Marvell. Signed-off-by: Mark Brown --- drivers/regulator/core.c | 87 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 87 insertions(+) (limited to 'drivers') diff --git a/drivers/regulator/core.c b/drivers/regulator/core.c index 288c75abc190..e8604be4c66d 100644 --- a/drivers/regulator/core.c +++ b/drivers/regulator/core.c @@ -2078,6 +2078,43 @@ int regulator_list_voltage_linear(struct regulator_dev *rdev, } EXPORT_SYMBOL_GPL(regulator_list_voltage_linear); +/** + * regulator_list_voltage_linear_range - List voltages for linear ranges + * + * @rdev: Regulator device + * @selector: Selector to convert into a voltage + * + * Regulators with a series of simple linear mappings between voltages + * and selectors can set linear_ranges in the regulator descriptor and + * then use this function as their list_voltage() operation, + */ +int regulator_list_voltage_linear_range(struct regulator_dev *rdev, + unsigned int selector) +{ + const struct regulator_linear_range *range; + int i; + + if (!rdev->desc->n_linear_ranges) { + BUG_ON(!rdev->desc->n_linear_ranges); + return -EINVAL; + } + + for (i = 0; i < rdev->desc->n_linear_ranges; i++) { + range = &rdev->desc->linear_ranges[i]; + + if (!(selector >= range->min_sel && + selector <= range->max_sel)) + continue; + + selector -= range->min_sel; + + return range->min_uV + (range->uV_step * selector); + } + + return -EINVAL; +} +EXPORT_SYMBOL_GPL(regulator_list_voltage_linear_range); + /** * regulator_list_voltage_table - List voltages with table based mapping * @@ -2368,6 +2405,56 @@ int regulator_map_voltage_linear(struct regulator_dev *rdev, } EXPORT_SYMBOL_GPL(regulator_map_voltage_linear); +/** + * regulator_map_voltage_linear - map_voltage() for multiple linear ranges + * + * @rdev: Regulator to operate on + * @min_uV: Lower bound for voltage + * @max_uV: Upper bound for voltage + * + * Drivers providing linear_ranges in their descriptor can use this as + * their map_voltage() callback. + */ +int regulator_map_voltage_linear_range(struct regulator_dev *rdev, + int min_uV, int max_uV) +{ + const struct regulator_linear_range *range; + int ret = -EINVAL; + int voltage, i; + + if (!rdev->desc->n_linear_ranges) { + BUG_ON(!rdev->desc->n_linear_ranges); + return -EINVAL; + } + + for (i = 0; i < rdev->desc->n_linear_ranges; i++) { + range = &rdev->desc->linear_ranges[i]; + + if (!(min_uV <= range->max_uV && max_uV >= range->min_uV)) + continue; + + if (min_uV <= range->min_uV) + min_uV = range->min_uV; + + ret = DIV_ROUND_UP(min_uV - range->min_uV, range->uV_step); + if (ret < 0) + return ret; + + break; + } + + if (i == rdev->desc->n_linear_ranges) + return -EINVAL; + + /* Map back into a voltage to verify we're still in bounds */ + voltage = rdev->desc->ops->list_voltage(rdev, ret); + if (voltage < min_uV || voltage > max_uV) + return -EINVAL; + + return ret; +} +EXPORT_SYMBOL_GPL(regulator_map_voltage_linear_range); + static int _regulator_do_set_voltage(struct regulator_dev *rdev, int min_uV, int max_uV) { -- cgit v1.2.3 From 6692e432a9d59b55edbfdb4ed388e03c7f17e43c Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Tue, 2 Jul 2013 23:26:36 +0100 Subject: regulator: wm8400: Use linear ranges Signed-off-by: Mark Brown --- drivers/regulator/wm8400-regulator.c | 50 ++++++++++++------------------------ 1 file changed, 16 insertions(+), 34 deletions(-) (limited to 'drivers') diff --git a/drivers/regulator/wm8400-regulator.c b/drivers/regulator/wm8400-regulator.c index a09f03ee5506..2ac7e1aceb05 100644 --- a/drivers/regulator/wm8400-regulator.c +++ b/drivers/regulator/wm8400-regulator.c @@ -19,47 +19,21 @@ #include #include -static int wm8400_ldo_list_voltage(struct regulator_dev *dev, - unsigned selector) -{ - if (selector > WM8400_LDO1_VSEL_MASK) - return -EINVAL; - - if (selector < 15) - return 900000 + (selector * 50000); - else - return 1700000 + ((selector - 15) * 100000); -} - -static int wm8400_ldo_map_voltage(struct regulator_dev *dev, - int min_uV, int max_uV) -{ - u16 val; - int volt; - - if (min_uV < 900000 || min_uV > 3300000) - return -EINVAL; - - if (min_uV < 1700000) /* Steps of 50mV from 900mV; */ - val = DIV_ROUND_UP(min_uV - 900000, 50000); - else /* Steps of 100mV from 1700mV */ - val = DIV_ROUND_UP(min_uV - 1700000, 100000) + 15; - - volt = wm8400_ldo_list_voltage(dev, val); - if (volt < min_uV || volt > max_uV) - return -EINVAL; - - return val; -} +static const struct regulator_linear_range wm8400_ldo_ranges[] = { + { .min_uV = 900000, .max_uV = 1600000, .min_sel = 0, .max_sel = 14, + .uV_step = 50000 }, + { .min_uV = 1700000, .max_uV = 3300000, .min_sel = 15, .max_sel = 31, + .uV_step = 100000 }, +}; static struct regulator_ops wm8400_ldo_ops = { .is_enabled = regulator_is_enabled_regmap, .enable = regulator_enable_regmap, .disable = regulator_disable_regmap, - .list_voltage = wm8400_ldo_list_voltage, + .list_voltage = regulator_list_voltage_linear_range, .get_voltage_sel = regulator_get_voltage_sel_regmap, .set_voltage_sel = regulator_set_voltage_sel_regmap, - .map_voltage = wm8400_ldo_map_voltage, + .map_voltage = regulator_map_voltage_linear_range, }; static unsigned int wm8400_dcdc_get_mode(struct regulator_dev *dev) @@ -155,6 +129,8 @@ static struct regulator_desc regulators[] = { .enable_reg = WM8400_LDO1_CONTROL, .enable_mask = WM8400_LDO1_ENA, .n_voltages = WM8400_LDO1_VSEL_MASK + 1, + .linear_ranges = wm8400_ldo_ranges, + .n_linear_ranges = ARRAY_SIZE(wm8400_ldo_ranges), .vsel_reg = WM8400_LDO1_CONTROL, .vsel_mask = WM8400_LDO1_VSEL_MASK, .type = REGULATOR_VOLTAGE, @@ -167,6 +143,8 @@ static struct regulator_desc regulators[] = { .enable_reg = WM8400_LDO2_CONTROL, .enable_mask = WM8400_LDO2_ENA, .n_voltages = WM8400_LDO2_VSEL_MASK + 1, + .linear_ranges = wm8400_ldo_ranges, + .n_linear_ranges = ARRAY_SIZE(wm8400_ldo_ranges), .type = REGULATOR_VOLTAGE, .vsel_reg = WM8400_LDO2_CONTROL, .vsel_mask = WM8400_LDO2_VSEL_MASK, @@ -179,6 +157,8 @@ static struct regulator_desc regulators[] = { .enable_reg = WM8400_LDO3_CONTROL, .enable_mask = WM8400_LDO3_ENA, .n_voltages = WM8400_LDO3_VSEL_MASK + 1, + .linear_ranges = wm8400_ldo_ranges, + .n_linear_ranges = ARRAY_SIZE(wm8400_ldo_ranges), .vsel_reg = WM8400_LDO3_CONTROL, .vsel_mask = WM8400_LDO3_VSEL_MASK, .type = REGULATOR_VOLTAGE, @@ -191,6 +171,8 @@ static struct regulator_desc regulators[] = { .enable_reg = WM8400_LDO4_CONTROL, .enable_mask = WM8400_LDO4_ENA, .n_voltages = WM8400_LDO4_VSEL_MASK + 1, + .linear_ranges = wm8400_ldo_ranges, + .n_linear_ranges = ARRAY_SIZE(wm8400_ldo_ranges), .vsel_reg = WM8400_LDO4_CONTROL, .vsel_mask = WM8400_LDO4_VSEL_MASK, .type = REGULATOR_VOLTAGE, -- cgit v1.2.3 From 5ff26a14c333113967f3abe5fcb81c8e49d282c0 Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Tue, 2 Jul 2013 23:35:22 +0100 Subject: regulator: wm831x-ldo: Convert to use linear ranges Signed-off-by: Mark Brown --- drivers/regulator/wm831x-ldo.c | 104 ++++++++++------------------------------- 1 file changed, 24 insertions(+), 80 deletions(-) (limited to 'drivers') diff --git a/drivers/regulator/wm831x-ldo.c b/drivers/regulator/wm831x-ldo.c index 9ff883f80878..76792c7d86f3 100644 --- a/drivers/regulator/wm831x-ldo.c +++ b/drivers/regulator/wm831x-ldo.c @@ -62,41 +62,12 @@ static irqreturn_t wm831x_ldo_uv_irq(int irq, void *data) * General purpose LDOs */ -#define WM831X_GP_LDO_SELECTOR_LOW 0xe -#define WM831X_GP_LDO_MAX_SELECTOR 0x1f - -static int wm831x_gp_ldo_list_voltage(struct regulator_dev *rdev, - unsigned int selector) -{ - /* 0.9-1.6V in 50mV steps */ - if (selector <= WM831X_GP_LDO_SELECTOR_LOW) - return 900000 + (selector * 50000); - /* 1.7-3.3V in 100mV steps */ - if (selector <= WM831X_GP_LDO_MAX_SELECTOR) - return 1600000 + ((selector - WM831X_GP_LDO_SELECTOR_LOW) - * 100000); - return -EINVAL; -} - -static int wm831x_gp_ldo_map_voltage(struct regulator_dev *rdev, - int min_uV, int max_uV) -{ - int volt, vsel; - - if (min_uV < 900000) - vsel = 0; - else if (min_uV < 1700000) - vsel = ((min_uV - 900000) / 50000); - else - vsel = ((min_uV - 1700000) / 100000) - + WM831X_GP_LDO_SELECTOR_LOW + 1; - - volt = wm831x_gp_ldo_list_voltage(rdev, vsel); - if (volt < min_uV || volt > max_uV) - return -EINVAL; - - return vsel; -} +static const struct regulator_linear_range wm831x_gp_ldo_ranges[] = { + { .min_uV = 900000, .max_uV = 1650000, .min_sel = 0, .max_sel = 14, + .uV_step = 50000 }, + { .min_uV = 1700000, .max_uV = 3300000, .min_sel = 15, .max_sel = 31, + .uV_step = 100000 }, +}; static int wm831x_gp_ldo_set_suspend_voltage(struct regulator_dev *rdev, int uV) @@ -105,7 +76,7 @@ static int wm831x_gp_ldo_set_suspend_voltage(struct regulator_dev *rdev, struct wm831x *wm831x = ldo->wm831x; int sel, reg = ldo->base + WM831X_LDO_SLEEP_CONTROL; - sel = wm831x_gp_ldo_map_voltage(rdev, uV, uV); + sel = regulator_map_voltage_linear_range(rdev, uV, uV); if (sel < 0) return sel; @@ -230,8 +201,8 @@ static unsigned int wm831x_gp_ldo_get_optimum_mode(struct regulator_dev *rdev, static struct regulator_ops wm831x_gp_ldo_ops = { - .list_voltage = wm831x_gp_ldo_list_voltage, - .map_voltage = wm831x_gp_ldo_map_voltage, + .list_voltage = regulator_list_voltage_linear_range, + .map_voltage = regulator_map_voltage_linear_range, .get_voltage_sel = regulator_get_voltage_sel_regmap, .set_voltage_sel = regulator_set_voltage_sel_regmap, .set_suspend_voltage = wm831x_gp_ldo_set_suspend_voltage, @@ -290,7 +261,7 @@ static int wm831x_gp_ldo_probe(struct platform_device *pdev) ldo->desc.id = id; ldo->desc.type = REGULATOR_VOLTAGE; - ldo->desc.n_voltages = WM831X_GP_LDO_MAX_SELECTOR + 1; + ldo->desc.n_voltages = 32; ldo->desc.ops = &wm831x_gp_ldo_ops; ldo->desc.owner = THIS_MODULE; ldo->desc.vsel_reg = ldo->base + WM831X_LDO_ON_CONTROL; @@ -299,6 +270,8 @@ static int wm831x_gp_ldo_probe(struct platform_device *pdev) ldo->desc.enable_mask = 1 << id; ldo->desc.bypass_reg = ldo->base; ldo->desc.bypass_mask = WM831X_LDO1_SWI; + ldo->desc.linear_ranges = wm831x_gp_ldo_ranges; + ldo->desc.n_linear_ranges = ARRAY_SIZE(wm831x_gp_ldo_ranges); config.dev = pdev->dev.parent; if (pdata) @@ -358,43 +331,12 @@ static struct platform_driver wm831x_gp_ldo_driver = { * Analogue LDOs */ - -#define WM831X_ALDO_SELECTOR_LOW 0xc -#define WM831X_ALDO_MAX_SELECTOR 0x1f - -static int wm831x_aldo_list_voltage(struct regulator_dev *rdev, - unsigned int selector) -{ - /* 1-1.6V in 50mV steps */ - if (selector <= WM831X_ALDO_SELECTOR_LOW) - return 1000000 + (selector * 50000); - /* 1.7-3.5V in 100mV steps */ - if (selector <= WM831X_ALDO_MAX_SELECTOR) - return 1600000 + ((selector - WM831X_ALDO_SELECTOR_LOW) - * 100000); - return -EINVAL; -} - -static int wm831x_aldo_map_voltage(struct regulator_dev *rdev, - int min_uV, int max_uV) -{ - int volt, vsel; - - if (min_uV < 1000000) - vsel = 0; - else if (min_uV < 1700000) - vsel = ((min_uV - 1000000) / 50000); - else - vsel = ((min_uV - 1700000) / 100000) - + WM831X_ALDO_SELECTOR_LOW + 1; - - volt = wm831x_aldo_list_voltage(rdev, vsel); - if (volt < min_uV || volt > max_uV) - return -EINVAL; - - return vsel; - -} +static const struct regulator_linear_range wm831x_aldo_ranges[] = { + { .min_uV = 1000000, .max_uV = 1650000, .min_sel = 0, .max_sel = 12, + .uV_step = 50000 }, + { .min_uV = 1700000, .max_uV = 3500000, .min_sel = 13, .max_sel = 31, + .uV_step = 100000 }, +}; static int wm831x_aldo_set_suspend_voltage(struct regulator_dev *rdev, int uV) @@ -403,7 +345,7 @@ static int wm831x_aldo_set_suspend_voltage(struct regulator_dev *rdev, struct wm831x *wm831x = ldo->wm831x; int sel, reg = ldo->base + WM831X_LDO_SLEEP_CONTROL; - sel = wm831x_aldo_map_voltage(rdev, uV, uV); + sel = regulator_map_voltage_linear_range(rdev, uV, uV); if (sel < 0) return sel; @@ -486,8 +428,8 @@ static int wm831x_aldo_get_status(struct regulator_dev *rdev) } static struct regulator_ops wm831x_aldo_ops = { - .list_voltage = wm831x_aldo_list_voltage, - .map_voltage = wm831x_aldo_map_voltage, + .list_voltage = regulator_list_voltage_linear_range, + .map_voltage = regulator_map_voltage_linear_range, .get_voltage_sel = regulator_get_voltage_sel_regmap, .set_voltage_sel = regulator_set_voltage_sel_regmap, .set_suspend_voltage = wm831x_aldo_set_suspend_voltage, @@ -545,7 +487,9 @@ static int wm831x_aldo_probe(struct platform_device *pdev) ldo->desc.id = id; ldo->desc.type = REGULATOR_VOLTAGE; - ldo->desc.n_voltages = WM831X_ALDO_MAX_SELECTOR + 1; + ldo->desc.n_voltages = 32; + ldo->desc.linear_ranges = wm831x_aldo_ranges; + ldo->desc.n_linear_ranges = ARRAY_SIZE(wm831x_aldo_ranges); ldo->desc.ops = &wm831x_aldo_ops; ldo->desc.owner = THIS_MODULE; ldo->desc.vsel_reg = ldo->base + WM831X_LDO_ON_CONTROL; -- cgit v1.2.3 From c36a1cdf96dd3a4e6b612d6847bff6c7086e358b Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Tue, 2 Jul 2013 23:35:42 +0100 Subject: regulator: wm8350: Convert to use linear ranges Signed-off-by: Mark Brown --- drivers/regulator/wm8350-regulator.c | 55 +++++++++++------------------------- 1 file changed, 17 insertions(+), 38 deletions(-) (limited to 'drivers') diff --git a/drivers/regulator/wm8350-regulator.c b/drivers/regulator/wm8350-regulator.c index 7f0fa22ef2aa..5453dd0105ed 100644 --- a/drivers/regulator/wm8350-regulator.c +++ b/drivers/regulator/wm8350-regulator.c @@ -542,41 +542,12 @@ static int wm8350_dcdc_set_suspend_mode(struct regulator_dev *rdev, return 0; } -static int wm8350_ldo_list_voltage(struct regulator_dev *rdev, - unsigned selector) -{ - if (selector > WM8350_LDO1_VSEL_MASK) - return -EINVAL; - - if (selector < 16) - return (selector * 50000) + 900000; - else - return ((selector - 16) * 100000) + 1800000; -} - -static int wm8350_ldo_map_voltage(struct regulator_dev *rdev, int min_uV, - int max_uV) -{ - int volt, sel; - int min_mV = min_uV / 1000; - int max_mV = max_uV / 1000; - - if (min_mV < 900 || min_mV > 3300) - return -EINVAL; - if (max_mV < 900 || max_mV > 3300) - return -EINVAL; - - if (min_mV < 1800) /* step size is 50mV < 1800mV */ - sel = DIV_ROUND_UP(min_uV - 900, 50); - else /* step size is 100mV > 1800mV */ - sel = DIV_ROUND_UP(min_uV - 1800, 100) + 16; - - volt = wm8350_ldo_list_voltage(rdev, sel); - if (volt < min_uV || volt > max_uV) - return -EINVAL; - - return sel; -} +static const struct regulator_linear_range wm8350_ldo_ranges[] = { + { .min_uV = 900000, .max_uV = 1750000, .min_sel = 0, .max_sel = 15, + .uV_step = 50000 }, + { .min_uV = 1800000, .max_uV = 3300000, .min_sel = 16, .max_sel = 31, + .uV_step = 100000 }, +}; static int wm8350_ldo_set_suspend_voltage(struct regulator_dev *rdev, int uV) { @@ -603,7 +574,7 @@ static int wm8350_ldo_set_suspend_voltage(struct regulator_dev *rdev, int uV) return -EINVAL; } - sel = wm8350_ldo_map_voltage(rdev, uV, uV); + sel = regulator_map_voltage_linear_range(rdev, uV, uV); if (sel < 0) return -EINVAL; @@ -998,10 +969,10 @@ static struct regulator_ops wm8350_dcdc2_5_ops = { }; static struct regulator_ops wm8350_ldo_ops = { - .map_voltage = wm8350_ldo_map_voltage, + .map_voltage = regulator_map_voltage_linear_range, .set_voltage_sel = regulator_set_voltage_sel_regmap, .get_voltage_sel = regulator_get_voltage_sel_regmap, - .list_voltage = wm8350_ldo_list_voltage, + .list_voltage = regulator_list_voltage_linear_range, .enable = regulator_enable_regmap, .disable = regulator_disable_regmap, .is_enabled = regulator_is_enabled_regmap, @@ -1108,6 +1079,8 @@ static const struct regulator_desc wm8350_reg[NUM_WM8350_REGULATORS] = { .irq = WM8350_IRQ_UV_LDO1, .type = REGULATOR_VOLTAGE, .n_voltages = WM8350_LDO1_VSEL_MASK + 1, + .linear_ranges = wm8350_ldo_ranges, + .n_linear_ranges = ARRAY_SIZE(wm8350_ldo_ranges), .vsel_reg = WM8350_LDO1_CONTROL, .vsel_mask = WM8350_LDO1_VSEL_MASK, .enable_reg = WM8350_DCDC_LDO_REQUESTED, @@ -1121,6 +1094,8 @@ static const struct regulator_desc wm8350_reg[NUM_WM8350_REGULATORS] = { .irq = WM8350_IRQ_UV_LDO2, .type = REGULATOR_VOLTAGE, .n_voltages = WM8350_LDO2_VSEL_MASK + 1, + .linear_ranges = wm8350_ldo_ranges, + .n_linear_ranges = ARRAY_SIZE(wm8350_ldo_ranges), .vsel_reg = WM8350_LDO2_CONTROL, .vsel_mask = WM8350_LDO2_VSEL_MASK, .enable_reg = WM8350_DCDC_LDO_REQUESTED, @@ -1134,6 +1109,8 @@ static const struct regulator_desc wm8350_reg[NUM_WM8350_REGULATORS] = { .irq = WM8350_IRQ_UV_LDO3, .type = REGULATOR_VOLTAGE, .n_voltages = WM8350_LDO3_VSEL_MASK + 1, + .linear_ranges = wm8350_ldo_ranges, + .n_linear_ranges = ARRAY_SIZE(wm8350_ldo_ranges), .vsel_reg = WM8350_LDO3_CONTROL, .vsel_mask = WM8350_LDO3_VSEL_MASK, .enable_reg = WM8350_DCDC_LDO_REQUESTED, @@ -1147,6 +1124,8 @@ static const struct regulator_desc wm8350_reg[NUM_WM8350_REGULATORS] = { .irq = WM8350_IRQ_UV_LDO4, .type = REGULATOR_VOLTAGE, .n_voltages = WM8350_LDO4_VSEL_MASK + 1, + .linear_ranges = wm8350_ldo_ranges, + .n_linear_ranges = ARRAY_SIZE(wm8350_ldo_ranges), .vsel_reg = WM8350_LDO4_CONTROL, .vsel_mask = WM8350_LDO4_VSEL_MASK, .enable_reg = WM8350_DCDC_LDO_REQUESTED, -- cgit v1.2.3 From 82b736df4da2c6fdf2c0018938685cf36d112ecd Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Fri, 5 Jul 2013 20:45:22 +0100 Subject: regulator: build: Sort Kconfig Reduces merge issues if nothing else. Signed-off-by: Mark Brown --- drivers/regulator/Kconfig | 244 ++++++++++++++++++++++----------------------- drivers/regulator/Makefile | 2 +- 2 files changed, 123 insertions(+), 123 deletions(-) (limited to 'drivers') diff --git a/drivers/regulator/Kconfig b/drivers/regulator/Kconfig index f1e6ad98eeba..759b601b54ef 100644 --- a/drivers/regulator/Kconfig +++ b/drivers/regulator/Kconfig @@ -64,15 +64,11 @@ config REGULATOR_USERSPACE_CONSUMER If unsure, say no. -config REGULATOR_GPIO - tristate "GPIO regulator support" - depends on GPIOLIB +config REGULATOR_88PM8607 + bool "Marvell 88PM8607 Power regulators" + depends on MFD_88PM860X=y help - This driver provides support for regulators that can be - controlled via gpios. - It is capable of supporting current and voltage regulators - and the platform has to provide a mapping of GPIO-states - to target volts/amps. + This driver supports 88PM8607 voltage regulator chips. config REGULATOR_AD5398 tristate "Analog Devices AD5398/AD5821 regulators" @@ -81,6 +77,14 @@ config REGULATOR_AD5398 This driver supports AD5398 and AD5821 current regulator chips. If building into module, its name is ad5398.ko. +config REGULATOR_ANATOP + tristate "Freescale i.MX on-chip ANATOP LDO regulators" + depends on MFD_SYSCON + help + Say y here to support Freescale i.MX on-chip ANATOP LDOs + regulators. It is recommended that this option be + enabled on i.MX6 platform. + config REGULATOR_AAT2870 tristate "AnalogicTech AAT2870 Regulators" depends on MFD_AAT2870_CORE @@ -88,6 +92,22 @@ config REGULATOR_AAT2870 If you have a AnalogicTech AAT2870 say Y to enable the regulator driver. +config REGULATOR_AB3100 + tristate "ST-Ericsson AB3100 Regulator functions" + depends on AB3100_CORE + default y if AB3100_CORE + help + These regulators correspond to functionality in the + AB3100 analog baseband dealing with power regulators + for the system. + +config REGULATOR_AB8500 + bool "ST-Ericsson AB8500 Power Regulators" + depends on AB8500_CORE + help + This driver supports the regulators found on the ST-Ericsson mixed + signal AB8500 PMIC + config REGULATOR_ARIZONA tristate "Wolfson Arizona class devices" depends on MFD_ARIZONA @@ -96,6 +116,13 @@ config REGULATOR_ARIZONA Support for the regulators found on Wolfson Arizona class devices. +config REGULATOR_AS3711 + tristate "AS3711 PMIC" + depends on MFD_AS3711 + help + This driver provides support for the voltage regulators on the + AS3711 PMIC + config REGULATOR_DA903X tristate "Dialog Semiconductor DA9030/DA9034 regulators" depends on PMIC_DA903X @@ -120,6 +147,17 @@ config REGULATOR_DA9055 This driver can also be built as a module. If so, the module will be called da9055-regulator. +config REGULATOR_DBX500_PRCMU + bool + +config REGULATOR_DB8500_PRCMU + bool "ST-Ericsson DB8500 Voltage Domain Regulators" + depends on MFD_DB8500_PRCMU + select REGULATOR_DBX500_PRCMU + help + This driver supports the voltage domain regulators controlled by the + DB8500 PRCMU + config REGULATOR_FAN53555 tristate "Fairchild FAN53555 Regulator" depends on I2C @@ -131,44 +169,57 @@ config REGULATOR_FAN53555 input voltage supply of 2.5V to 5.5V. The output voltage is programmed through an I2C interface. -config REGULATOR_ANATOP - tristate "Freescale i.MX on-chip ANATOP LDO regulators" - depends on MFD_SYSCON +config REGULATOR_GPIO + tristate "GPIO regulator support" + depends on GPIOLIB help - Say y here to support Freescale i.MX on-chip ANATOP LDOs - regulators. It is recommended that this option be - enabled on i.MX6 platform. + This driver provides support for regulators that can be + controlled via gpios. + It is capable of supporting current and voltage regulators + and the platform has to provide a mapping of GPIO-states + to target volts/amps. -config REGULATOR_MC13XXX_CORE - tristate +config REGULATOR_ISL6271A + tristate "Intersil ISL6271A Power regulator" + depends on I2C + help + This driver supports ISL6271A voltage regulator chip. -config REGULATOR_MC13783 - tristate "Freescale MC13783 regulator driver" - depends on MFD_MC13783 - select REGULATOR_MC13XXX_CORE +config REGULATOR_LP3971 + tristate "National Semiconductors LP3971 PMIC regulator driver" + depends on I2C help - Say y here to support the regulators found on the Freescale MC13783 - PMIC. + Say Y here to support the voltage regulators and convertors + on National Semiconductors LP3971 PMIC -config REGULATOR_MC13892 - tristate "Freescale MC13892 regulator driver" - depends on MFD_MC13XXX - select REGULATOR_MC13XXX_CORE +config REGULATOR_LP3972 + tristate "National Semiconductors LP3972 PMIC regulator driver" + depends on I2C help - Say y here to support the regulators found on the Freescale MC13892 - PMIC. + Say Y here to support the voltage regulators and convertors + on National Semiconductors LP3972 PMIC -config REGULATOR_ISL6271A - tristate "Intersil ISL6271A Power regulator" +config REGULATOR_LP872X + bool "TI/National Semiconductor LP8720/LP8725 voltage regulators" + depends on I2C=y + select REGMAP_I2C + help + This driver supports LP8720/LP8725 PMIC + +config REGULATOR_LP8755 + tristate "TI LP8755 High Performance PMU driver" depends on I2C + select REGMAP_I2C help - This driver supports ISL6271A voltage regulator chip. + This driver supports LP8755 High Performance PMU driver. This + chip contains six step-down DC/DC converters which can support + 9 mode multiphase configuration. -config REGULATOR_88PM8607 - bool "Marvell 88PM8607 Power regulators" - depends on MFD_88PM860X=y +config REGULATOR_LP8788 + bool "TI LP8788 Power Regulators" + depends on MFD_LP8788 help - This driver supports 88PM8607 voltage regulator chips. + This driver supports LP8788 voltage regulator chip. config REGULATOR_MAX1586 tristate "Maxim 1586/1587 voltage regulator" @@ -259,48 +310,43 @@ config REGULATOR_MAX77693 and one current regulator 'CHARGER'. This is suitable for Exynos-4x12 chips. -config REGULATOR_PCAP - tristate "Motorola PCAP2 regulator driver" - depends on EZX_PCAP - help - This driver provides support for the voltage regulators of the - PCAP2 PMIC. +config REGULATOR_MC13XXX_CORE + tristate -config REGULATOR_LP3971 - tristate "National Semiconductors LP3971 PMIC regulator driver" - depends on I2C +config REGULATOR_MC13783 + tristate "Freescale MC13783 regulator driver" + depends on MFD_MC13783 + select REGULATOR_MC13XXX_CORE help - Say Y here to support the voltage regulators and convertors - on National Semiconductors LP3971 PMIC + Say y here to support the regulators found on the Freescale MC13783 + PMIC. -config REGULATOR_LP3972 - tristate "National Semiconductors LP3972 PMIC regulator driver" - depends on I2C +config REGULATOR_MC13892 + tristate "Freescale MC13892 regulator driver" + depends on MFD_MC13XXX + select REGULATOR_MC13XXX_CORE help - Say Y here to support the voltage regulators and convertors - on National Semiconductors LP3972 PMIC + Say y here to support the regulators found on the Freescale MC13892 + PMIC. -config REGULATOR_LP872X - bool "TI/National Semiconductor LP8720/LP8725 voltage regulators" - depends on I2C=y - select REGMAP_I2C +config REGULATOR_PALMAS + tristate "TI Palmas PMIC Regulators" + depends on MFD_PALMAS help - This driver supports LP8720/LP8725 PMIC + If you wish to control the regulators on the Palmas series of + chips say Y here. This will enable support for all the software + controllable SMPS/LDO regulators. -config REGULATOR_LP8755 - tristate "TI LP8755 High Performance PMU driver" - depends on I2C - select REGMAP_I2C - help - This driver supports LP8755 High Performance PMU driver. This - chip contains six step-down DC/DC converters which can support - 9 mode multiphase configuration. + The regulators available on Palmas series chips vary depending + on the muxing. This is handled automatically in the driver by + reading the mux info from OTP. -config REGULATOR_LP8788 - bool "TI LP8788 Power Regulators" - depends on MFD_LP8788 +config REGULATOR_PCAP + tristate "Motorola PCAP2 regulator driver" + depends on EZX_PCAP help - This driver supports LP8788 voltage regulator chip. + This driver provides support for the voltage regulators of the + PCAP2 PMIC. config REGULATOR_PCF50633 tristate "NXP PCF50633 regulator driver" @@ -335,44 +381,15 @@ config REGULATOR_S5M8767 via I2C bus. S5M8767A have 9 Bucks and 28 LDOs output and supports DVS mode with 8bits of output voltage control. -config REGULATOR_AB3100 - tristate "ST-Ericsson AB3100 Regulator functions" - depends on AB3100_CORE - default y if AB3100_CORE - help - These regulators correspond to functionality in the - AB3100 analog baseband dealing with power regulators - for the system. - -config REGULATOR_AB8500 - bool "ST-Ericsson AB8500 Power Regulators" - depends on AB8500_CORE - help - This driver supports the regulators found on the ST-Ericsson mixed - signal AB8500 PMIC - -config REGULATOR_DBX500_PRCMU - bool - -config REGULATOR_DB8500_PRCMU - bool "ST-Ericsson DB8500 Voltage Domain Regulators" - depends on MFD_DB8500_PRCMU - select REGULATOR_DBX500_PRCMU - help - This driver supports the voltage domain regulators controlled by the - DB8500 PRCMU - -config REGULATOR_PALMAS - tristate "TI Palmas PMIC Regulators" - depends on MFD_PALMAS +config REGULATOR_TI_ABB + bool "TI Adaptive Body Bias on-chip LDO" + depends on ARCH_OMAP help - If you wish to control the regulators on the Palmas series of - chips say Y here. This will enable support for all the software - controllable SMPS/LDO regulators. - - The regulators available on Palmas series chips vary depending - on the muxing. This is handled automatically in the driver by - reading the mux info from OTP. + Select this option to support Texas Instruments' on-chip Adaptive Body + Bias (ABB) LDO regulators. It is recommended that this option be + enabled on required TI SoC. Certain Operating Performance Points + on TI SoCs may be unstable without enabling this as it provides + device specific optimized bias to allow/optimize functionality. config REGULATOR_TPS51632 tristate "TI TPS51632 Power Regulator" @@ -481,16 +498,6 @@ config REGULATOR_TWL4030 This driver supports the voltage regulators provided by this family of companion chips. -config REGULATOR_TI_ABB - bool "TI Adaptive Body Bias on-chip LDO" - depends on ARCH_OMAP - help - Select this option to support Texas Instruments' on-chip Adaptive Body - Bias (ABB) LDO regulators. It is recommended that this option be - enabled on required TI SoC. Certain Operating Performance Points - on TI SoCs may be unstable without enabling this as it provides - device specific optimized bias to allow/optimize functionality. - config REGULATOR_VEXPRESS tristate "Versatile Express regulators" depends on VEXPRESS_CONFIG @@ -526,12 +533,5 @@ config REGULATOR_WM8994 This driver provides support for the voltage regulators on the WM8994 CODEC. -config REGULATOR_AS3711 - tristate "AS3711 PMIC" - depends on MFD_AS3711 - help - This driver provides support for the voltage regulators on the - AS3711 PMIC - endif diff --git a/drivers/regulator/Makefile b/drivers/regulator/Makefile index ba4a3cf3afec..d240772d90ee 100644 --- a/drivers/regulator/Makefile +++ b/drivers/regulator/Makefile @@ -52,6 +52,7 @@ obj-$(CONFIG_REGULATOR_PCF50633) += pcf50633-regulator.o obj-$(CONFIG_REGULATOR_RC5T583) += rc5t583-regulator.o obj-$(CONFIG_REGULATOR_S2MPS11) += s2mps11.o obj-$(CONFIG_REGULATOR_S5M8767) += s5m8767.o +obj-$(CONFIG_REGULATOR_TI_ABB) += ti-abb-regulator.o obj-$(CONFIG_REGULATOR_TPS6105X) += tps6105x-regulator.o obj-$(CONFIG_REGULATOR_TPS62360) += tps62360-regulator.o obj-$(CONFIG_REGULATOR_TPS65023) += tps65023-regulator.o @@ -64,7 +65,6 @@ obj-$(CONFIG_REGULATOR_TPS65910) += tps65910-regulator.o obj-$(CONFIG_REGULATOR_TPS65912) += tps65912-regulator.o obj-$(CONFIG_REGULATOR_TPS80031) += tps80031-regulator.o obj-$(CONFIG_REGULATOR_TWL4030) += twl-regulator.o -obj-$(CONFIG_REGULATOR_TI_ABB) += ti-abb-regulator.o obj-$(CONFIG_REGULATOR_VEXPRESS) += vexpress.o obj-$(CONFIG_REGULATOR_WM831X) += wm831x-dcdc.o obj-$(CONFIG_REGULATOR_WM831X) += wm831x-isink.o -- cgit v1.2.3 From a56d66a2f01b172bc00d73b0b0392423c8aaae19 Mon Sep 17 00:00:00 2001 From: Axel Lin Date: Thu, 18 Jul 2013 22:21:57 +0800 Subject: regulator: core: Allow fixed voltage range in multiple linear ranges Current code does not allow fixed voltage range in multiple linear ranges. If someone does set range->uV_step == 0 in one of the linear ranges, we hit divided by zero bug. This patch fixes this issue. For fixed voltage range, return any selector means the same voltage. Thus just return 0. Signed-off-by: Axel Lin Signed-off-by: Mark Brown --- drivers/regulator/core.c | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/regulator/core.c b/drivers/regulator/core.c index e8604be4c66d..fd3f6e003729 100644 --- a/drivers/regulator/core.c +++ b/drivers/regulator/core.c @@ -2436,9 +2436,15 @@ int regulator_map_voltage_linear_range(struct regulator_dev *rdev, if (min_uV <= range->min_uV) min_uV = range->min_uV; - ret = DIV_ROUND_UP(min_uV - range->min_uV, range->uV_step); - if (ret < 0) - return ret; + /* range->uV_step == 0 means fixed voltage range */ + if (range->uV_step == 0) { + ret = 0; + } else { + ret = DIV_ROUND_UP(min_uV - range->min_uV, + range->uV_step); + if (ret < 0) + return ret; + } break; } -- cgit v1.2.3 From 6c918d220925eeeca75b67e896eabffd061cd128 Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Thu, 18 Jul 2013 16:06:33 +0100 Subject: regulator: core: Ensure selector is mapped Clearly the testing only covered the bottom range. Signed-off-by: Mark Brown --- drivers/regulator/core.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'drivers') diff --git a/drivers/regulator/core.c b/drivers/regulator/core.c index fd3f6e003729..42ae134797e0 100644 --- a/drivers/regulator/core.c +++ b/drivers/regulator/core.c @@ -2446,6 +2446,8 @@ int regulator_map_voltage_linear_range(struct regulator_dev *rdev, return ret; } + ret += range->min_sel; + break; } -- cgit v1.2.3 From 95f1dc08c6f98a62b5dae6ed86fa04f40fb6b34f Mon Sep 17 00:00:00 2001 From: Chao Xie Date: Wed, 17 Jul 2013 23:07:03 -0400 Subject: regulator: 88pm800: add regulator driver for 88pm800 Add the regulator driver for PMIC 88pm800 including device tree support. 88pm800 is an I2C-based power-management IC containing voltage regulators, a real-time clock, and some general purpose ADC devices, Signed-off-by: Yi Zhang Signed-off-by: Chao Xie Signed-off-by: Mark Brown --- .../devicetree/bindings/regulator/88pm800.txt | 38 +++ drivers/regulator/88pm800.c | 377 +++++++++++++++++++++ drivers/regulator/Kconfig | 10 + drivers/regulator/Makefile | 1 + 4 files changed, 426 insertions(+) create mode 100644 Documentation/devicetree/bindings/regulator/88pm800.txt create mode 100644 drivers/regulator/88pm800.c (limited to 'drivers') diff --git a/Documentation/devicetree/bindings/regulator/88pm800.txt b/Documentation/devicetree/bindings/regulator/88pm800.txt new file mode 100644 index 000000000000..e8a54c2a5821 --- /dev/null +++ b/Documentation/devicetree/bindings/regulator/88pm800.txt @@ -0,0 +1,38 @@ +Marvell 88PM800 regulator + +Required properties: +- compatible: "marvell,88pm800" +- reg: I2C slave address +- regulators: A node that houses a sub-node for each regulator within the + device. Each sub-node is identified using the node's name (or the deprecated + regulator-compatible property if present), with valid values listed below. + The content of each sub-node is defined by the standard binding for + regulators; see regulator.txt. + +The valid names for regulators are: + + buck1, buck2, buck3, buck4, buck5, ldo1, ldo2, ldo3, ldo4, ldo5, ldo6, ldo7, + ldo8, ldo9, ldo10, ldo11, ldo12, ldo13, ldo14, ldo15, ldo16, ldo17, ldo18, ldo19 + +Example: + + pmic: 88pm800@31 { + compatible = "marvell,88pm800"; + reg = <0x31>; + + regulators { + buck1 { + regulator-min-microvolt = <600000>; + regulator-max-microvolt = <3950000>; + regulator-boot-on; + regulator-always-on; + }; + ldo1 { + regulator-min-microvolt = <600000>; + regulator-max-microvolt = <15000000>; + regulator-boot-on; + regulator-always-on; + }; +... + }; + }; diff --git a/drivers/regulator/88pm800.c b/drivers/regulator/88pm800.c new file mode 100644 index 000000000000..a7d962f7a9b4 --- /dev/null +++ b/drivers/regulator/88pm800.c @@ -0,0 +1,377 @@ +/* + * Regulators driver for Marvell 88PM800 + * + * Copyright (C) 2012 Marvell International Ltd. + * Joseph(Yossi) Hanin + * Yi Zhang + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* LDO1 with DVC[0..3] */ +#define PM800_LDO1_VOUT (0x08) /* VOUT1 */ +#define PM800_LDO1_VOUT_2 (0x09) +#define PM800_LDO1_VOUT_3 (0x0A) +#define PM800_LDO2_VOUT (0x0B) +#define PM800_LDO3_VOUT (0x0C) +#define PM800_LDO4_VOUT (0x0D) +#define PM800_LDO5_VOUT (0x0E) +#define PM800_LDO6_VOUT (0x0F) +#define PM800_LDO7_VOUT (0x10) +#define PM800_LDO8_VOUT (0x11) +#define PM800_LDO9_VOUT (0x12) +#define PM800_LDO10_VOUT (0x13) +#define PM800_LDO11_VOUT (0x14) +#define PM800_LDO12_VOUT (0x15) +#define PM800_LDO13_VOUT (0x16) +#define PM800_LDO14_VOUT (0x17) +#define PM800_LDO15_VOUT (0x18) +#define PM800_LDO16_VOUT (0x19) +#define PM800_LDO17_VOUT (0x1A) +#define PM800_LDO18_VOUT (0x1B) +#define PM800_LDO19_VOUT (0x1C) + +/* BUCK1 with DVC[0..3] */ +#define PM800_BUCK1 (0x3C) +#define PM800_BUCK1_1 (0x3D) +#define PM800_BUCK1_2 (0x3E) +#define PM800_BUCK1_3 (0x3F) +#define PM800_BUCK2 (0x40) +#define PM800_BUCK3 (0x41) +#define PM800_BUCK3 (0x41) +#define PM800_BUCK4 (0x42) +#define PM800_BUCK4_1 (0x43) +#define PM800_BUCK4_2 (0x44) +#define PM800_BUCK4_3 (0x45) +#define PM800_BUCK5 (0x46) + +#define PM800_BUCK_ENA (0x50) +#define PM800_LDO_ENA1_1 (0x51) +#define PM800_LDO_ENA1_2 (0x52) +#define PM800_LDO_ENA1_3 (0x53) + +#define PM800_LDO_ENA2_1 (0x56) +#define PM800_LDO_ENA2_2 (0x57) +#define PM800_LDO_ENA2_3 (0x58) + +#define PM800_BUCK1_MISC1 (0x78) +#define PM800_BUCK3_MISC1 (0x7E) +#define PM800_BUCK4_MISC1 (0x81) +#define PM800_BUCK5_MISC1 (0x84) + +struct pm800_regulator_info { + struct regulator_desc desc; + int max_ua; +}; + +struct pm800_regulators { + struct regulator_dev *regulators[PM800_ID_RG_MAX]; + struct pm80x_chip *chip; + struct regmap *map; +}; + +/* + * vreg - the buck regs string. + * ereg - the string for the enable register. + * ebit - the bit number in the enable register. + * amax - the current + * Buck has 2 kinds of voltage steps. It is easy to find voltage by ranges, + * not the constant voltage table. + */ +#define PM800_BUCK(vreg, ereg, ebit, amax, volt_ranges) \ +{ \ + .desc = { \ + .name = #vreg, \ + .ops = &pm800_volt_range_ops, \ + .type = REGULATOR_VOLTAGE, \ + .id = PM800_ID_##vreg, \ + .owner = THIS_MODULE, \ + .linear_ranges = volt_ranges, \ + .n_linear_ranges = ARRAY_SIZE(volt_ranges), \ + .vsel_reg = PM800_##vreg, \ + .vsel_mask = 0x7f, \ + .enable_reg = PM800_##ereg, \ + .enable_mask = 1 << (ebit), \ + }, \ + .max_ua = (amax), \ +} + +/* + * vreg - the LDO regs string + * ereg - the string for the enable register. + * ebit - the bit number in the enable register. + * amax - the current + * volt_table - the LDO voltage table + * For all the LDOes, there are too many ranges. Using volt_table will be + * simpler and faster. + */ +#define PM800_LDO(vreg, ereg, ebit, amax, ldo_volt_table) \ +{ \ + .desc = { \ + .name = #vreg, \ + .ops = &pm800_volt_table_ops, \ + .type = REGULATOR_VOLTAGE, \ + .id = PM800_ID_##vreg, \ + .owner = THIS_MODULE, \ + .n_voltages = ARRAY_SIZE(ldo_volt_table), \ + .vsel_reg = PM800_##vreg##_VOUT, \ + .vsel_mask = 0x1f, \ + .enable_reg = PM800_##ereg, \ + .enable_mask = 1 << (ebit), \ + .volt_table = ldo_volt_table, \ + }, \ + .max_ua = (amax), \ +} + +/* Ranges are sorted in ascending order. */ +static const struct regulator_linear_range buck1_volt_range[] = { + { .min_uV = 600000, .max_uV = 1587500, .min_sel = 0, .max_sel = 0x4f, + .uV_step = 12500 }, + { .min_uV = 1600000, .max_uV = 1800000, .min_sel = 0x50, + .max_sel = 0x54, .uV_step = 50000 }, +}; + +/* BUCK 2~5 have same ranges. */ +static const struct regulator_linear_range buck2_5_volt_range[] = { + { .min_uV = 600000, .max_uV = 1587500, .min_sel = 0, .max_sel = 0x4f, + .uV_step = 12500 }, + { .min_uV = 1600000, .max_uV = 3300000, .min_sel = 0x50, + .max_sel = 0x72, .uV_step = 50000 }, +}; + +static const unsigned int ldo1_volt_table[] = { + 600000, 650000, 700000, 750000, 800000, 850000, 900000, 950000, + 1000000, 1050000, 1100000, 1150000, 1200000, 1300000, 1400000, 1500000, +}; + +static const unsigned int ldo2_volt_table[] = { + 1700000, 1800000, 1900000, 2000000, 2100000, 2500000, 2700000, 2800000, +}; + +/* LDO 3~17 have same voltage table. */ +static const unsigned int ldo3_17_volt_table[] = { + 1200000, 1250000, 1700000, 1800000, 1850000, 1900000, 2500000, 2600000, + 2700000, 2750000, 2800000, 2850000, 2900000, 3000000, 3100000, 3300000, +}; + +/* LDO 18~19 have same voltage table. */ +static const unsigned int ldo18_19_volt_table[] = { + 1700000, 1800000, 1900000, 2500000, 2800000, 2900000, 3100000, 3300000, +}; + +static int pm800_get_current_limit(struct regulator_dev *rdev) +{ + struct pm800_regulator_info *info = rdev_get_drvdata(rdev); + + return info->max_ua; +} + +static struct regulator_ops pm800_volt_range_ops = { + .list_voltage = regulator_list_voltage_linear_range, + .map_voltage = regulator_map_voltage_linear_range, + .set_voltage_sel = regulator_set_voltage_sel_regmap, + .get_voltage_sel = regulator_get_voltage_sel_regmap, + .enable = regulator_enable_regmap, + .disable = regulator_disable_regmap, + .is_enabled = regulator_is_enabled_regmap, + .get_current_limit = pm800_get_current_limit, +}; + +static struct regulator_ops pm800_volt_table_ops = { + .list_voltage = regulator_list_voltage_table, + .map_voltage = regulator_map_voltage_iterate, + .set_voltage_sel = regulator_set_voltage_sel_regmap, + .get_voltage_sel = regulator_get_voltage_sel_regmap, + .enable = regulator_enable_regmap, + .disable = regulator_disable_regmap, + .is_enabled = regulator_is_enabled_regmap, + .get_current_limit = pm800_get_current_limit, +}; + +/* The array is indexed by id(PM800_ID_XXX) */ +static struct pm800_regulator_info pm800_regulator_info[] = { + PM800_BUCK(BUCK1, BUCK_ENA, 0, 3000000, buck1_volt_range), + PM800_BUCK(BUCK2, BUCK_ENA, 1, 1200000, buck2_5_volt_range), + PM800_BUCK(BUCK3, BUCK_ENA, 2, 1200000, buck2_5_volt_range), + PM800_BUCK(BUCK4, BUCK_ENA, 3, 1200000, buck2_5_volt_range), + PM800_BUCK(BUCK5, BUCK_ENA, 4, 1200000, buck2_5_volt_range), + + PM800_LDO(LDO1, LDO_ENA1_1, 0, 200000, ldo1_volt_table), + PM800_LDO(LDO2, LDO_ENA1_1, 1, 10000, ldo2_volt_table), + PM800_LDO(LDO3, LDO_ENA1_1, 2, 300000, ldo3_17_volt_table), + PM800_LDO(LDO4, LDO_ENA1_1, 3, 300000, ldo3_17_volt_table), + PM800_LDO(LDO5, LDO_ENA1_1, 4, 300000, ldo3_17_volt_table), + PM800_LDO(LDO6, LDO_ENA1_1, 5, 300000, ldo3_17_volt_table), + PM800_LDO(LDO7, LDO_ENA1_1, 6, 300000, ldo3_17_volt_table), + PM800_LDO(LDO8, LDO_ENA1_1, 7, 300000, ldo3_17_volt_table), + PM800_LDO(LDO9, LDO_ENA1_2, 0, 300000, ldo3_17_volt_table), + PM800_LDO(LDO10, LDO_ENA1_2, 1, 300000, ldo3_17_volt_table), + PM800_LDO(LDO11, LDO_ENA1_2, 2, 300000, ldo3_17_volt_table), + PM800_LDO(LDO12, LDO_ENA1_2, 3, 300000, ldo3_17_volt_table), + PM800_LDO(LDO13, LDO_ENA1_2, 4, 300000, ldo3_17_volt_table), + PM800_LDO(LDO14, LDO_ENA1_2, 5, 300000, ldo3_17_volt_table), + PM800_LDO(LDO15, LDO_ENA1_2, 6, 300000, ldo3_17_volt_table), + PM800_LDO(LDO16, LDO_ENA1_2, 7, 300000, ldo3_17_volt_table), + PM800_LDO(LDO17, LDO_ENA1_3, 0, 300000, ldo3_17_volt_table), + PM800_LDO(LDO18, LDO_ENA1_3, 1, 200000, ldo18_19_volt_table), + PM800_LDO(LDO19, LDO_ENA1_3, 2, 200000, ldo18_19_volt_table), +}; + +#define PM800_REGULATOR_OF_MATCH(_name, _id) \ + [PM800_ID_##_id] = { \ + .name = #_name, \ + .driver_data = &pm800_regulator_info[PM800_ID_##_id], \ + } + +static struct of_regulator_match pm800_regulator_matches[] = { + PM800_REGULATOR_OF_MATCH(buck1, BUCK1), + PM800_REGULATOR_OF_MATCH(buck2, BUCK2), + PM800_REGULATOR_OF_MATCH(buck3, BUCK3), + PM800_REGULATOR_OF_MATCH(buck4, BUCK4), + PM800_REGULATOR_OF_MATCH(buck5, BUCK5), + PM800_REGULATOR_OF_MATCH(ldo1, LDO1), + PM800_REGULATOR_OF_MATCH(ldo2, LDO2), + PM800_REGULATOR_OF_MATCH(ldo3, LDO3), + PM800_REGULATOR_OF_MATCH(ldo4, LDO4), + PM800_REGULATOR_OF_MATCH(ldo5, LDO5), + PM800_REGULATOR_OF_MATCH(ldo6, LDO6), + PM800_REGULATOR_OF_MATCH(ldo7, LDO7), + PM800_REGULATOR_OF_MATCH(ldo8, LDO8), + PM800_REGULATOR_OF_MATCH(ldo9, LDO9), + PM800_REGULATOR_OF_MATCH(ldo10, LDO10), + PM800_REGULATOR_OF_MATCH(ldo11, LDO11), + PM800_REGULATOR_OF_MATCH(ldo12, LDO12), + PM800_REGULATOR_OF_MATCH(ldo13, LDO13), + PM800_REGULATOR_OF_MATCH(ldo14, LDO14), + PM800_REGULATOR_OF_MATCH(ldo15, LDO15), + PM800_REGULATOR_OF_MATCH(ldo16, LDO16), + PM800_REGULATOR_OF_MATCH(ldo17, LDO17), + PM800_REGULATOR_OF_MATCH(ldo18, LDO18), + PM800_REGULATOR_OF_MATCH(ldo19, LDO19), +}; + +static int pm800_regulator_dt_init(struct platform_device *pdev) +{ + struct device_node *np = pdev->dev.of_node; + int ret; + + ret = of_regulator_match(&pdev->dev, np, + pm800_regulator_matches, + ARRAY_SIZE(pm800_regulator_matches)); + if (ret < 0) + return ret; + + return 0; +} + +static int pm800_regulator_probe(struct platform_device *pdev) +{ + struct pm80x_chip *chip = dev_get_drvdata(pdev->dev.parent); + struct pm80x_platform_data *pdata = pdev->dev.parent->platform_data; + struct pm800_regulators *pm800_data; + struct pm800_regulator_info *info; + struct regulator_config config = { }; + struct regulator_init_data *init_data; + int i, ret; + + if (!pdata || pdata->num_regulators == 0) { + if (IS_ENABLED(CONFIG_OF)) { + ret = pm800_regulator_dt_init(pdev); + if (ret) + return ret; + } else { + return -ENODEV; + } + } else if (pdata->num_regulators) { + /* Check whether num_regulator is valid. */ + unsigned int count = 0; + for (i = 0; pdata->regulators[i]; i++) + count++; + if (count != pdata->num_regulators) + return -EINVAL; + } else { + return -EINVAL; + } + + pm800_data = devm_kzalloc(&pdev->dev, sizeof(*pm800_data), + GFP_KERNEL); + if (!pm800_data) { + dev_err(&pdev->dev, "Failed to allocate pm800_regualtors"); + return -ENOMEM; + } + + pm800_data->map = chip->subchip->regmap_power; + pm800_data->chip = chip; + + platform_set_drvdata(pdev, pm800_data); + + for (i = 0; i < PM800_ID_RG_MAX; i++) { + if (!pdata || pdata->num_regulators == 0) + init_data = pm800_regulator_matches[i].init_data; + else + init_data = pdata->regulators[i]; + if (!init_data) + continue; + info = pm800_regulator_matches[i].driver_data; + config.dev = &pdev->dev; + config.init_data = init_data; + config.driver_data = info; + config.regmap = pm800_data->map; + + pm800_data->regulators[i] = + regulator_register(&info->desc, &config); + if (IS_ERR(pm800_data->regulators[i])) { + ret = PTR_ERR(pm800_data->regulators[i]); + dev_err(&pdev->dev, "Failed to register %s\n", + info->desc.name); + + while (--i >= 0) + regulator_unregister(pm800_data->regulators[i]); + + return ret; + } + } + + return 0; +} + +static int pm800_regulator_remove(struct platform_device *pdev) +{ + struct pm800_regulators *pm800_data = platform_get_drvdata(pdev); + int i; + + for (i = 0; i < PM800_ID_RG_MAX; i++) + regulator_unregister(pm800_data->regulators[i]); + + return 0; +} + +static struct platform_driver pm800_regulator_driver = { + .driver = { + .name = "88pm80x-regulator", + .owner = THIS_MODULE, + }, + .probe = pm800_regulator_probe, + .remove = pm800_regulator_remove, +}; + +module_platform_driver(pm800_regulator_driver); + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Joseph(Yossi) Hanin "); +MODULE_DESCRIPTION("Regulator Driver for Marvell 88PM800 PMIC"); +MODULE_ALIAS("platform:88pm800-regulator"); diff --git a/drivers/regulator/Kconfig b/drivers/regulator/Kconfig index 759b601b54ef..65b7d5b1bb39 100644 --- a/drivers/regulator/Kconfig +++ b/drivers/regulator/Kconfig @@ -64,6 +64,16 @@ config REGULATOR_USERSPACE_CONSUMER If unsure, say no. +config REGULATOR_88PM800 + tristate "Marvell 88PM800 Power regulators" + depends on MFD_88PM800=y + help + This driver supports Marvell 88PM800 voltage regulator chips. + It delivers digitally programmable output, + the voltage is programmed via I2C interface. + It's suitable to support PXA988 chips to control VCC_MAIN and + various voltages. + config REGULATOR_88PM8607 bool "Marvell 88PM8607 Power regulators" depends on MFD_88PM860X=y diff --git a/drivers/regulator/Makefile b/drivers/regulator/Makefile index d240772d90ee..e292f26a1fbd 100644 --- a/drivers/regulator/Makefile +++ b/drivers/regulator/Makefile @@ -9,6 +9,7 @@ obj-$(CONFIG_REGULATOR_FIXED_VOLTAGE) += fixed.o obj-$(CONFIG_REGULATOR_VIRTUAL_CONSUMER) += virtual.o obj-$(CONFIG_REGULATOR_USERSPACE_CONSUMER) += userspace-consumer.o +obj-$(CONFIG_REGULATOR_88PM800) += 88pm800.o obj-$(CONFIG_REGULATOR_88PM8607) += 88pm8607.o obj-$(CONFIG_REGULATOR_AAT2870) += aat2870-regulator.o obj-$(CONFIG_REGULATOR_AB3100) += ab3100.o -- cgit v1.2.3 From e5e80f6dd65d27085d86c3c0eb598b4a1b49a271 Mon Sep 17 00:00:00 2001 From: Axel Lin Date: Fri, 19 Jul 2013 09:16:55 +0800 Subject: regulator: 88pm800: Add missing config.of_node setting for regulator register Signed-off-by: Axel Lin Signed-off-by: Mark Brown --- drivers/regulator/88pm800.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers') diff --git a/drivers/regulator/88pm800.c b/drivers/regulator/88pm800.c index a7d962f7a9b4..fc0c352c98df 100644 --- a/drivers/regulator/88pm800.c +++ b/drivers/regulator/88pm800.c @@ -331,6 +331,7 @@ static int pm800_regulator_probe(struct platform_device *pdev) config.init_data = init_data; config.driver_data = info; config.regmap = pm800_data->map; + config.of_node = pm800_regulator_matches[i].of_node; pm800_data->regulators[i] = regulator_register(&info->desc, &config); -- cgit v1.2.3 From 7c45f60b42e0f916aaf31fedf8e8afeaf585ee90 Mon Sep 17 00:00:00 2001 From: Axel Lin Date: Fri, 19 Jul 2013 09:17:53 +0800 Subject: regulator: 88pm800: Depend on MFD_88PM800 rather than MFD_88PM800=y This driver can be built as a module, make it depend on MFD_88PM800. Otherwise, we are not able to select this driver when MFD_88PM800=m. Signed-off-by: Axel Lin Signed-off-by: Mark Brown --- drivers/regulator/Kconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/regulator/Kconfig b/drivers/regulator/Kconfig index 65b7d5b1bb39..b05fa9009e82 100644 --- a/drivers/regulator/Kconfig +++ b/drivers/regulator/Kconfig @@ -66,7 +66,7 @@ config REGULATOR_USERSPACE_CONSUMER config REGULATOR_88PM800 tristate "Marvell 88PM800 Power regulators" - depends on MFD_88PM800=y + depends on MFD_88PM800 help This driver supports Marvell 88PM800 voltage regulator chips. It delivers digitally programmable output, -- cgit v1.2.3 From 6625d9d297f28741d42a4ba712338a05f7464bd6 Mon Sep 17 00:00:00 2001 From: Axel Lin Date: Fri, 19 Jul 2013 13:06:22 +0800 Subject: regulator: 88pm800: Add missing n_voltages setting for bucks Some regulator APIs are broken if n_voltages setting is not set. e.g. regulator_count_voltages(), regulator_list_voltage(), and regulator_can_change_voltage() do not work if n_voltages setting is missing. Signed-off-by: Axel Lin Signed-off-by: Mark Brown --- drivers/regulator/88pm800.c | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) (limited to 'drivers') diff --git a/drivers/regulator/88pm800.c b/drivers/regulator/88pm800.c index fc0c352c98df..b4c29b1c52a5 100644 --- a/drivers/regulator/88pm800.c +++ b/drivers/regulator/88pm800.c @@ -91,8 +91,9 @@ struct pm800_regulators { * amax - the current * Buck has 2 kinds of voltage steps. It is easy to find voltage by ranges, * not the constant voltage table. + * n_volt - Number of available selectors */ -#define PM800_BUCK(vreg, ereg, ebit, amax, volt_ranges) \ +#define PM800_BUCK(vreg, ereg, ebit, amax, volt_ranges, n_volt) \ { \ .desc = { \ .name = #vreg, \ @@ -100,6 +101,7 @@ struct pm800_regulators { .type = REGULATOR_VOLTAGE, \ .id = PM800_ID_##vreg, \ .owner = THIS_MODULE, \ + .n_voltages = n_volt, \ .linear_ranges = volt_ranges, \ .n_linear_ranges = ARRAY_SIZE(volt_ranges), \ .vsel_reg = PM800_##vreg, \ @@ -204,11 +206,11 @@ static struct regulator_ops pm800_volt_table_ops = { /* The array is indexed by id(PM800_ID_XXX) */ static struct pm800_regulator_info pm800_regulator_info[] = { - PM800_BUCK(BUCK1, BUCK_ENA, 0, 3000000, buck1_volt_range), - PM800_BUCK(BUCK2, BUCK_ENA, 1, 1200000, buck2_5_volt_range), - PM800_BUCK(BUCK3, BUCK_ENA, 2, 1200000, buck2_5_volt_range), - PM800_BUCK(BUCK4, BUCK_ENA, 3, 1200000, buck2_5_volt_range), - PM800_BUCK(BUCK5, BUCK_ENA, 4, 1200000, buck2_5_volt_range), + PM800_BUCK(BUCK1, BUCK_ENA, 0, 3000000, buck1_volt_range, 0x55), + PM800_BUCK(BUCK2, BUCK_ENA, 1, 1200000, buck2_5_volt_range, 0x73), + PM800_BUCK(BUCK3, BUCK_ENA, 2, 1200000, buck2_5_volt_range, 0x73), + PM800_BUCK(BUCK4, BUCK_ENA, 3, 1200000, buck2_5_volt_range, 0x73), + PM800_BUCK(BUCK5, BUCK_ENA, 4, 1200000, buck2_5_volt_range, 0x73), PM800_LDO(LDO1, LDO_ENA1_1, 0, 200000, ldo1_volt_table), PM800_LDO(LDO2, LDO_ENA1_1, 1, 10000, ldo2_volt_table), -- cgit v1.2.3 From 19c6b5440a66cba44365e511d9794e5e34ae2e4e Mon Sep 17 00:00:00 2001 From: Axel Lin Date: Sun, 4 Aug 2013 09:23:28 +0800 Subject: regulator: 88pm800: Fix checking whether num_regulator is valid The code to check whether num_regulator is valid is wrong because it should iterate all array entries rather than break from the for loop if pdata->regulators[i] is NULL. Signed-off-by: Axel Lin Signed-off-by: Mark Brown --- drivers/regulator/88pm800.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/regulator/88pm800.c b/drivers/regulator/88pm800.c index b4c29b1c52a5..f42356552f21 100644 --- a/drivers/regulator/88pm800.c +++ b/drivers/regulator/88pm800.c @@ -299,10 +299,13 @@ static int pm800_regulator_probe(struct platform_device *pdev) return -ENODEV; } } else if (pdata->num_regulators) { - /* Check whether num_regulator is valid. */ unsigned int count = 0; - for (i = 0; pdata->regulators[i]; i++) - count++; + + /* Check whether num_regulator is valid. */ + for (i = 0; ARRAY_SIZE(pdata->regulators); i++) { + if (pdata->regulators[i]) + count++; + } if (count != pdata->num_regulators) return -EINVAL; } else { -- cgit v1.2.3 From 720c027303b91ea7320dc9da51b502633c9fece4 Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Wed, 14 Aug 2013 19:14:03 +0300 Subject: regulator: 88pm800: forever loop in pm800_regulator_probe() This is supposed to be testing "i < ARRAY_SIZE()" instead of just "ARRAY_SIZE()". Signed-off-by: Dan Carpenter Reviewed-by: Axel Lin Signed-off-by: Mark Brown --- drivers/regulator/88pm800.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/regulator/88pm800.c b/drivers/regulator/88pm800.c index f42356552f21..b30f5ce659d1 100644 --- a/drivers/regulator/88pm800.c +++ b/drivers/regulator/88pm800.c @@ -302,7 +302,7 @@ static int pm800_regulator_probe(struct platform_device *pdev) unsigned int count = 0; /* Check whether num_regulator is valid. */ - for (i = 0; ARRAY_SIZE(pdata->regulators); i++) { + for (i = 0; i < ARRAY_SIZE(pdata->regulators); i++) { if (pdata->regulators[i]) count++; } -- cgit v1.2.3