From 4dee4d441d3f90cd8cec10a9eb222d8a4f2fa2a3 Mon Sep 17 00:00:00 2001 From: Roel Kluin Date: Mon, 15 Jun 2009 22:30:39 +0200 Subject: regulator: add check index of wm8350->pmic.pdev[] Ensure that reg is within the bounds of array wm8350->pmic.pdev[]. Signed-off-by: Roel Kluin Acked-by: Mark Brown Signed-off-by: Liam Girdwood --- drivers/regulator/wm8350-regulator.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'drivers') diff --git a/drivers/regulator/wm8350-regulator.c b/drivers/regulator/wm8350-regulator.c index 17a00b0fafd..768bd0e5b48 100644 --- a/drivers/regulator/wm8350-regulator.c +++ b/drivers/regulator/wm8350-regulator.c @@ -1419,6 +1419,8 @@ int wm8350_register_regulator(struct wm8350 *wm8350, int reg, { struct platform_device *pdev; int ret; + if (reg < 0 || reg >= NUM_WM8350_REGULATORS) + return -EINVAL; if (wm8350->pmic.pdev[reg]) return -EBUSY; -- cgit v1.2.3 From d61c3d56e23b3548a91b70ecce9dc226a8655a57 Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Mon, 15 Jun 2009 20:01:01 +0100 Subject: regulator: Report regulator_get() failure in virtual consumer The core will no longer complain so we should log an error here. Signed-off-by: Mark Brown Signed-off-by: Liam Girdwood --- drivers/regulator/virtual.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'drivers') diff --git a/drivers/regulator/virtual.c b/drivers/regulator/virtual.c index e7db5664722..e953c1810c7 100644 --- a/drivers/regulator/virtual.c +++ b/drivers/regulator/virtual.c @@ -285,6 +285,8 @@ static int regulator_virtual_consumer_probe(struct platform_device *pdev) drvdata->regulator = regulator_get(&pdev->dev, reg_id); if (IS_ERR(drvdata->regulator)) { ret = PTR_ERR(drvdata->regulator); + dev_err(&pdev->dev, "Failed to obtain supply '%s': %d\n", + reg_id, ret); goto err; } -- cgit v1.2.3 From a07ac217146e0fac18c80d93e02109f2c96574d0 Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Wed, 17 Jun 2009 15:45:06 +0100 Subject: regulator: Make virtual consumer use dev_printk Signed-off-by: Mark Brown Signed-off-by: Liam Girdwood --- drivers/regulator/virtual.c | 34 ++++++++++++++++++---------------- 1 file changed, 18 insertions(+), 16 deletions(-) (limited to 'drivers') diff --git a/drivers/regulator/virtual.c b/drivers/regulator/virtual.c index e953c1810c7..5c1d75662b8 100644 --- a/drivers/regulator/virtual.c +++ b/drivers/regulator/virtual.c @@ -27,17 +27,18 @@ struct virtual_consumer_data { unsigned int mode; }; -static void update_voltage_constraints(struct virtual_consumer_data *data) +static void update_voltage_constraints(struct device *dev, + struct virtual_consumer_data *data) { int ret; if (data->min_uV && data->max_uV && data->min_uV <= data->max_uV) { ret = regulator_set_voltage(data->regulator, - data->min_uV, data->max_uV); + data->min_uV, data->max_uV); if (ret != 0) { - printk(KERN_ERR "regulator_set_voltage() failed: %d\n", - ret); + dev_err(dev, + "regulator_set_voltage() failed: %d\n", ret); return; } } @@ -47,7 +48,7 @@ static void update_voltage_constraints(struct virtual_consumer_data *data) if (ret == 0) data->enabled = 1; else - printk(KERN_ERR "regulator_enable() failed: %d\n", + dev_err(dev, "regulator_enable() failed: %d\n", ret); } @@ -56,13 +57,13 @@ static void update_voltage_constraints(struct virtual_consumer_data *data) if (ret == 0) data->enabled = 0; else - printk(KERN_ERR "regulator_disable() failed: %d\n", + dev_err(dev, "regulator_disable() failed: %d\n", ret); } } -static void update_current_limit_constraints(struct virtual_consumer_data - *data) +static void update_current_limit_constraints(struct device *dev, + struct virtual_consumer_data *data) { int ret; @@ -71,8 +72,9 @@ static void update_current_limit_constraints(struct virtual_consumer_data ret = regulator_set_current_limit(data->regulator, data->min_uA, data->max_uA); if (ret != 0) { - pr_err("regulator_set_current_limit() failed: %d\n", - ret); + dev_err(dev, + "regulator_set_current_limit() failed: %d\n", + ret); return; } } @@ -82,7 +84,7 @@ static void update_current_limit_constraints(struct virtual_consumer_data if (ret == 0) data->enabled = 1; else - printk(KERN_ERR "regulator_enable() failed: %d\n", + dev_err(dev, "regulator_enable() failed: %d\n", ret); } @@ -91,7 +93,7 @@ static void update_current_limit_constraints(struct virtual_consumer_data if (ret == 0) data->enabled = 0; else - printk(KERN_ERR "regulator_disable() failed: %d\n", + dev_err(dev, "regulator_disable() failed: %d\n", ret); } } @@ -115,7 +117,7 @@ static ssize_t set_min_uV(struct device *dev, struct device_attribute *attr, mutex_lock(&data->lock); data->min_uV = val; - update_voltage_constraints(data); + update_voltage_constraints(dev, data); mutex_unlock(&data->lock); @@ -141,7 +143,7 @@ static ssize_t set_max_uV(struct device *dev, struct device_attribute *attr, mutex_lock(&data->lock); data->max_uV = val; - update_voltage_constraints(data); + update_voltage_constraints(dev, data); mutex_unlock(&data->lock); @@ -167,7 +169,7 @@ static ssize_t set_min_uA(struct device *dev, struct device_attribute *attr, mutex_lock(&data->lock); data->min_uA = val; - update_current_limit_constraints(data); + update_current_limit_constraints(dev, data); mutex_unlock(&data->lock); @@ -193,7 +195,7 @@ static ssize_t set_max_uA(struct device *dev, struct device_attribute *attr, mutex_lock(&data->lock); data->max_uA = val; - update_current_limit_constraints(data); + update_current_limit_constraints(dev, data); mutex_unlock(&data->lock); -- cgit v1.2.3 From a5d2abce4373810c0109c5939c0094ac16698625 Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Wed, 17 Jun 2009 15:45:07 +0100 Subject: regulator: Make virtual consumer a bit more chatty This makes it easier to read the logs when doing testing. Signed-off-by: Mark Brown Signed-off-by: Liam Girdwood --- drivers/regulator/virtual.c | 8 ++++++++ 1 file changed, 8 insertions(+) (limited to 'drivers') diff --git a/drivers/regulator/virtual.c b/drivers/regulator/virtual.c index 5c1d75662b8..144110788fd 100644 --- a/drivers/regulator/virtual.c +++ b/drivers/regulator/virtual.c @@ -34,6 +34,8 @@ static void update_voltage_constraints(struct device *dev, if (data->min_uV && data->max_uV && data->min_uV <= data->max_uV) { + dev_dbg(dev, "Requesting %d-%duV\n", + data->min_uV, data->max_uV); ret = regulator_set_voltage(data->regulator, data->min_uV, data->max_uV); if (ret != 0) { @@ -44,6 +46,7 @@ static void update_voltage_constraints(struct device *dev, } if (data->min_uV && data->max_uV && !data->enabled) { + dev_dbg(dev, "Enabling regulator\n"); ret = regulator_enable(data->regulator); if (ret == 0) data->enabled = 1; @@ -53,6 +56,7 @@ static void update_voltage_constraints(struct device *dev, } if (!(data->min_uV && data->max_uV) && data->enabled) { + dev_dbg(dev, "Disabling regulator\n"); ret = regulator_disable(data->regulator); if (ret == 0) data->enabled = 0; @@ -69,6 +73,8 @@ static void update_current_limit_constraints(struct device *dev, if (data->max_uA && data->min_uA <= data->max_uA) { + dev_dbg(dev, "Requesting %d-%duA\n", + data->min_uA, data->max_uA); ret = regulator_set_current_limit(data->regulator, data->min_uA, data->max_uA); if (ret != 0) { @@ -80,6 +86,7 @@ static void update_current_limit_constraints(struct device *dev, } if (data->max_uA && !data->enabled) { + dev_dbg(dev, "Enabling regulator\n"); ret = regulator_enable(data->regulator); if (ret == 0) data->enabled = 1; @@ -89,6 +96,7 @@ static void update_current_limit_constraints(struct device *dev, } if (!(data->min_uA && data->max_uA) && data->enabled) { + dev_dbg(dev, "Disabling regulator\n"); ret = regulator_disable(data->regulator); if (ret == 0) data->enabled = 0; -- cgit v1.2.3 From 40f9244f4da8976eeb6d5ed6313c635ba238a9d3 Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Wed, 17 Jun 2009 17:56:39 +0100 Subject: regulator: Allow consumer supplies to be set up with dev_name() Follow the approach suggested by Russell King and implemented by him in the clkdev API and allow consumer device supply mapings to be set up using the dev_name() for the consumer instead of the struct device. In order to avoid making existing machines instabuggy and creating merge issues the use of struct device is still supported for the time being. This resolves problems working with buses such as I2C which make the struct device available late providing that the final device name is known, which is the case for most embedded systems with fixed setups. Consumers must still use the struct device when calling regulator_get(). Signed-off-by: Mark Brown Signed-off-by: Liam Girdwood --- drivers/regulator/core.c | 62 +++++++++++++++++++++++++++++++++++++----------- 1 file changed, 48 insertions(+), 14 deletions(-) (limited to 'drivers') diff --git a/drivers/regulator/core.c b/drivers/regulator/core.c index 91ba9bfaa70..24e05b7607b 100644 --- a/drivers/regulator/core.c +++ b/drivers/regulator/core.c @@ -37,7 +37,7 @@ static int has_full_constraints; */ struct regulator_map { struct list_head list; - struct device *dev; + const char *dev_name; /* The dev_name() for the consumer */ const char *supply; struct regulator_dev *regulator; }; @@ -857,23 +857,33 @@ out: * set_consumer_device_supply: Bind a regulator to a symbolic supply * @rdev: regulator source * @consumer_dev: device the supply applies to + * @consumer_dev_name: dev_name() string for device supply applies to * @supply: symbolic name for supply * * Allows platform initialisation code to map physical regulator * sources to symbolic names for supplies for use by devices. Devices * should use these symbolic names to request regulators, avoiding the * need to provide board-specific regulator names as platform data. + * + * Only one of consumer_dev and consumer_dev_name may be specified. */ static int set_consumer_device_supply(struct regulator_dev *rdev, - struct device *consumer_dev, const char *supply) + struct device *consumer_dev, const char *consumer_dev_name, + const char *supply) { struct regulator_map *node; + if (consumer_dev && consumer_dev_name) + return -EINVAL; + + if (!consumer_dev_name && consumer_dev) + consumer_dev_name = dev_name(consumer_dev); + if (supply == NULL) return -EINVAL; list_for_each_entry(node, ®ulator_map_list, list) { - if (consumer_dev != node->dev) + if (consumer_dev_name != node->dev_name) continue; if (strcmp(node->supply, supply) != 0) continue; @@ -891,25 +901,38 @@ static int set_consumer_device_supply(struct regulator_dev *rdev, return -ENOMEM; node->regulator = rdev; - node->dev = consumer_dev; + node->dev_name = kstrdup(consumer_dev_name, GFP_KERNEL); node->supply = supply; + if (node->dev_name == NULL) { + kfree(node); + return -ENOMEM; + } + list_add(&node->list, ®ulator_map_list); return 0; } static void unset_consumer_device_supply(struct regulator_dev *rdev, - struct device *consumer_dev) + const char *consumer_dev_name, struct device *consumer_dev) { struct regulator_map *node, *n; + if (consumer_dev && !consumer_dev_name) + consumer_dev_name = dev_name(consumer_dev); + list_for_each_entry_safe(node, n, ®ulator_map_list, list) { - if (rdev == node->regulator && - consumer_dev == node->dev) { - list_del(&node->list); - kfree(node); - return; - } + if (rdev != node->regulator) + continue; + + if (consumer_dev_name && node->dev_name && + strcmp(consumer_dev_name, node->dev_name)) + continue; + + list_del(&node->list); + kfree(node->dev_name); + kfree(node); + return; } } @@ -920,6 +943,7 @@ static void unset_regulator_supplies(struct regulator_dev *rdev) list_for_each_entry_safe(node, n, ®ulator_map_list, list) { if (rdev == node->regulator) { list_del(&node->list); + kfree(node->dev_name); kfree(node); return; } @@ -1019,17 +1043,25 @@ struct regulator *regulator_get(struct device *dev, const char *id) struct regulator_dev *rdev; struct regulator_map *map; struct regulator *regulator = ERR_PTR(-ENODEV); + const char *devname = NULL; if (id == NULL) { printk(KERN_ERR "regulator: get() with no identifier\n"); return regulator; } + if (dev) + devname = dev_name(dev); + mutex_lock(®ulator_list_mutex); list_for_each_entry(map, ®ulator_map_list, list) { - if (dev == map->dev && - strcmp(map->supply, id) == 0) { + /* If the mapping has a device set up it must match */ + if (map->dev_name && + (!devname || strcmp(map->dev_name, devname))) + continue; + + if (strcmp(map->supply, id) == 0) { rdev = map->regulator; goto found; } @@ -2091,11 +2123,13 @@ struct regulator_dev *regulator_register(struct regulator_desc *regulator_desc, for (i = 0; i < init_data->num_consumer_supplies; i++) { ret = set_consumer_device_supply(rdev, init_data->consumer_supplies[i].dev, + init_data->consumer_supplies[i].dev_name, init_data->consumer_supplies[i].supply); if (ret < 0) { for (--i; i >= 0; i--) unset_consumer_device_supply(rdev, - init_data->consumer_supplies[i].dev); + init_data->consumer_supplies[i].dev_name, + init_data->consumer_supplies[i].dev); goto scrub; } } -- cgit v1.2.3 From 561864e8e3c263ff72bd0888aca80089027195ca Mon Sep 17 00:00:00 2001 From: Joe Perches Date: Sun, 28 Jun 2009 09:26:42 -0700 Subject: drivers/regulator/pcf50633-regulator.c: Remove unnecessary semicolons Signed-off-by: Joe Perches Signed-off-by: Liam Girdwood --- drivers/regulator/pcf50633-regulator.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/regulator/pcf50633-regulator.c b/drivers/regulator/pcf50633-regulator.c index 8e14900eb68..70ba7755765 100644 --- a/drivers/regulator/pcf50633-regulator.c +++ b/drivers/regulator/pcf50633-regulator.c @@ -155,7 +155,7 @@ static int pcf50633_regulator_get_voltage(struct regulator_dev *rdev) int regulator_id, millivolts, volt_bits; u8 regnr; - pcf = rdev_get_drvdata(rdev);; + pcf = rdev_get_drvdata(rdev); regulator_id = rdev_get_id(rdev); if (regulator_id >= PCF50633_NUM_REGULATORS) -- cgit v1.2.3 From 0198d1163b3e0313b3f073b62384abfab1a17cff Mon Sep 17 00:00:00 2001 From: Haojian Zhuang Date: Fri, 26 Jun 2009 19:20:59 +0800 Subject: regulator: add buck3 in da903x driver BUCK3 is the new component in DA9035. So there're three BUCKs in DA9035. And there're two BUCKs in DA9034. Signed-off-by: Haojian Zhuang Acked-by: Mark Brown Acked-by: Eric Miao Signed-off-by: Liam Girdwood --- drivers/regulator/da903x.c | 32 ++++++++++++++++++++++++++++++++ 1 file changed, 32 insertions(+) (limited to 'drivers') diff --git a/drivers/regulator/da903x.c b/drivers/regulator/da903x.c index b8b89ef10a8..33dfeeb9407 100644 --- a/drivers/regulator/da903x.c +++ b/drivers/regulator/da903x.c @@ -64,6 +64,14 @@ #define DA9034_MDTV2 (0x33) #define DA9034_MVRC (0x34) +/* DA9035 Registers. DA9034 Registers are comptabile to DA9035. */ +#define DA9035_OVER3 (0x12) +#define DA9035_VCC2 (0x1f) +#define DA9035_3DTV1 (0x2c) +#define DA9035_3DTV2 (0x2d) +#define DA9035_3VRC (0x2e) +#define DA9035_AUTOSKIP (0x2f) + struct da903x_regulator_info { struct regulator_desc desc; @@ -388,6 +396,27 @@ static struct regulator_ops da9034_regulator_ldo12_ops = { .enable_bit = (ebit), \ } +#define DA9035_DVC(_id, min, max, step, vreg, nbits, ureg, ubit, ereg, ebit) \ +{ \ + .desc = { \ + .name = #_id, \ + .ops = &da9034_regulator_dvc_ops, \ + .type = REGULATOR_VOLTAGE, \ + .id = DA9035_ID_##_id, \ + .owner = THIS_MODULE, \ + }, \ + .min_uV = (min) * 1000, \ + .max_uV = (max) * 1000, \ + .step_uV = (step) * 1000, \ + .vol_reg = DA9035_##vreg, \ + .vol_shift = (0), \ + .vol_nbits = (nbits), \ + .update_reg = DA9035_##ureg, \ + .update_bit = (ubit), \ + .enable_reg = DA9035_##ereg, \ + .enable_bit = (ebit), \ +} + #define DA9034_LDO(_id, min, max, step, vreg, shift, nbits, ereg, ebit) \ DA903x_LDO(DA9034, _id, min, max, step, vreg, shift, nbits, ereg, ebit) @@ -435,6 +464,9 @@ static struct da903x_regulator_info da903x_regulator_info[] = { DA9034_LDO(14, 1800, 3300, 100, LDO1514, 0, 4, OVER3, 0), DA9034_LDO(15, 1800, 3300, 100, LDO1514, 4, 4, OVER3, 1), DA9034_LDO(5, 3100, 3100, 0, INVAL, 0, 0, OVER3, 7), /* fixed @3.1V */ + + /* DA9035 */ + DA9035_DVC(BUCK3, 1800, 2200, 100, 3DTV1, 3, VCC2, 0, OVER3, 3), }; static inline struct da903x_regulator_info *find_regulator_info(int id) -- cgit v1.2.3 From fc4f42e7fb021340c14dfd726313be6cfdeab19e Mon Sep 17 00:00:00 2001 From: Haojian Zhuang Date: Wed, 8 Jul 2009 17:57:24 +0800 Subject: regulator: support da9030 BUCK in da903x driver Support the operation of DA9030 BUCK2 in da903x driver. Signed-off-by: Haojian Zhuang Acked-by: Mark Brown Acked-by: Eric Miao Acked-by: Mike Rapoport Signed-off-by: Liam Girdwood --- drivers/regulator/da903x.c | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) (limited to 'drivers') diff --git a/drivers/regulator/da903x.c b/drivers/regulator/da903x.c index 33dfeeb9407..49081b44bf5 100644 --- a/drivers/regulator/da903x.c +++ b/drivers/regulator/da903x.c @@ -375,6 +375,27 @@ static struct regulator_ops da9034_regulator_ldo12_ops = { .enable_bit = (ebit), \ } +#define DA9030_DVC(_id, min, max, step, vreg, nbits, ureg, ubit, ereg, ebit) \ +{ \ + .desc = { \ + .name = #_id, \ + .ops = &da9034_regulator_dvc_ops, \ + .type = REGULATOR_VOLTAGE, \ + .id = DA9030_ID_##_id, \ + .owner = THIS_MODULE, \ + }, \ + .min_uV = (min) * 1000, \ + .max_uV = (max) * 1000, \ + .step_uV = (step) * 1000, \ + .vol_reg = DA9030_##vreg, \ + .vol_shift = (0), \ + .vol_nbits = (nbits), \ + .update_reg = DA9030_##ureg, \ + .update_bit = (ubit), \ + .enable_reg = DA9030_##ereg, \ + .enable_bit = (ebit), \ +} + #define DA9034_DVC(_id, min, max, step, vreg, nbits, ureg, ubit, ereg, ebit) \ { \ .desc = { \ @@ -425,6 +446,8 @@ static struct regulator_ops da9034_regulator_ldo12_ops = { static struct da903x_regulator_info da903x_regulator_info[] = { /* DA9030 */ + DA9030_DVC(BUCK2, 850, 1625, 25, BUCK2DVM1, 5, BUCK2DVM1, 7, RCTL11, 0), + DA9030_LDO( 1, 1200, 3200, 100, LDO1, 0, 5, RCTL12, 1), DA9030_LDO( 2, 1800, 3200, 100, LDO23, 0, 4, RCTL12, 2), DA9030_LDO( 3, 1800, 3200, 100, LDO23, 4, 4, RCTL12, 3), -- cgit v1.2.3 From e88267e1646037fa2c155515c78bd01a5c81f058 Mon Sep 17 00:00:00 2001 From: Haojian Zhuang Date: Thu, 9 Jul 2009 17:52:30 +0800 Subject: regulator: replace ADTV1 register by ADTV2 in da903x In PXA3xx SoC family, V_CORE power doamin is supplied by BUCK1 that is controller by ADTV1 or ADTV2 register. By default, v1 and v2 has the same copy. If v1 or v2 is updated, the last value that is written to either register takes effect. It means that v1 and v2 has different copy. And the actual voltage output is determinated by last update on either register. DA9034/35 is binded with PXA3xx SoC family. While SoC is scaling OP or entering/exiting lower power mode, SoC needs to change voltage of V_CORE power doamin. In order to be efficient, POWER I2C (hardcode) mode could be enabled in SoC. In this mode, SoC will control v2 register directly. In original DA903x driver, software will only read regulator data from v1 register. But SoC controls v2 register directly. It results that v1 and v2 isn't synchronized. Wrong data will be read from v1 register. So access v2 register in da903x driver instead. Signed-off-by: Haojian Zhuang Acked-by: Mark Brown Signed-off-by: Liam Girdwood --- drivers/regulator/da903x.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/regulator/da903x.c b/drivers/regulator/da903x.c index 49081b44bf5..d8d251f066a 100644 --- a/drivers/regulator/da903x.c +++ b/drivers/regulator/da903x.c @@ -469,9 +469,9 @@ static struct da903x_regulator_info da903x_regulator_info[] = { DA9030_LDO(13, 2100, 2100, 0, INVAL, 0, 0, RCTL11, 3), /* fixed @2.1V */ /* DA9034 */ - DA9034_DVC(BUCK1, 725, 1500, 25, ADTV1, 5, VCC1, 0, OVER1, 0), - DA9034_DVC(BUCK2, 725, 1500, 25, CDTV1, 5, VCC1, 2, OVER1, 1), - DA9034_DVC(LDO2, 725, 1500, 25, SDTV1, 5, VCC1, 4, OVER1, 2), + DA9034_DVC(BUCK1, 725, 1500, 25, ADTV2, 5, VCC1, 0, OVER1, 0), + DA9034_DVC(BUCK2, 725, 1500, 25, CDTV2, 5, VCC1, 2, OVER1, 1), + DA9034_DVC(LDO2, 725, 1500, 25, SDTV2, 5, VCC1, 4, OVER1, 2), DA9034_DVC(LDO1, 1700, 2075, 25, MDTV1, 4, VCC1, 6, OVER3, 4), DA9034_LDO( 3, 1800, 3300, 100, LDO643, 0, 4, OVER3, 5), -- cgit v1.2.3 From c1b60873ca2078bfca94b73bc88ef1c5adcc928b Mon Sep 17 00:00:00 2001 From: Haojian Zhuang Date: Fri, 10 Jul 2009 16:03:36 +0800 Subject: regulator: support list voltage in da903x Make da903x driver to list voltage and count voltage. Signed-off-by: Haojian Zhuang Acked-by: Mark Brown Acked-by: Eric Miao Signed-off-by: Liam Girdwood --- drivers/regulator/da903x.c | 36 +++++++++++++++++++++++++++++++++++- 1 file changed, 35 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/regulator/da903x.c b/drivers/regulator/da903x.c index d8d251f066a..236de113439 100644 --- a/drivers/regulator/da903x.c +++ b/drivers/regulator/da903x.c @@ -87,6 +87,10 @@ struct da903x_regulator_info { int enable_bit; }; +static int da9034_ldo12_data[] = { 1700, 1750, 1800, 1850, 1900, 1950, + 2000, 2050, 2700, 2750, 2800, 2850, + 2900, 2950, 3000, 3050 }; + static inline struct device *to_da903x_dev(struct regulator_dev *rdev) { return rdev_get_dev(rdev)->parent->parent; @@ -170,6 +174,17 @@ static int da903x_is_enabled(struct regulator_dev *rdev) return !!(reg_val & (1 << info->enable_bit)); } +static int da903x_list_voltage(struct regulator_dev *rdev, unsigned selector) +{ + struct da903x_regulator_info *info = rdev_get_drvdata(rdev); + int ret; + + ret = info->min_uV + info->step_uV * selector; + if (ret > info->max_uV) + return -EINVAL; + return ret; +} + /* DA9030 specific operations */ static int da9030_set_ldo1_15_voltage(struct regulator_dev *rdev, int min_uV, int max_uV) @@ -313,9 +328,18 @@ static int da9034_get_ldo12_voltage(struct regulator_dev *rdev) return info->min_uV + info->step_uV * val; } +static int da9034_list_ldo12_voltage(struct regulator_dev *rdev, + unsigned selector) +{ + if (selector > ARRAY_SIZE(da9034_ldo12_data)) + return -EINVAL; + return da9034_ldo12_data[selector] * 1000; +} + static struct regulator_ops da903x_regulator_ldo_ops = { .set_voltage = da903x_set_ldo_voltage, .get_voltage = da903x_get_voltage, + .list_voltage = da903x_list_voltage, .enable = da903x_enable, .disable = da903x_disable, .is_enabled = da903x_is_enabled, @@ -325,6 +349,7 @@ static struct regulator_ops da903x_regulator_ldo_ops = { static struct regulator_ops da9030_regulator_ldo14_ops = { .set_voltage = da9030_set_ldo14_voltage, .get_voltage = da9030_get_ldo14_voltage, + .list_voltage = da903x_list_voltage, .enable = da903x_enable, .disable = da903x_disable, .is_enabled = da903x_is_enabled, @@ -334,6 +359,7 @@ static struct regulator_ops da9030_regulator_ldo14_ops = { static struct regulator_ops da9030_regulator_ldo1_15_ops = { .set_voltage = da9030_set_ldo1_15_voltage, .get_voltage = da903x_get_voltage, + .list_voltage = da903x_list_voltage, .enable = da903x_enable, .disable = da903x_disable, .is_enabled = da903x_is_enabled, @@ -342,6 +368,7 @@ static struct regulator_ops da9030_regulator_ldo1_15_ops = { static struct regulator_ops da9034_regulator_dvc_ops = { .set_voltage = da9034_set_dvc_voltage, .get_voltage = da903x_get_voltage, + .list_voltage = da903x_list_voltage, .enable = da903x_enable, .disable = da903x_disable, .is_enabled = da903x_is_enabled, @@ -351,6 +378,7 @@ static struct regulator_ops da9034_regulator_dvc_ops = { static struct regulator_ops da9034_regulator_ldo12_ops = { .set_voltage = da9034_set_ldo12_voltage, .get_voltage = da9034_get_ldo12_voltage, + .list_voltage = da9034_list_ldo12_voltage, .enable = da903x_enable, .disable = da903x_disable, .is_enabled = da903x_is_enabled, @@ -363,6 +391,7 @@ static struct regulator_ops da9034_regulator_ldo12_ops = { .ops = &da903x_regulator_ldo_ops, \ .type = REGULATOR_VOLTAGE, \ .id = _pmic##_ID_LDO##_id, \ + .n_voltages = (step) ? ((max - min) / step + 1) : 1, \ .owner = THIS_MODULE, \ }, \ .min_uV = (min) * 1000, \ @@ -382,6 +411,7 @@ static struct regulator_ops da9034_regulator_ldo12_ops = { .ops = &da9034_regulator_dvc_ops, \ .type = REGULATOR_VOLTAGE, \ .id = DA9030_ID_##_id, \ + .n_voltages = (step) ? ((max - min) / step + 1) : 1, \ .owner = THIS_MODULE, \ }, \ .min_uV = (min) * 1000, \ @@ -403,6 +433,7 @@ static struct regulator_ops da9034_regulator_ldo12_ops = { .ops = &da9034_regulator_dvc_ops, \ .type = REGULATOR_VOLTAGE, \ .id = DA9034_ID_##_id, \ + .n_voltages = (step) ? ((max - min) / step + 1) : 1, \ .owner = THIS_MODULE, \ }, \ .min_uV = (min) * 1000, \ @@ -424,6 +455,7 @@ static struct regulator_ops da9034_regulator_ldo12_ops = { .ops = &da9034_regulator_dvc_ops, \ .type = REGULATOR_VOLTAGE, \ .id = DA9035_ID_##_id, \ + .n_voltages = (step) ? ((max - min) / step + 1) : 1, \ .owner = THIS_MODULE, \ }, \ .min_uV = (min) * 1000, \ @@ -517,8 +549,10 @@ static int __devinit da903x_regulator_probe(struct platform_device *pdev) } /* Workaround for the weird LDO12 voltage setting */ - if (ri->desc.id == DA9034_ID_LDO12) + if (ri->desc.id == DA9034_ID_LDO12) { ri->desc.ops = &da9034_regulator_ldo12_ops; + ri->desc.n_voltages = ARRAY_SIZE(da9034_ldo12_data); + } if (ri->desc.id == DA9030_ID_LDO14) ri->desc.ops = &da9030_regulator_ldo14_ops; -- cgit v1.2.3 From 5ffbd136e6c51c8d1eec7a4a0c5d2180c81aea30 Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Tue, 21 Jul 2009 16:00:23 +0100 Subject: regulator: Add regulator_get_exclusive() API Some consumers require complete control of the regulator and can't tolerate sharing it with other consumers, most commonly because they need to have the regulator actually disabled so can't have other consumers forcing it on. This new regulator_get_exclusive() API call allows these consumers to explicitly request this, documenting the assumptions that they are making. In order to simplify coding of such consumers the use count for regulators they request is forced to match the enabled state of the regulator when it is requested. This is not possible for consumers which can share regulators due to the need to keep track of the ownership of use counts. A new API call is used rather than an additional argument to the existing regulator_get() in order to avoid merge headaches with driver code in other trees. Signed-off-by: Mark Brown Signed-off-by: Liam Girdwood --- drivers/regulator/core.c | 88 ++++++++++++++++++++++++++++++++++++++++-------- 1 file changed, 74 insertions(+), 14 deletions(-) (limited to 'drivers') diff --git a/drivers/regulator/core.c b/drivers/regulator/core.c index 24e05b7607b..68549008582 100644 --- a/drivers/regulator/core.c +++ b/drivers/regulator/core.c @@ -1025,25 +1025,15 @@ overflow_err: return NULL; } -/** - * regulator_get - lookup and obtain a reference to a regulator. - * @dev: device for regulator "consumer" - * @id: Supply name or regulator ID. - * - * Returns a struct regulator corresponding to the regulator producer, - * or IS_ERR() condition containing errno. - * - * Use of supply names configured via regulator_set_device_supply() is - * strongly encouraged. It is recommended that the supply name used - * should match the name used for the supply and/or the relevant - * device pins in the datasheet. - */ -struct regulator *regulator_get(struct device *dev, const char *id) +/* Internal regulator request function */ +static struct regulator *_regulator_get(struct device *dev, const char *id, + int exclusive) { struct regulator_dev *rdev; struct regulator_map *map; struct regulator *regulator = ERR_PTR(-ENODEV); const char *devname = NULL; + int ret; if (id == NULL) { printk(KERN_ERR "regulator: get() with no identifier\n"); @@ -1070,6 +1060,16 @@ struct regulator *regulator_get(struct device *dev, const char *id) return regulator; found: + if (rdev->exclusive) { + regulator = ERR_PTR(-EPERM); + goto out; + } + + if (exclusive && rdev->open_count) { + regulator = ERR_PTR(-EBUSY); + goto out; + } + if (!try_module_get(rdev->owner)) goto out; @@ -1079,12 +1079,69 @@ found: module_put(rdev->owner); } + rdev->open_count++; + if (exclusive) { + rdev->exclusive = 1; + + ret = _regulator_is_enabled(rdev); + if (ret > 0) + rdev->use_count = 1; + else + rdev->use_count = 0; + } + out: mutex_unlock(®ulator_list_mutex); + return regulator; } + +/** + * regulator_get - lookup and obtain a reference to a regulator. + * @dev: device for regulator "consumer" + * @id: Supply name or regulator ID. + * + * Returns a struct regulator corresponding to the regulator producer, + * or IS_ERR() condition containing errno. + * + * Use of supply names configured via regulator_set_device_supply() is + * strongly encouraged. It is recommended that the supply name used + * should match the name used for the supply and/or the relevant + * device pins in the datasheet. + */ +struct regulator *regulator_get(struct device *dev, const char *id) +{ + return _regulator_get(dev, id, 0); +} EXPORT_SYMBOL_GPL(regulator_get); +/** + * regulator_get_exclusive - obtain exclusive access to a regulator. + * @dev: device for regulator "consumer" + * @id: Supply name or regulator ID. + * + * Returns a struct regulator corresponding to the regulator producer, + * or IS_ERR() condition containing errno. Other consumers will be + * unable to obtain this reference is held and the use count for the + * regulator will be initialised to reflect the current state of the + * regulator. + * + * This is intended for use by consumers which cannot tolerate shared + * use of the regulator such as those which need to force the + * regulator off for correct operation of the hardware they are + * controlling. + * + * Use of supply names configured via regulator_set_device_supply() is + * strongly encouraged. It is recommended that the supply name used + * should match the name used for the supply and/or the relevant + * device pins in the datasheet. + */ +struct regulator *regulator_get_exclusive(struct device *dev, const char *id) +{ + return _regulator_get(dev, id, 1); +} +EXPORT_SYMBOL_GPL(regulator_get_exclusive); + /** * regulator_put - "free" the regulator source * @regulator: regulator source @@ -1113,6 +1170,9 @@ void regulator_put(struct regulator *regulator) list_del(®ulator->list); kfree(regulator); + rdev->open_count--; + rdev->exclusive = 0; + module_put(rdev->owner); mutex_unlock(®ulator_list_mutex); } -- cgit v1.2.3 From a7a1ad9066e0266c8a4357ba3dbaeebfb80f531d Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Tue, 21 Jul 2009 16:00:24 +0100 Subject: regulator: Add regulator voltage range check API Simplify checking of support for voltage ranges by providing an API which wraps the existing count and list operations. Signed-off-by: Mark Brown Signed-off-by: Liam Girdwood --- drivers/regulator/core.c | 29 +++++++++++++++++++++++++++++ 1 file changed, 29 insertions(+) (limited to 'drivers') diff --git a/drivers/regulator/core.c b/drivers/regulator/core.c index 68549008582..e11c2222d9a 100644 --- a/drivers/regulator/core.c +++ b/drivers/regulator/core.c @@ -1441,6 +1441,35 @@ int regulator_list_voltage(struct regulator *regulator, unsigned selector) } EXPORT_SYMBOL_GPL(regulator_list_voltage); +/** + * regulator_is_supported_voltage - check if a voltage range can be supported + * + * @regulator: Regulator to check. + * @min_uV: Minimum required voltage in uV. + * @max_uV: Maximum required voltage in uV. + * + * Returns a boolean or a negative error code. + */ +int regulator_is_supported_voltage(struct regulator *regulator, + int min_uV, int max_uV) +{ + int i, voltages, ret; + + ret = regulator_count_voltages(regulator); + if (ret < 0) + return ret; + voltages = ret; + + for (i = 0; i < voltages; i++) { + ret = regulator_list_voltage(regulator, i); + + if (ret >= min_uV && ret <= max_uV) + return 1; + } + + return 0; +} + /** * regulator_set_voltage - set regulator output voltage * @regulator: regulator source -- cgit v1.2.3 From 6bf87d17c9f5b855e9dde7b3d6f726385b966814 Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Tue, 21 Jul 2009 16:00:25 +0100 Subject: regulator: Warn when unregistering an in-use regulator We're probably going to start oopsing fairly soon after this happens. Signed-off-by: Mark Brown Signed-off-by: Liam Girdwood --- drivers/regulator/core.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers') diff --git a/drivers/regulator/core.c b/drivers/regulator/core.c index e11c2222d9a..79a6910eb89 100644 --- a/drivers/regulator/core.c +++ b/drivers/regulator/core.c @@ -2253,6 +2253,7 @@ void regulator_unregister(struct regulator_dev *rdev) return; mutex_lock(®ulator_list_mutex); + WARN_ON(rdev->open_count); unset_regulator_supplies(rdev); list_del(&rdev->list); if (rdev->supply) -- cgit v1.2.3 From 9ed2099edca26d07947beb42c12bd1d6669e82bc Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Tue, 21 Jul 2009 16:00:26 +0100 Subject: regulator: Fix support for deviceless supply mappings The patch to add support for looking up consumers by device name had the side effect of causing us to require a device which is at best premature since at least cpufreq still operates outside the device model. Remove that requirement. Reported-by: Haojian Zhuang Signed-off-by: Mark Brown Signed-off-by: Liam Girdwood --- drivers/regulator/core.c | 18 +++++++++++++----- 1 file changed, 13 insertions(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/regulator/core.c b/drivers/regulator/core.c index 79a6910eb89..e38db55600e 100644 --- a/drivers/regulator/core.c +++ b/drivers/regulator/core.c @@ -872,6 +872,7 @@ static int set_consumer_device_supply(struct regulator_dev *rdev, const char *supply) { struct regulator_map *node; + int has_dev; if (consumer_dev && consumer_dev_name) return -EINVAL; @@ -882,6 +883,11 @@ static int set_consumer_device_supply(struct regulator_dev *rdev, if (supply == NULL) return -EINVAL; + if (consumer_dev_name != NULL) + has_dev = 1; + else + has_dev = 0; + list_for_each_entry(node, ®ulator_map_list, list) { if (consumer_dev_name != node->dev_name) continue; @@ -896,17 +902,19 @@ static int set_consumer_device_supply(struct regulator_dev *rdev, return -EBUSY; } - node = kmalloc(sizeof(struct regulator_map), GFP_KERNEL); + node = kzalloc(sizeof(struct regulator_map), GFP_KERNEL); if (node == NULL) return -ENOMEM; node->regulator = rdev; - node->dev_name = kstrdup(consumer_dev_name, GFP_KERNEL); node->supply = supply; - if (node->dev_name == NULL) { - kfree(node); - return -ENOMEM; + if (has_dev) { + node->dev_name = kstrdup(consumer_dev_name, GFP_KERNEL); + if (node->dev_name == NULL) { + kfree(node); + return -ENOMEM; + } } list_add(&node->list, ®ulator_map_list); -- cgit v1.2.3 From 72b86876d437a33253a47373579787b6dcc3bd36 Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Tue, 21 Jul 2009 16:00:27 +0100 Subject: regulator: Improve virtual consumer probe error handling Report errors to the user and try harder to clean up if we're not able to probe. Signed-off-by: Mark Brown Signed-off-by: Liam Girdwood --- drivers/regulator/virtual.c | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/regulator/virtual.c b/drivers/regulator/virtual.c index 144110788fd..addc032c84b 100644 --- a/drivers/regulator/virtual.c +++ b/drivers/regulator/virtual.c @@ -286,8 +286,7 @@ static int regulator_virtual_consumer_probe(struct platform_device *pdev) drvdata = kzalloc(sizeof(struct virtual_consumer_data), GFP_KERNEL); if (drvdata == NULL) { - ret = -ENOMEM; - goto err; + return -ENOMEM; } mutex_init(&drvdata->lock); @@ -302,8 +301,11 @@ static int regulator_virtual_consumer_probe(struct platform_device *pdev) for (i = 0; i < ARRAY_SIZE(attributes); i++) { ret = device_create_file(&pdev->dev, attributes[i]); - if (ret != 0) - goto err; + if (ret != 0) { + dev_err(&pdev->dev, "Failed to create attr %d: %d\n", + i, ret); + goto err_regulator; + } } drvdata->mode = regulator_get_mode(drvdata->regulator); @@ -312,6 +314,8 @@ static int regulator_virtual_consumer_probe(struct platform_device *pdev) return 0; +err_regulator: + regulator_put(drvdata->regulator); err: for (i = 0; i < ARRAY_SIZE(attributes); i++) device_remove_file(&pdev->dev, attributes[i]); -- cgit v1.2.3 From c6db182822e292575b5beb56c003e95f616407f4 Mon Sep 17 00:00:00 2001 From: Mike Rapoport Date: Sun, 26 Jul 2009 13:33:04 +0300 Subject: regulator: da903x: consolidate DA903[045]_DVC macros Signed-off-by: Mike Rapoport Signed-off-by: Liam Girdwood --- drivers/regulator/da903x.c | 66 ++++++++++++---------------------------------- 1 file changed, 17 insertions(+), 49 deletions(-) (limited to 'drivers') diff --git a/drivers/regulator/da903x.c b/drivers/regulator/da903x.c index 236de113439..7d9c2506d21 100644 --- a/drivers/regulator/da903x.c +++ b/drivers/regulator/da903x.c @@ -404,69 +404,25 @@ static struct regulator_ops da9034_regulator_ldo12_ops = { .enable_bit = (ebit), \ } -#define DA9030_DVC(_id, min, max, step, vreg, nbits, ureg, ubit, ereg, ebit) \ +#define DA903x_DVC(_pmic, _id, min, max, step, vreg, nbits, ureg, ubit, ereg, ebit) \ { \ .desc = { \ .name = #_id, \ .ops = &da9034_regulator_dvc_ops, \ .type = REGULATOR_VOLTAGE, \ - .id = DA9030_ID_##_id, \ + .id = _pmic##_ID_##_id, \ .n_voltages = (step) ? ((max - min) / step + 1) : 1, \ .owner = THIS_MODULE, \ }, \ .min_uV = (min) * 1000, \ .max_uV = (max) * 1000, \ .step_uV = (step) * 1000, \ - .vol_reg = DA9030_##vreg, \ - .vol_shift = (0), \ - .vol_nbits = (nbits), \ - .update_reg = DA9030_##ureg, \ - .update_bit = (ubit), \ - .enable_reg = DA9030_##ereg, \ - .enable_bit = (ebit), \ -} - -#define DA9034_DVC(_id, min, max, step, vreg, nbits, ureg, ubit, ereg, ebit) \ -{ \ - .desc = { \ - .name = #_id, \ - .ops = &da9034_regulator_dvc_ops, \ - .type = REGULATOR_VOLTAGE, \ - .id = DA9034_ID_##_id, \ - .n_voltages = (step) ? ((max - min) / step + 1) : 1, \ - .owner = THIS_MODULE, \ - }, \ - .min_uV = (min) * 1000, \ - .max_uV = (max) * 1000, \ - .step_uV = (step) * 1000, \ - .vol_reg = DA9034_##vreg, \ - .vol_shift = (0), \ - .vol_nbits = (nbits), \ - .update_reg = DA9034_##ureg, \ - .update_bit = (ubit), \ - .enable_reg = DA9034_##ereg, \ - .enable_bit = (ebit), \ -} - -#define DA9035_DVC(_id, min, max, step, vreg, nbits, ureg, ubit, ereg, ebit) \ -{ \ - .desc = { \ - .name = #_id, \ - .ops = &da9034_regulator_dvc_ops, \ - .type = REGULATOR_VOLTAGE, \ - .id = DA9035_ID_##_id, \ - .n_voltages = (step) ? ((max - min) / step + 1) : 1, \ - .owner = THIS_MODULE, \ - }, \ - .min_uV = (min) * 1000, \ - .max_uV = (max) * 1000, \ - .step_uV = (step) * 1000, \ - .vol_reg = DA9035_##vreg, \ + .vol_reg = _pmic##_##vreg, \ .vol_shift = (0), \ .vol_nbits = (nbits), \ - .update_reg = DA9035_##ureg, \ + .update_reg = _pmic##_##ureg, \ .update_bit = (ubit), \ - .enable_reg = DA9035_##ereg, \ + .enable_reg = _pmic##_##ereg, \ .enable_bit = (ebit), \ } @@ -476,6 +432,18 @@ static struct regulator_ops da9034_regulator_ldo12_ops = { #define DA9030_LDO(_id, min, max, step, vreg, shift, nbits, ereg, ebit) \ DA903x_LDO(DA9030, _id, min, max, step, vreg, shift, nbits, ereg, ebit) +#define DA9030_DVC(_id, min, max, step, vreg, nbits, ureg, ubit, ereg, ebit) \ + DA903x_DVC(DA9030, _id, min, max, step, vreg, nbits, ureg, ubit, \ + ereg, ebit) + +#define DA9034_DVC(_id, min, max, step, vreg, nbits, ureg, ubit, ereg, ebit) \ + DA903x_DVC(DA9034, _id, min, max, step, vreg, nbits, ureg, ubit, \ + ereg, ebit) + +#define DA9035_DVC(_id, min, max, step, vreg, nbits, ureg, ubit, ereg, ebit) \ + DA903x_DVC(DA9035, _id, min, max, step, vreg, nbits, ureg, ubit, \ + ereg, ebit) + static struct da903x_regulator_info da903x_regulator_info[] = { /* DA9030 */ DA9030_DVC(BUCK2, 850, 1625, 25, BUCK2DVM1, 5, BUCK2DVM1, 7, RCTL11, 0), -- cgit v1.2.3 From c53ad7fe5759cea10137c9e176d14f8c8f22d286 Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Mon, 3 Aug 2009 18:49:53 +0100 Subject: regulator: More explict error reporting for fixed regulator Signed-off-by: Mark Brown Signed-off-by: Liam Girdwood --- drivers/regulator/fixed.c | 3 +++ 1 file changed, 3 insertions(+) (limited to 'drivers') diff --git a/drivers/regulator/fixed.c b/drivers/regulator/fixed.c index cdc674fb46c..9c7f956d57c 100644 --- a/drivers/regulator/fixed.c +++ b/drivers/regulator/fixed.c @@ -70,12 +70,14 @@ static int regulator_fixed_voltage_probe(struct platform_device *pdev) drvdata = kzalloc(sizeof(struct fixed_voltage_data), GFP_KERNEL); if (drvdata == NULL) { + dev_err(&pdev->dev, "Failed to allocate device data\n"); ret = -ENOMEM; goto err; } drvdata->desc.name = kstrdup(config->supply_name, GFP_KERNEL); if (drvdata->desc.name == NULL) { + dev_err(&pdev->dev, "Failed to allocate supply name\n"); ret = -ENOMEM; goto err; } @@ -90,6 +92,7 @@ static int regulator_fixed_voltage_probe(struct platform_device *pdev) config->init_data, drvdata); if (IS_ERR(drvdata->dev)) { ret = PTR_ERR(drvdata->dev); + dev_err(&pdev->dev, "Failed to register regulator: %d\n", ret); goto err_name; } -- cgit v1.2.3 From b39480ac37951de126455991744c9dbb61bbb839 Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Mon, 3 Aug 2009 18:49:54 +0100 Subject: regulator: Check for constraints before using them for name Signed-off-by: Mark Brown Signed-off-by: Liam Girdwood --- drivers/regulator/core.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/regulator/core.c b/drivers/regulator/core.c index e38db55600e..6e0c723371d 100644 --- a/drivers/regulator/core.c +++ b/drivers/regulator/core.c @@ -232,7 +232,7 @@ static ssize_t regulator_name_show(struct device *dev, struct regulator_dev *rdev = dev_get_drvdata(dev); const char *name; - if (rdev->constraints->name) + if (rdev->constraints && rdev->constraints->name) name = rdev->constraints->name; else if (rdev->desc->name) name = rdev->desc->name; -- cgit v1.2.3 From f25e0b4fcc38d120e704c377791158c4b2a54daa Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Mon, 3 Aug 2009 18:49:55 +0100 Subject: regulator: Check for constraints in regulator_init_complete() Signed-off-by: Mark Brown Signed-off-by: Liam Girdwood --- drivers/regulator/core.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/regulator/core.c b/drivers/regulator/core.c index 6e0c723371d..dfbf4312ec3 100644 --- a/drivers/regulator/core.c +++ b/drivers/regulator/core.c @@ -2409,14 +2409,14 @@ static int __init regulator_init_complete(void) ops = rdev->desc->ops; c = rdev->constraints; - if (c->name) + if (c && c->name) name = c->name; else if (rdev->desc->name) name = rdev->desc->name; else name = "regulator"; - if (!ops->disable || c->always_on) + if (!ops->disable || (c && c->always_on)) continue; mutex_lock(&rdev->mutex); -- cgit v1.2.3 From 9332546fe88fa88bf6a7d9b1dce53ff5d314934e Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Mon, 3 Aug 2009 18:49:56 +0100 Subject: regulator: Push locking for regulator_is_enabled() out Allows use by more of the internal regulator API code. Signed-off-by: Mark Brown Signed-off-by: Liam Girdwood --- drivers/regulator/core.c | 30 ++++++++++++++++-------------- 1 file changed, 16 insertions(+), 14 deletions(-) (limited to 'drivers') diff --git a/drivers/regulator/core.c b/drivers/regulator/core.c index dfbf4312ec3..60fcd986ff3 100644 --- a/drivers/regulator/core.c +++ b/drivers/regulator/core.c @@ -280,8 +280,13 @@ static ssize_t regulator_state_show(struct device *dev, struct device_attribute *attr, char *buf) { struct regulator_dev *rdev = dev_get_drvdata(dev); + ssize_t ret; + + mutex_lock(&rdev->mutex); + ret = regulator_print_state(buf, _regulator_is_enabled(rdev)); + mutex_unlock(&rdev->mutex); - return regulator_print_state(buf, _regulator_is_enabled(rdev)); + return ret; } static DEVICE_ATTR(state, 0444, regulator_state_show, NULL); @@ -1365,20 +1370,11 @@ EXPORT_SYMBOL_GPL(regulator_force_disable); static int _regulator_is_enabled(struct regulator_dev *rdev) { - int ret; - - mutex_lock(&rdev->mutex); - /* sanity check */ - if (!rdev->desc->ops->is_enabled) { - ret = -EINVAL; - goto out; - } + if (!rdev->desc->ops->is_enabled) + return -EINVAL; - ret = rdev->desc->ops->is_enabled(rdev); -out: - mutex_unlock(&rdev->mutex); - return ret; + return rdev->desc->ops->is_enabled(rdev); } /** @@ -1395,7 +1391,13 @@ out: */ int regulator_is_enabled(struct regulator *regulator) { - return _regulator_is_enabled(regulator->rdev); + int ret; + + mutex_lock(®ulator->rdev->mutex); + ret = _regulator_is_enabled(regulator->rdev); + mutex_unlock(®ulator->rdev->mutex); + + return ret; } EXPORT_SYMBOL_GPL(regulator_is_enabled); -- cgit v1.2.3 From 9a2372fa7a403ba327873d0208a619d781a8a150 Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Mon, 3 Aug 2009 18:49:57 +0100 Subject: regulator: regulator_enable() permission checking The regulator_enable() code wasn't actually checking that the machine constraints had given permission to enable the regulator. Add code to do that, but only if the regulator is not already on due to something like always_on or being left on at startup since in those cases there's no physical change being introduced and the constraint wouldn't make any sense. Also add matching code for disable(). We need to do less there since either regulator_enable() should have succeeded first or the board setup makes no sense. Signed-off-by: Mark Brown Signed-off-by: Liam Girdwood --- drivers/regulator/core.c | 56 +++++++++++++++++++++++++++++++----------------- 1 file changed, 36 insertions(+), 20 deletions(-) (limited to 'drivers') diff --git a/drivers/regulator/core.c b/drivers/regulator/core.c index 60fcd986ff3..dbf27bf028c 100644 --- a/drivers/regulator/core.c +++ b/drivers/regulator/core.c @@ -1191,16 +1191,21 @@ void regulator_put(struct regulator *regulator) } EXPORT_SYMBOL_GPL(regulator_put); +static int _regulator_can_change_status(struct regulator_dev *rdev) +{ + if (!rdev->constraints) + return 0; + + if (rdev->constraints->valid_ops_mask & REGULATOR_CHANGE_STATUS) + return 1; + else + return 0; +} + /* locks held by regulator_enable() */ static int _regulator_enable(struct regulator_dev *rdev) { - int ret = -EINVAL; - - if (!rdev->constraints) { - printk(KERN_ERR "%s: %s has no constraints\n", - __func__, rdev->desc->name); - return ret; - } + int ret; /* do we need to enable the supply regulator first */ if (rdev->supply) { @@ -1213,24 +1218,34 @@ static int _regulator_enable(struct regulator_dev *rdev) } /* check voltage and requested load before enabling */ - if (rdev->desc->ops->enable) { + if (rdev->constraints && + (rdev->constraints->valid_ops_mask & REGULATOR_CHANGE_DRMS)) + drms_uA_update(rdev); - if (rdev->constraints && - (rdev->constraints->valid_ops_mask & - REGULATOR_CHANGE_DRMS)) - drms_uA_update(rdev); - - ret = rdev->desc->ops->enable(rdev); - if (ret < 0) { - printk(KERN_ERR "%s: failed to enable %s: %d\n", + if (rdev->use_count == 0) { + /* The regulator may on if it's not switchable or left on */ + ret = _regulator_is_enabled(rdev); + if (ret == -EINVAL || ret == 0) { + if (!_regulator_can_change_status(rdev)) + return -EPERM; + + if (rdev->desc->ops->enable) { + ret = rdev->desc->ops->enable(rdev); + if (ret < 0) + return ret; + } else { + return -EINVAL; + } + } else { + printk(KERN_ERR "%s: is_enabled() failed for %s: %d\n", __func__, rdev->desc->name, ret); return ret; } - rdev->use_count++; - return ret; } - return ret; + rdev->use_count++; + + return 0; } /** @@ -1270,7 +1285,8 @@ static int _regulator_disable(struct regulator_dev *rdev) if (rdev->use_count == 1 && !rdev->constraints->always_on) { /* we are last user */ - if (rdev->desc->ops->disable) { + if (_regulator_can_change_status(rdev) && + rdev->desc->ops->disable) { ret = rdev->desc->ops->disable(rdev); if (ret < 0) { printk(KERN_ERR "%s: failed to disable %s\n", -- cgit v1.2.3 From a6576cff1801e2f1a9f328f02bd4cbcab7b03f91 Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Tue, 4 Aug 2009 02:03:52 +0200 Subject: Regulator: Implement list_voltage for pcf50633 regulator driver. This patch implements list_voltage for the pcf50644 regulator driver. As the voltages are linearly scaled the code to convert register values to voltages can be reused and most of the code can be shared with get_voltage. Signed-off-by: Lars-Peter Clausen Signed-off-by: Liam Girdwood --- drivers/regulator/pcf50633-regulator.c | 96 ++++++++++++++++++++++------------ 1 file changed, 64 insertions(+), 32 deletions(-) (limited to 'drivers') diff --git a/drivers/regulator/pcf50633-regulator.c b/drivers/regulator/pcf50633-regulator.c index 70ba7755765..0803ffe6236 100644 --- a/drivers/regulator/pcf50633-regulator.c +++ b/drivers/regulator/pcf50633-regulator.c @@ -24,11 +24,12 @@ #include #include -#define PCF50633_REGULATOR(_name, _id) \ +#define PCF50633_REGULATOR(_name, _id, _n) \ { \ .name = _name, \ .id = _id, \ .ops = &pcf50633_regulator_ops, \ + .n_voltages = _n, \ .type = REGULATOR_VOLTAGE, \ .owner = THIS_MODULE, \ } @@ -149,11 +150,42 @@ static int pcf50633_regulator_set_voltage(struct regulator_dev *rdev, return pcf50633_reg_write(pcf, regnr, volt_bits); } +static int pcf50633_regulator_voltage_value(enum pcf50633_regulator_id id, + u8 bits) +{ + int millivolts; + + switch (id) { + case PCF50633_REGULATOR_AUTO: + millivolts = auto_voltage_value(bits); + break; + case PCF50633_REGULATOR_DOWN1: + millivolts = down_voltage_value(bits); + break; + case PCF50633_REGULATOR_DOWN2: + millivolts = down_voltage_value(bits); + break; + case PCF50633_REGULATOR_LDO1: + case PCF50633_REGULATOR_LDO2: + case PCF50633_REGULATOR_LDO3: + case PCF50633_REGULATOR_LDO4: + case PCF50633_REGULATOR_LDO5: + case PCF50633_REGULATOR_LDO6: + case PCF50633_REGULATOR_HCLDO: + millivolts = ldo_voltage_value(bits); + break; + default: + return -EINVAL; + } + + return millivolts * 1000; +} + static int pcf50633_regulator_get_voltage(struct regulator_dev *rdev) { struct pcf50633 *pcf; - int regulator_id, millivolts, volt_bits; - u8 regnr; + int regulator_id; + u8 volt_bits, regnr; pcf = rdev_get_drvdata(rdev); @@ -164,33 +196,32 @@ static int pcf50633_regulator_get_voltage(struct regulator_dev *rdev) regnr = pcf50633_regulator_registers[regulator_id]; volt_bits = pcf50633_reg_read(pcf, regnr); - if (volt_bits < 0) - return -1; + + return pcf50633_regulator_voltage_value(regulator_id, volt_bits); +} + +static int pcf50633_regulator_list_voltage(struct regulator_dev *rdev, + unsigned int index) +{ + struct pcf50633 *pcf; + int regulator_id; + + pcf = rdev_get_drvdata(rdev); + + regulator_id = rdev_get_id(rdev); switch (regulator_id) { case PCF50633_REGULATOR_AUTO: - millivolts = auto_voltage_value(volt_bits); - break; - case PCF50633_REGULATOR_DOWN1: - millivolts = down_voltage_value(volt_bits); - break; - case PCF50633_REGULATOR_DOWN2: - millivolts = down_voltage_value(volt_bits); + index += 0x2f; break; - case PCF50633_REGULATOR_LDO1: - case PCF50633_REGULATOR_LDO2: - case PCF50633_REGULATOR_LDO3: - case PCF50633_REGULATOR_LDO4: - case PCF50633_REGULATOR_LDO5: - case PCF50633_REGULATOR_LDO6: case PCF50633_REGULATOR_HCLDO: - millivolts = ldo_voltage_value(volt_bits); + index += 0x01; break; default: - return -EINVAL; + break; } - return millivolts * 1000; + return pcf50633_regulator_voltage_value(regulator_id, index); } static int pcf50633_regulator_enable(struct regulator_dev *rdev) @@ -246,6 +277,7 @@ static int pcf50633_regulator_is_enabled(struct regulator_dev *rdev) static struct regulator_ops pcf50633_regulator_ops = { .set_voltage = pcf50633_regulator_set_voltage, .get_voltage = pcf50633_regulator_get_voltage, + .list_voltage = pcf50633_regulator_list_voltage, .enable = pcf50633_regulator_enable, .disable = pcf50633_regulator_disable, .is_enabled = pcf50633_regulator_is_enabled, @@ -253,27 +285,27 @@ static struct regulator_ops pcf50633_regulator_ops = { static struct regulator_desc regulators[] = { [PCF50633_REGULATOR_AUTO] = - PCF50633_REGULATOR("auto", PCF50633_REGULATOR_AUTO), + PCF50633_REGULATOR("auto", PCF50633_REGULATOR_AUTO, 80), [PCF50633_REGULATOR_DOWN1] = - PCF50633_REGULATOR("down1", PCF50633_REGULATOR_DOWN1), + PCF50633_REGULATOR("down1", PCF50633_REGULATOR_DOWN1, 95), [PCF50633_REGULATOR_DOWN2] = - PCF50633_REGULATOR("down2", PCF50633_REGULATOR_DOWN2), + PCF50633_REGULATOR("down2", PCF50633_REGULATOR_DOWN2, 95), [PCF50633_REGULATOR_LDO1] = - PCF50633_REGULATOR("ldo1", PCF50633_REGULATOR_LDO1), + PCF50633_REGULATOR("ldo1", PCF50633_REGULATOR_LDO1, 27), [PCF50633_REGULATOR_LDO2] = - PCF50633_REGULATOR("ldo2", PCF50633_REGULATOR_LDO2), + PCF50633_REGULATOR("ldo2", PCF50633_REGULATOR_LDO2, 27), [PCF50633_REGULATOR_LDO3] = - PCF50633_REGULATOR("ldo3", PCF50633_REGULATOR_LDO3), + PCF50633_REGULATOR("ldo3", PCF50633_REGULATOR_LDO3, 27), [PCF50633_REGULATOR_LDO4] = - PCF50633_REGULATOR("ldo4", PCF50633_REGULATOR_LDO4), + PCF50633_REGULATOR("ldo4", PCF50633_REGULATOR_LDO4, 27), [PCF50633_REGULATOR_LDO5] = - PCF50633_REGULATOR("ldo5", PCF50633_REGULATOR_LDO5), + PCF50633_REGULATOR("ldo5", PCF50633_REGULATOR_LDO5, 27), [PCF50633_REGULATOR_LDO6] = - PCF50633_REGULATOR("ldo6", PCF50633_REGULATOR_LDO6), + PCF50633_REGULATOR("ldo6", PCF50633_REGULATOR_LDO6, 27), [PCF50633_REGULATOR_HCLDO] = - PCF50633_REGULATOR("hcldo", PCF50633_REGULATOR_HCLDO), + PCF50633_REGULATOR("hcldo", PCF50633_REGULATOR_HCLDO, 26), [PCF50633_REGULATOR_MEMLDO] = - PCF50633_REGULATOR("memldo", PCF50633_REGULATOR_MEMLDO), + PCF50633_REGULATOR("memldo", PCF50633_REGULATOR_MEMLDO, 0), }; static int __devinit pcf50633_regulator_probe(struct platform_device *pdev) -- cgit v1.2.3 From 86d9884b6a3646bc24e57430f1f694c5171c1bf6 Mon Sep 17 00:00:00 2001 From: Roger Quadros Date: Thu, 6 Aug 2009 19:37:29 +0300 Subject: regulator: Add GPIO enable control to fixed voltage regulator driver Now fixed regulators that have their enable pin connected to a GPIO line can use the fixed regulator driver for regulator enable/disable control. The GPIO number and polarity information is passed through platform data. GPIO enable control is achieved using gpiolib. Signed-off-by: Roger Quadros Reviewed-by: Philipp Zabel Reviewed-by: Felipe Balbi Acked-by: Mark Brown Signed-off-by: Liam Girdwood --- drivers/regulator/fixed.c | 88 +++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 86 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/regulator/fixed.c b/drivers/regulator/fixed.c index 9c7f956d57c..f8b295700d7 100644 --- a/drivers/regulator/fixed.c +++ b/drivers/regulator/fixed.c @@ -5,6 +5,9 @@ * * Author: Mark Brown * + * Copyright (c) 2009 Nokia Corporation + * Roger Quadros + * * 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 @@ -20,20 +23,45 @@ #include #include #include +#include struct fixed_voltage_data { struct regulator_desc desc; struct regulator_dev *dev; int microvolts; + int gpio; + unsigned enable_high:1; + unsigned is_enabled:1; }; static int fixed_voltage_is_enabled(struct regulator_dev *dev) { - return 1; + struct fixed_voltage_data *data = rdev_get_drvdata(dev); + + return data->is_enabled; } static int fixed_voltage_enable(struct regulator_dev *dev) { + struct fixed_voltage_data *data = rdev_get_drvdata(dev); + + if (gpio_is_valid(data->gpio)) { + gpio_set_value_cansleep(data->gpio, data->enable_high); + data->is_enabled = 1; + } + + return 0; +} + +static int fixed_voltage_disable(struct regulator_dev *dev) +{ + struct fixed_voltage_data *data = rdev_get_drvdata(dev); + + if (gpio_is_valid(data->gpio)) { + gpio_set_value_cansleep(data->gpio, !data->enable_high); + data->is_enabled = 0; + } + return 0; } @@ -58,6 +86,7 @@ static int fixed_voltage_list_voltage(struct regulator_dev *dev, static struct regulator_ops fixed_voltage_ops = { .is_enabled = fixed_voltage_is_enabled, .enable = fixed_voltage_enable, + .disable = fixed_voltage_disable, .get_voltage = fixed_voltage_get_voltage, .list_voltage = fixed_voltage_list_voltage, }; @@ -87,13 +116,62 @@ static int regulator_fixed_voltage_probe(struct platform_device *pdev) drvdata->desc.n_voltages = 1; drvdata->microvolts = config->microvolts; + drvdata->gpio = config->gpio; + + if (gpio_is_valid(config->gpio)) { + drvdata->enable_high = config->enable_high; + + /* FIXME: Remove below print warning + * + * config->gpio must be set to -EINVAL by platform code if + * GPIO control is not required. However, early adopters + * not requiring GPIO control may forget to initialize + * config->gpio to -EINVAL. This will cause GPIO 0 to be used + * for GPIO control. + * + * This warning will be removed once there are a couple of users + * for this driver. + */ + if (!config->gpio) + dev_warn(&pdev->dev, + "using GPIO 0 for regulator enable control\n"); + + ret = gpio_request(config->gpio, config->supply_name); + if (ret) { + dev_err(&pdev->dev, + "Could not obtain regulator enable GPIO %d: %d\n", + config->gpio, ret); + goto err_name; + } + + /* set output direction without changing state + * to prevent glitch + */ + drvdata->is_enabled = config->enabled_at_boot; + ret = drvdata->is_enabled ? + config->enable_high : !config->enable_high; + + ret = gpio_direction_output(config->gpio, ret); + if (ret) { + dev_err(&pdev->dev, + "Could not configure regulator enable GPIO %d direction: %d\n", + config->gpio, ret); + goto err_gpio; + } + + } else { + /* Regulator without GPIO control is considered + * always enabled + */ + drvdata->is_enabled = 1; + } drvdata->dev = regulator_register(&drvdata->desc, &pdev->dev, config->init_data, drvdata); if (IS_ERR(drvdata->dev)) { ret = PTR_ERR(drvdata->dev); dev_err(&pdev->dev, "Failed to register regulator: %d\n", ret); - goto err_name; + goto err_gpio; } platform_set_drvdata(pdev, drvdata); @@ -103,6 +181,9 @@ static int regulator_fixed_voltage_probe(struct platform_device *pdev) return 0; +err_gpio: + if (gpio_is_valid(config->gpio)) + gpio_free(config->gpio); err_name: kfree(drvdata->desc.name); err: @@ -118,6 +199,9 @@ static int regulator_fixed_voltage_remove(struct platform_device *pdev) kfree(drvdata->desc.name); kfree(drvdata); + if (gpio_is_valid(drvdata->gpio)) + gpio_free(drvdata->gpio); + return 0; } -- cgit v1.2.3 From e9d62698e8e5228638093c48783eb9dda788f1c3 Mon Sep 17 00:00:00 2001 From: Felipe Balbi Date: Mon, 10 Aug 2009 09:05:13 +0300 Subject: regulator: userspace: use sysfs_create_group and avoid introducing our own loops for creating several sysfs entries. Signed-off-by: Felipe Balbi Acked-by: Mark Brown Acked-by: Mike Rapoport Signed-off-by: Liam Girdwood --- drivers/regulator/userspace-consumer.c | 45 +++++++++++++++++----------------- 1 file changed, 23 insertions(+), 22 deletions(-) (limited to 'drivers') diff --git a/drivers/regulator/userspace-consumer.c b/drivers/regulator/userspace-consumer.c index 06d2fa96a8b..44917da4ac9 100644 --- a/drivers/regulator/userspace-consumer.c +++ b/drivers/regulator/userspace-consumer.c @@ -93,16 +93,21 @@ static ssize_t reg_set_state(struct device *dev, struct device_attribute *attr, static DEVICE_ATTR(name, 0444, reg_show_name, NULL); static DEVICE_ATTR(state, 0644, reg_show_state, reg_set_state); -static struct device_attribute *attributes[] = { - &dev_attr_name, - &dev_attr_state, +static struct attribute *attributes[] = { + &dev_attr_name.attr, + &dev_attr_state.attr, + NULL, +}; + +static const struct attribute_group attr_group = { + .attrs = attributes, }; static int regulator_userspace_consumer_probe(struct platform_device *pdev) { struct regulator_userspace_consumer_data *pdata; struct userspace_consumer_data *drvdata; - int ret, i; + int ret; pdata = pdev->dev.platform_data; if (!pdata) @@ -125,31 +130,29 @@ static int regulator_userspace_consumer_probe(struct platform_device *pdev) goto err_alloc_supplies; } - for (i = 0; i < ARRAY_SIZE(attributes); i++) { - ret = device_create_file(&pdev->dev, attributes[i]); - if (ret != 0) - goto err_create_attrs; - } + ret = sysfs_create_group(&pdev->dev.kobj, &attr_group); + if (ret != 0) + goto err_create_attrs; - if (pdata->init_on) + if (pdata->init_on) { ret = regulator_bulk_enable(drvdata->num_supplies, drvdata->supplies); - - drvdata->enabled = pdata->init_on; - - if (ret) { - dev_err(&pdev->dev, "Failed to set initial state: %d\n", ret); - goto err_create_attrs; + if (ret) { + dev_err(&pdev->dev, + "Failed to set initial state: %d\n", ret); + goto err_enable; + } } + drvdata->enabled = pdata->init_on; platform_set_drvdata(pdev, drvdata); return 0; -err_create_attrs: - for (i = 0; i < ARRAY_SIZE(attributes); i++) - device_remove_file(&pdev->dev, attributes[i]); +err_enable: + sysfs_remove_group(&pdev->dev.kobj, &attr_group); +err_create_attrs: regulator_bulk_free(drvdata->num_supplies, drvdata->supplies); err_alloc_supplies: @@ -160,10 +163,8 @@ err_alloc_supplies: static int regulator_userspace_consumer_remove(struct platform_device *pdev) { struct userspace_consumer_data *data = platform_get_drvdata(pdev); - int i; - for (i = 0; i < ARRAY_SIZE(attributes); i++) - device_remove_file(&pdev->dev, attributes[i]); + sysfs_remove_group(&pdev->dev.kobj, &attr_group); if (data->enabled) regulator_bulk_disable(data->num_supplies, data->supplies); -- cgit v1.2.3 From 30e6599d317ec83c664f341f18b5b2b57b831a6d Mon Sep 17 00:00:00 2001 From: Anuj Aggarwal Date: Fri, 21 Aug 2009 00:39:31 +0530 Subject: Regulator: Add TPS65023 regulator driver Adding support for TI TPS65023 regulator driver Signed-off-by: Anuj Aggarwal Acked-by: Mark Brown Signed-off-by: Liam Girdwood --- drivers/regulator/tps65023-regulator.c | 631 +++++++++++++++++++++++++++++++++ 1 file changed, 631 insertions(+) create mode 100644 drivers/regulator/tps65023-regulator.c (limited to 'drivers') diff --git a/drivers/regulator/tps65023-regulator.c b/drivers/regulator/tps65023-regulator.c new file mode 100644 index 00000000000..1e54f46af67 --- /dev/null +++ b/drivers/regulator/tps65023-regulator.c @@ -0,0 +1,631 @@ +/* + * tps65023-regulator.c + * + * Supports TPS65023 Regulator + * + * Copyright (C) 2009 Texas Instrument Incorporated - http://www.ti.com/ + * + * 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 version 2. + * + * This program is distributed "as is" WITHOUT ANY WARRANTY of any kind, + * whether express or implied; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* Register definitions */ +#define TPS65023_REG_VERSION 0 +#define TPS65023_REG_PGOODZ 1 +#define TPS65023_REG_MASK 2 +#define TPS65023_REG_REG_CTRL 3 +#define TPS65023_REG_CON_CTRL 4 +#define TPS65023_REG_CON_CTRL2 5 +#define TPS65023_REG_DEF_CORE 6 +#define TPS65023_REG_DEFSLEW 7 +#define TPS65023_REG_LDO_CTRL 8 + +/* PGOODZ bitfields */ +#define TPS65023_PGOODZ_PWRFAILZ BIT(7) +#define TPS65023_PGOODZ_LOWBATTZ BIT(6) +#define TPS65023_PGOODZ_VDCDC1 BIT(5) +#define TPS65023_PGOODZ_VDCDC2 BIT(4) +#define TPS65023_PGOODZ_VDCDC3 BIT(3) +#define TPS65023_PGOODZ_LDO2 BIT(2) +#define TPS65023_PGOODZ_LDO1 BIT(1) + +/* MASK bitfields */ +#define TPS65023_MASK_PWRFAILZ BIT(7) +#define TPS65023_MASK_LOWBATTZ BIT(6) +#define TPS65023_MASK_VDCDC1 BIT(5) +#define TPS65023_MASK_VDCDC2 BIT(4) +#define TPS65023_MASK_VDCDC3 BIT(3) +#define TPS65023_MASK_LDO2 BIT(2) +#define TPS65023_MASK_LDO1 BIT(1) + +/* REG_CTRL bitfields */ +#define TPS65023_REG_CTRL_VDCDC1_EN BIT(5) +#define TPS65023_REG_CTRL_VDCDC2_EN BIT(4) +#define TPS65023_REG_CTRL_VDCDC3_EN BIT(3) +#define TPS65023_REG_CTRL_LDO2_EN BIT(2) +#define TPS65023_REG_CTRL_LDO1_EN BIT(1) + +/* LDO_CTRL bitfields */ +#define TPS65023_LDO_CTRL_LDOx_SHIFT(ldo_id) ((ldo_id)*4) +#define TPS65023_LDO_CTRL_LDOx_MASK(ldo_id) (0xF0 >> ((ldo_id)*4)) + +/* Number of step-down converters available */ +#define TPS65023_NUM_DCDC 3 +/* Number of LDO voltage regulators available */ +#define TPS65023_NUM_LDO 2 +/* Number of total regulators available */ +#define TPS65023_NUM_REGULATOR (TPS65023_NUM_DCDC + TPS65023_NUM_LDO) + +/* DCDCs */ +#define TPS65023_DCDC_1 0 +#define TPS65023_DCDC_2 1 +#define TPS65023_DCDC_3 2 +/* LDOs */ +#define TPS65023_LDO_1 3 +#define TPS65023_LDO_2 4 + +#define TPS65023_MAX_REG_ID TPS65023_LDO_2 + +/* Supported voltage values for regulators */ +static const u16 VDCDC1_VSEL_table[] = { + 800, 825, 850, 875, + 900, 925, 950, 975, + 1000, 1025, 1050, 1075, + 1100, 1125, 1150, 1175, + 1200, 1225, 1250, 1275, + 1300, 1325, 1350, 1375, + 1400, 1425, 1450, 1475, + 1500, 1525, 1550, 1600, +}; + +static const u16 LDO1_VSEL_table[] = { + 1000, 1100, 1300, 1800, + 2200, 2600, 2800, 3150, +}; + +static const u16 LDO2_VSEL_table[] = { + 1050, 1200, 1300, 1800, + 2500, 2800, 3000, 3300, +}; + +static unsigned int num_voltages[] = {ARRAY_SIZE(VDCDC1_VSEL_table), + 0, 0, ARRAY_SIZE(LDO1_VSEL_table), + ARRAY_SIZE(LDO2_VSEL_table)}; + +/* Regulator specific details */ +struct tps_info { + const char *name; + unsigned min_uV; + unsigned max_uV; + bool fixed; + u8 table_len; + const u16 *table; +}; + +/* PMIC details */ +struct tps_pmic { + struct regulator_desc desc[TPS65023_NUM_REGULATOR]; + struct i2c_client *client; + struct regulator_dev *rdev[TPS65023_NUM_REGULATOR]; + const struct tps_info *info[TPS65023_NUM_REGULATOR]; + struct mutex io_lock; +}; + +static inline int tps_65023_read(struct tps_pmic *tps, u8 reg) +{ + return i2c_smbus_read_byte_data(tps->client, reg); +} + +static inline int tps_65023_write(struct tps_pmic *tps, u8 reg, u8 val) +{ + return i2c_smbus_write_byte_data(tps->client, reg, val); +} + +static int tps_65023_set_bits(struct tps_pmic *tps, u8 reg, u8 mask) +{ + int err, data; + + mutex_lock(&tps->io_lock); + + data = tps_65023_read(tps, reg); + if (data < 0) { + dev_err(&tps->client->dev, "Read from reg 0x%x failed\n", reg); + err = data; + goto out; + } + + data |= mask; + err = tps_65023_write(tps, reg, data); + if (err) + dev_err(&tps->client->dev, "Write for reg 0x%x failed\n", reg); + +out: + mutex_unlock(&tps->io_lock); + return err; +} + +static int tps_65023_clear_bits(struct tps_pmic *tps, u8 reg, u8 mask) +{ + int err, data; + + mutex_lock(&tps->io_lock); + + data = tps_65023_read(tps, reg); + if (data < 0) { + dev_err(&tps->client->dev, "Read from reg 0x%x failed\n", reg); + err = data; + goto out; + } + + data &= ~mask; + + err = tps_65023_write(tps, reg, data); + if (err) + dev_err(&tps->client->dev, "Write for reg 0x%x failed\n", reg); + +out: + mutex_unlock(&tps->io_lock); + return err; + +} + +static int tps_65023_reg_read(struct tps_pmic *tps, u8 reg) +{ + int data; + + mutex_lock(&tps->io_lock); + + data = tps_65023_read(tps, reg); + if (data < 0) + dev_err(&tps->client->dev, "Read from reg 0x%x failed\n", reg); + + mutex_unlock(&tps->io_lock); + return data; +} + +static int tps_65023_reg_write(struct tps_pmic *tps, u8 reg, u8 val) +{ + int err; + + mutex_lock(&tps->io_lock); + + err = tps_65023_write(tps, reg, val); + if (err < 0) + dev_err(&tps->client->dev, "Write for reg 0x%x failed\n", reg); + + mutex_unlock(&tps->io_lock); + return err; +} + +static int tps65023_dcdc_is_enabled(struct regulator_dev *dev) +{ + struct tps_pmic *tps = rdev_get_drvdata(dev); + int data, dcdc = rdev_get_id(dev); + u8 shift; + + if (dcdc < TPS65023_DCDC_1 || dcdc > TPS65023_DCDC_3) + return -EINVAL; + + shift = TPS65023_NUM_REGULATOR - dcdc; + data = tps_65023_reg_read(tps, TPS65023_REG_REG_CTRL); + + if (data < 0) + return data; + else + return (data & 1< TPS65023_LDO_2) + return -EINVAL; + + shift = (ldo == TPS65023_LDO_1 ? 1 : 2); + data = tps_65023_reg_read(tps, TPS65023_REG_REG_CTRL); + + if (data < 0) + return data; + else + return (data & 1< TPS65023_DCDC_3) + return -EINVAL; + + shift = TPS65023_NUM_REGULATOR - dcdc; + return tps_65023_set_bits(tps, TPS65023_REG_REG_CTRL, 1 << shift); +} + +static int tps65023_dcdc_disable(struct regulator_dev *dev) +{ + struct tps_pmic *tps = rdev_get_drvdata(dev); + int dcdc = rdev_get_id(dev); + u8 shift; + + if (dcdc < TPS65023_DCDC_1 || dcdc > TPS65023_DCDC_3) + return -EINVAL; + + shift = TPS65023_NUM_REGULATOR - dcdc; + return tps_65023_clear_bits(tps, TPS65023_REG_REG_CTRL, 1 << shift); +} + +static int tps65023_ldo_enable(struct regulator_dev *dev) +{ + struct tps_pmic *tps = rdev_get_drvdata(dev); + int ldo = rdev_get_id(dev); + u8 shift; + + if (ldo < TPS65023_LDO_1 || ldo > TPS65023_LDO_2) + return -EINVAL; + + shift = (ldo == TPS65023_LDO_1 ? 1 : 2); + return tps_65023_set_bits(tps, TPS65023_REG_REG_CTRL, 1 << shift); +} + +static int tps65023_ldo_disable(struct regulator_dev *dev) +{ + struct tps_pmic *tps = rdev_get_drvdata(dev); + int ldo = rdev_get_id(dev); + u8 shift; + + if (ldo < TPS65023_LDO_1 || ldo > TPS65023_LDO_2) + return -EINVAL; + + shift = (ldo == TPS65023_LDO_1 ? 1 : 2); + return tps_65023_clear_bits(tps, TPS65023_REG_REG_CTRL, 1 << shift); +} + +static int tps65023_dcdc_get_voltage(struct regulator_dev *dev) +{ + struct tps_pmic *tps = rdev_get_drvdata(dev); + int data, dcdc = rdev_get_id(dev); + + if (dcdc < TPS65023_DCDC_1 || dcdc > TPS65023_DCDC_3) + return -EINVAL; + + if (dcdc == TPS65023_DCDC_1) { + data = tps_65023_reg_read(tps, TPS65023_REG_DEF_CORE); + if (data < 0) + return data; + data &= (tps->info[dcdc]->table_len - 1); + return tps->info[dcdc]->table[data] * 1000; + } else + return tps->info[dcdc]->min_uV; +} + +static int tps65023_dcdc_set_voltage(struct regulator_dev *dev, + int min_uV, int max_uV) +{ + struct tps_pmic *tps = rdev_get_drvdata(dev); + int dcdc = rdev_get_id(dev); + int vsel; + + if (dcdc != TPS65023_DCDC_1) + return -EINVAL; + + if (min_uV < tps->info[dcdc]->min_uV + || min_uV > tps->info[dcdc]->max_uV) + return -EINVAL; + if (max_uV < tps->info[dcdc]->min_uV + || max_uV > tps->info[dcdc]->max_uV) + return -EINVAL; + + for (vsel = 0; vsel < tps->info[dcdc]->table_len; vsel++) { + int mV = tps->info[dcdc]->table[vsel]; + int uV = mV * 1000; + + /* Break at the first in-range value */ + if (min_uV <= uV && uV <= max_uV) + break; + } + + /* write to the register in case we found a match */ + if (vsel == tps->info[dcdc]->table_len) + return -EINVAL; + else + return tps_65023_reg_write(tps, TPS65023_REG_DEF_CORE, vsel); +} + +static int tps65023_ldo_get_voltage(struct regulator_dev *dev) +{ + struct tps_pmic *tps = rdev_get_drvdata(dev); + int data, ldo = rdev_get_id(dev); + + if (ldo < TPS65023_LDO_1 || ldo > TPS65023_LDO_2) + return -EINVAL; + + data = tps_65023_reg_read(tps, TPS65023_REG_LDO_CTRL); + if (data < 0) + return data; + + data >>= (TPS65023_LDO_CTRL_LDOx_SHIFT(ldo - TPS65023_LDO_1)); + data &= (tps->info[ldo]->table_len - 1); + return tps->info[ldo]->table[data] * 1000; +} + +static int tps65023_ldo_set_voltage(struct regulator_dev *dev, + int min_uV, int max_uV) +{ + struct tps_pmic *tps = rdev_get_drvdata(dev); + int data, vsel, ldo = rdev_get_id(dev); + + if (ldo < TPS65023_LDO_1 || ldo > TPS65023_LDO_2) + return -EINVAL; + + if (min_uV < tps->info[ldo]->min_uV || min_uV > tps->info[ldo]->max_uV) + return -EINVAL; + if (max_uV < tps->info[ldo]->min_uV || max_uV > tps->info[ldo]->max_uV) + return -EINVAL; + + for (vsel = 0; vsel < tps->info[ldo]->table_len; vsel++) { + int mV = tps->info[ldo]->table[vsel]; + int uV = mV * 1000; + + /* Break at the first in-range value */ + if (min_uV <= uV && uV <= max_uV) + break; + } + + if (vsel == tps->info[ldo]->table_len) + return -EINVAL; + + data = tps_65023_reg_read(tps, TPS65023_REG_LDO_CTRL); + if (data < 0) + return data; + + data &= TPS65023_LDO_CTRL_LDOx_MASK(ldo - TPS65023_LDO_1); + data |= (vsel << (TPS65023_LDO_CTRL_LDOx_SHIFT(ldo - TPS65023_LDO_1))); + return tps_65023_reg_write(tps, TPS65023_REG_LDO_CTRL, data); +} + +static int tps65023_dcdc_list_voltage(struct regulator_dev *dev, + unsigned selector) +{ + struct tps_pmic *tps = rdev_get_drvdata(dev); + int dcdc = rdev_get_id(dev); + + if (dcdc < TPS65023_DCDC_1 || dcdc > TPS65023_DCDC_3) + return -EINVAL; + + if (dcdc == TPS65023_DCDC_1) { + if (selector >= tps->info[dcdc]->table_len) + return -EINVAL; + else + return tps->info[dcdc]->table[selector] * 1000; + } else + return tps->info[dcdc]->min_uV; +} + +static int tps65023_ldo_list_voltage(struct regulator_dev *dev, + unsigned selector) +{ + struct tps_pmic *tps = rdev_get_drvdata(dev); + int ldo = rdev_get_id(dev); + + if (ldo < TPS65023_LDO_1 || ldo > TPS65023_LDO_2) + return -EINVAL; + + if (selector >= tps->info[ldo]->table_len) + return -EINVAL; + else + return tps->info[ldo]->table[selector] * 1000; +} + +/* Operations permitted on VDCDCx */ +static struct regulator_ops tps65023_dcdc_ops = { + .is_enabled = tps65023_dcdc_is_enabled, + .enable = tps65023_dcdc_enable, + .disable = tps65023_dcdc_disable, + .get_voltage = tps65023_dcdc_get_voltage, + .set_voltage = tps65023_dcdc_set_voltage, + .list_voltage = tps65023_dcdc_list_voltage, +}; + +/* Operations permitted on LDOx */ +static struct regulator_ops tps65023_ldo_ops = { + .is_enabled = tps65023_ldo_is_enabled, + .enable = tps65023_ldo_enable, + .disable = tps65023_ldo_disable, + .get_voltage = tps65023_ldo_get_voltage, + .set_voltage = tps65023_ldo_set_voltage, + .list_voltage = tps65023_ldo_list_voltage, +}; + +static +int tps_65023_probe(struct i2c_client *client, const struct i2c_device_id *id) +{ + static int desc_id; + const struct tps_info *info = (void *)id->driver_data; + struct regulator_init_data *init_data; + struct regulator_dev *rdev; + struct tps_pmic *tps; + int i; + + if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE_DATA)) + return -EIO; + + /** + * init_data points to array of regulator_init structures + * coming from the board-evm file. + */ + init_data = client->dev.platform_data; + + if (!init_data) + return -EIO; + + tps = kzalloc(sizeof(*tps), GFP_KERNEL); + if (!tps) + return -ENOMEM; + + mutex_init(&tps->io_lock); + + /* common for all regulators */ + tps->client = client; + + for (i = 0; i < TPS65023_NUM_REGULATOR; i++, info++, init_data++) { + /* Store regulator specific information */ + tps->info[i] = info; + + tps->desc[i].name = info->name; + tps->desc[i].id = desc_id++; + tps->desc[i].n_voltages = num_voltages[i]; + tps->desc[i].ops = (i > TPS65023_DCDC_3 ? + &tps65023_ldo_ops : &tps65023_dcdc_ops); + tps->desc[i].type = REGULATOR_VOLTAGE; + tps->desc[i].owner = THIS_MODULE; + + /* Register the regulators */ + rdev = regulator_register(&tps->desc[i], &client->dev, + init_data, tps); + if (IS_ERR(rdev)) { + dev_err(&client->dev, "failed to register %s\n", + id->name); + + /* Unregister */ + while (i) + regulator_unregister(tps->rdev[--i]); + + tps->client = NULL; + + /* clear the client data in i2c */ + i2c_set_clientdata(client, NULL); + kfree(tps); + return PTR_ERR(rdev); + } + + /* Save regulator for cleanup */ + tps->rdev[i] = rdev; + } + + i2c_set_clientdata(client, tps); + + return 0; +} + +/** + * tps_65023_remove - TPS65023 driver i2c remove handler + * @client: i2c driver client device structure + * + * Unregister TPS driver as an i2c client device driver + */ +static int __devexit tps_65023_remove(struct i2c_client *client) +{ + struct tps_pmic *tps = i2c_get_clientdata(client); + int i; + + for (i = 0; i < TPS65023_NUM_REGULATOR; i++) + regulator_unregister(tps->rdev[i]); + + tps->client = NULL; + + /* clear the client data in i2c */ + i2c_set_clientdata(client, NULL); + kfree(tps); + + return 0; +} + +static const struct tps_info tps65023_regs[] = { + { + .name = "VDCDC1", + .min_uV = 800000, + .max_uV = 1600000, + .table_len = ARRAY_SIZE(VDCDC1_VSEL_table), + .table = VDCDC1_VSEL_table, + }, + { + .name = "VDCDC2", + .min_uV = 3300000, + .max_uV = 3300000, + .fixed = 1, + }, + { + .name = "VDCDC3", + .min_uV = 1800000, + .max_uV = 1800000, + .fixed = 1, + }, + { + .name = "LDO1", + .min_uV = 1000000, + .max_uV = 3150000, + .table_len = ARRAY_SIZE(LDO1_VSEL_table), + .table = LDO1_VSEL_table, + }, + { + .name = "LDO2", + .min_uV = 1050000, + .max_uV = 3300000, + .table_len = ARRAY_SIZE(LDO2_VSEL_table), + .table = LDO2_VSEL_table, + }, +}; + +static const struct i2c_device_id tps_65023_id = { + .name = "tps65023", + .driver_data = (unsigned long) &tps65023_regs[0], +}; + +MODULE_DEVICE_TABLE(i2c, tps_65023_id); + +static struct i2c_driver tps_65023_i2c_driver = { + .driver = { + .name = "tps65023", + .owner = THIS_MODULE, + }, + .probe = tps_65023_probe, + .remove = __devexit_p(tps_65023_remove), + .id_table = &tps_65023_id, +}; + +/** + * tps_65023_init + * + * Module init function + */ +static int __init tps_65023_init(void) +{ + return i2c_add_driver(&tps_65023_i2c_driver); +} +subsys_initcall(tps_65023_init); + +/** + * tps_65023_cleanup + * + * Module exit function + */ +static void __exit tps_65023_cleanup(void) +{ + i2c_del_driver(&tps_65023_i2c_driver); +} +module_exit(tps_65023_cleanup); + +MODULE_AUTHOR("Texas Instruments"); +MODULE_DESCRIPTION("TPS65023 voltage regulator driver"); +MODULE_LICENSE("GPLv2"); -- cgit v1.2.3 From 3fa5b8e08296b250088b1a6b8e3db500ab1b847d Mon Sep 17 00:00:00 2001 From: Anuj Aggarwal Date: Fri, 21 Aug 2009 00:39:39 +0530 Subject: Regulator: Add TPS6507x regulator driver Adding support for TI TPS6507x regulator driver Signed-off-by: Anuj Aggarwal Acked-by: Mark Brown Signed-off-by: Liam Girdwood --- drivers/regulator/tps6507x-regulator.c | 713 +++++++++++++++++++++++++++++++++ 1 file changed, 713 insertions(+) create mode 100644 drivers/regulator/tps6507x-regulator.c (limited to 'drivers') diff --git a/drivers/regulator/tps6507x-regulator.c b/drivers/regulator/tps6507x-regulator.c new file mode 100644 index 00000000000..1aa36369512 --- /dev/null +++ b/drivers/regulator/tps6507x-regulator.c @@ -0,0 +1,713 @@ +/* + * tps6507x-regulator.c + * + * Regulator driver for TPS65073 PMIC + * + * Copyright (C) 2009 Texas Instrument Incorporated - http://www.ti.com/ + * + * 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 version 2. + * + * This program is distributed "as is" WITHOUT ANY WARRANTY of any kind, + * whether express or implied; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* Register definitions */ +#define TPS6507X_REG_PPATH1 0X01 +#define TPS6507X_REG_INT 0X02 +#define TPS6507X_REG_CHGCONFIG0 0X03 +#define TPS6507X_REG_CHGCONFIG1 0X04 +#define TPS6507X_REG_CHGCONFIG2 0X05 +#define TPS6507X_REG_CHGCONFIG3 0X06 +#define TPS6507X_REG_REG_ADCONFIG 0X07 +#define TPS6507X_REG_TSCMODE 0X08 +#define TPS6507X_REG_ADRESULT_1 0X09 +#define TPS6507X_REG_ADRESULT_2 0X0A +#define TPS6507X_REG_PGOOD 0X0B +#define TPS6507X_REG_PGOODMASK 0X0C +#define TPS6507X_REG_CON_CTRL1 0X0D +#define TPS6507X_REG_CON_CTRL2 0X0E +#define TPS6507X_REG_CON_CTRL3 0X0F +#define TPS6507X_REG_DEFDCDC1 0X10 +#define TPS6507X_REG_DEFDCDC2_LOW 0X11 +#define TPS6507X_REG_DEFDCDC2_HIGH 0X12 +#define TPS6507X_REG_DEFDCDC3_LOW 0X13 +#define TPS6507X_REG_DEFDCDC3_HIGH 0X14 +#define TPS6507X_REG_DEFSLEW 0X15 +#define TPS6507X_REG_LDO_CTRL1 0X16 +#define TPS6507X_REG_DEFLDO2 0X17 +#define TPS6507X_REG_WLED_CTRL1 0X18 +#define TPS6507X_REG_WLED_CTRL2 0X19 + +/* CON_CTRL1 bitfields */ +#define TPS6507X_CON_CTRL1_DCDC1_ENABLE BIT(4) +#define TPS6507X_CON_CTRL1_DCDC2_ENABLE BIT(3) +#define TPS6507X_CON_CTRL1_DCDC3_ENABLE BIT(2) +#define TPS6507X_CON_CTRL1_LDO1_ENABLE BIT(1) +#define TPS6507X_CON_CTRL1_LDO2_ENABLE BIT(0) + +/* DEFDCDC1 bitfields */ +#define TPS6507X_DEFDCDC1_DCDC1_EXT_ADJ_EN BIT(7) +#define TPS6507X_DEFDCDC1_DCDC1_MASK 0X3F + +/* DEFDCDC2_LOW bitfields */ +#define TPS6507X_DEFDCDC2_LOW_DCDC2_MASK 0X3F + +/* DEFDCDC2_HIGH bitfields */ +#define TPS6507X_DEFDCDC2_HIGH_DCDC2_MASK 0X3F + +/* DEFDCDC3_LOW bitfields */ +#define TPS6507X_DEFDCDC3_LOW_DCDC3_MASK 0X3F + +/* DEFDCDC3_HIGH bitfields */ +#define TPS6507X_DEFDCDC3_HIGH_DCDC3_MASK 0X3F + +/* TPS6507X_REG_LDO_CTRL1 bitfields */ +#define TPS6507X_REG_LDO_CTRL1_LDO1_MASK 0X0F + +/* TPS6507X_REG_DEFLDO2 bitfields */ +#define TPS6507X_REG_DEFLDO2_LDO2_MASK 0X3F + +/* VDCDC MASK */ +#define TPS6507X_DEFDCDCX_DCDC_MASK 0X3F + +/* DCDC's */ +#define TPS6507X_DCDC_1 0 +#define TPS6507X_DCDC_2 1 +#define TPS6507X_DCDC_3 2 +/* LDOs */ +#define TPS6507X_LDO_1 3 +#define TPS6507X_LDO_2 4 + +#define TPS6507X_MAX_REG_ID TPS6507X_LDO_2 + +/* Number of step-down converters available */ +#define TPS6507X_NUM_DCDC 3 +/* Number of LDO voltage regulators available */ +#define TPS6507X_NUM_LDO 2 +/* Number of total regulators available */ +#define TPS6507X_NUM_REGULATOR (TPS6507X_NUM_DCDC + TPS6507X_NUM_LDO) + +/* Supported voltage values for regulators (in milliVolts) */ +static const u16 VDCDCx_VSEL_table[] = { + 725, 750, 775, 800, + 825, 850, 875, 900, + 925, 950, 975, 1000, + 1025, 1050, 1075, 1100, + 1125, 1150, 1175, 1200, + 1225, 1250, 1275, 1300, + 1325, 1350, 1375, 1400, + 1425, 1450, 1475, 1500, + 1550, 1600, 1650, 1700, + 1750, 1800, 1850, 1900, + 1950, 2000, 2050, 2100, + 2150, 2200, 2250, 2300, + 2350, 2400, 2450, 2500, + 2550, 2600, 2650, 2700, + 2750, 2800, 2850, 2900, + 3000, 3100, 3200, 3300, +}; + +static const u16 LDO1_VSEL_table[] = { + 1000, 1100, 1200, 1250, + 1300, 1350, 1400, 1500, + 1600, 1800, 2500, 2750, + 2800, 3000, 3100, 3300, +}; + +static const u16 LDO2_VSEL_table[] = { + 725, 750, 775, 800, + 825, 850, 875, 900, + 925, 950, 975, 1000, + 1025, 1050, 1075, 1100, + 1125, 1150, 1175, 1200, + 1225, 1250, 1275, 1300, + 1325, 1350, 1375, 1400, + 1425, 1450, 1475, 1500, + 1550, 1600, 1650, 1700, + 1750, 1800, 1850, 1900, + 1950, 2000, 2050, 2100, + 2150, 2200, 2250, 2300, + 2350, 2400, 2450, 2500, + 2550, 2600, 2650, 2700, + 2750, 2800, 2850, 2900, + 3000, 3100, 3200, 3300, +}; + +static unsigned int num_voltages[] = {ARRAY_SIZE(VDCDCx_VSEL_table), + ARRAY_SIZE(VDCDCx_VSEL_table), + ARRAY_SIZE(VDCDCx_VSEL_table), + ARRAY_SIZE(LDO1_VSEL_table), + ARRAY_SIZE(LDO2_VSEL_table)}; + +struct tps_info { + const char *name; + unsigned min_uV; + unsigned max_uV; + u8 table_len; + const u16 *table; +}; + +struct tps_pmic { + struct regulator_desc desc[TPS6507X_NUM_REGULATOR]; + struct i2c_client *client; + struct regulator_dev *rdev[TPS6507X_NUM_REGULATOR]; + const struct tps_info *info[TPS6507X_NUM_REGULATOR]; + struct mutex io_lock; +}; + +static inline int tps_6507x_read(struct tps_pmic *tps, u8 reg) +{ + return i2c_smbus_read_byte_data(tps->client, reg); +} + +static inline int tps_6507x_write(struct tps_pmic *tps, u8 reg, u8 val) +{ + return i2c_smbus_write_byte_data(tps->client, reg, val); +} + +static int tps_6507x_set_bits(struct tps_pmic *tps, u8 reg, u8 mask) +{ + int err, data; + + mutex_lock(&tps->io_lock); + + data = tps_6507x_read(tps, reg); + if (data < 0) { + dev_err(&tps->client->dev, "Read from reg 0x%x failed\n", reg); + err = data; + goto out; + } + + data |= mask; + err = tps_6507x_write(tps, reg, data); + if (err) + dev_err(&tps->client->dev, "Write for reg 0x%x failed\n", reg); + +out: + mutex_unlock(&tps->io_lock); + return err; +} + +static int tps_6507x_clear_bits(struct tps_pmic *tps, u8 reg, u8 mask) +{ + int err, data; + + mutex_lock(&tps->io_lock); + + data = tps_6507x_read(tps, reg); + if (data < 0) { + dev_err(&tps->client->dev, "Read from reg 0x%x failed\n", reg); + err = data; + goto out; + } + + data &= ~mask; + err = tps_6507x_write(tps, reg, data); + if (err) + dev_err(&tps->client->dev, "Write for reg 0x%x failed\n", reg); + +out: + mutex_unlock(&tps->io_lock); + return err; +} + +static int tps_6507x_reg_read(struct tps_pmic *tps, u8 reg) +{ + int data; + + mutex_lock(&tps->io_lock); + + data = tps_6507x_read(tps, reg); + if (data < 0) + dev_err(&tps->client->dev, "Read from reg 0x%x failed\n", reg); + + mutex_unlock(&tps->io_lock); + return data; +} + +static int tps_6507x_reg_write(struct tps_pmic *tps, u8 reg, u8 val) +{ + int err; + + mutex_lock(&tps->io_lock); + + err = tps_6507x_write(tps, reg, val); + if (err < 0) + dev_err(&tps->client->dev, "Write for reg 0x%x failed\n", reg); + + mutex_unlock(&tps->io_lock); + return err; +} + +static int tps6507x_dcdc_is_enabled(struct regulator_dev *dev) +{ + struct tps_pmic *tps = rdev_get_drvdata(dev); + int data, dcdc = rdev_get_id(dev); + u8 shift; + + if (dcdc < TPS6507X_DCDC_1 || dcdc > TPS6507X_DCDC_3) + return -EINVAL; + + shift = TPS6507X_MAX_REG_ID - dcdc; + data = tps_6507x_reg_read(tps, TPS6507X_REG_CON_CTRL1); + + if (data < 0) + return data; + else + return (data & 1< TPS6507X_LDO_2) + return -EINVAL; + + shift = TPS6507X_MAX_REG_ID - ldo; + data = tps_6507x_reg_read(tps, TPS6507X_REG_CON_CTRL1); + + if (data < 0) + return data; + else + return (data & 1< TPS6507X_DCDC_3) + return -EINVAL; + + shift = TPS6507X_MAX_REG_ID - dcdc; + return tps_6507x_set_bits(tps, TPS6507X_REG_CON_CTRL1, 1 << shift); +} + +static int tps6507x_dcdc_disable(struct regulator_dev *dev) +{ + struct tps_pmic *tps = rdev_get_drvdata(dev); + int dcdc = rdev_get_id(dev); + u8 shift; + + if (dcdc < TPS6507X_DCDC_1 || dcdc > TPS6507X_DCDC_3) + return -EINVAL; + + shift = TPS6507X_MAX_REG_ID - dcdc; + return tps_6507x_clear_bits(tps, TPS6507X_REG_CON_CTRL1, 1 << shift); +} + +static int tps6507x_ldo_enable(struct regulator_dev *dev) +{ + struct tps_pmic *tps = rdev_get_drvdata(dev); + int ldo = rdev_get_id(dev); + u8 shift; + + if (ldo < TPS6507X_LDO_1 || ldo > TPS6507X_LDO_2) + return -EINVAL; + + shift = TPS6507X_MAX_REG_ID - ldo; + return tps_6507x_set_bits(tps, TPS6507X_REG_CON_CTRL1, 1 << shift); +} + +static int tps6507x_ldo_disable(struct regulator_dev *dev) +{ + struct tps_pmic *tps = rdev_get_drvdata(dev); + int ldo = rdev_get_id(dev); + u8 shift; + + if (ldo < TPS6507X_LDO_1 || ldo > TPS6507X_LDO_2) + return -EINVAL; + + shift = TPS6507X_MAX_REG_ID - ldo; + return tps_6507x_clear_bits(tps, TPS6507X_REG_CON_CTRL1, 1 << shift); +} + +static int tps6507x_dcdc_get_voltage(struct regulator_dev *dev) +{ + struct tps_pmic *tps = rdev_get_drvdata(dev); + int data, dcdc = rdev_get_id(dev); + u8 reg; + + switch (dcdc) { + case TPS6507X_DCDC_1: + reg = TPS6507X_REG_DEFDCDC1; + break; + case TPS6507X_DCDC_2: + reg = TPS6507X_REG_DEFDCDC2_LOW; + break; + case TPS6507X_DCDC_3: + reg = TPS6507X_REG_DEFDCDC3_LOW; + break; + default: + return -EINVAL; + } + + data = tps_6507x_reg_read(tps, reg); + if (data < 0) + return data; + + data &= TPS6507X_DEFDCDCX_DCDC_MASK; + return tps->info[dcdc]->table[data] * 1000; +} + +static int tps6507x_dcdc_set_voltage(struct regulator_dev *dev, + int min_uV, int max_uV) +{ + struct tps_pmic *tps = rdev_get_drvdata(dev); + int data, vsel, dcdc = rdev_get_id(dev); + u8 reg; + + switch (dcdc) { + case TPS6507X_DCDC_1: + reg = TPS6507X_REG_DEFDCDC1; + break; + case TPS6507X_DCDC_2: + reg = TPS6507X_REG_DEFDCDC2_LOW; + break; + case TPS6507X_DCDC_3: + reg = TPS6507X_REG_DEFDCDC3_LOW; + break; + default: + return -EINVAL; + } + + if (min_uV < tps->info[dcdc]->min_uV + || min_uV > tps->info[dcdc]->max_uV) + return -EINVAL; + if (max_uV < tps->info[dcdc]->min_uV + || max_uV > tps->info[dcdc]->max_uV) + return -EINVAL; + + for (vsel = 0; vsel < tps->info[dcdc]->table_len; vsel++) { + int mV = tps->info[dcdc]->table[vsel]; + int uV = mV * 1000; + + /* Break at the first in-range value */ + if (min_uV <= uV && uV <= max_uV) + break; + } + + /* write to the register in case we found a match */ + if (vsel == tps->info[dcdc]->table_len) + return -EINVAL; + + data = tps_6507x_reg_read(tps, reg); + if (data < 0) + return data; + + data &= ~TPS6507X_DEFDCDCX_DCDC_MASK; + data |= vsel; + + return tps_6507x_reg_write(tps, reg, data); +} + +static int tps6507x_ldo_get_voltage(struct regulator_dev *dev) +{ + struct tps_pmic *tps = rdev_get_drvdata(dev); + int data, ldo = rdev_get_id(dev); + u8 reg, mask; + + if (ldo < TPS6507X_LDO_1 || ldo > TPS6507X_LDO_2) + return -EINVAL; + else { + reg = (ldo == TPS6507X_LDO_1 ? + TPS6507X_REG_LDO_CTRL1 : TPS6507X_REG_DEFLDO2); + mask = (ldo == TPS6507X_LDO_1 ? + TPS6507X_REG_LDO_CTRL1_LDO1_MASK : + TPS6507X_REG_DEFLDO2_LDO2_MASK); + } + + data = tps_6507x_reg_read(tps, reg); + if (data < 0) + return data; + + data &= mask; + return tps->info[ldo]->table[data] * 1000; +} + +static int tps6507x_ldo_set_voltage(struct regulator_dev *dev, + int min_uV, int max_uV) +{ + struct tps_pmic *tps = rdev_get_drvdata(dev); + int data, vsel, ldo = rdev_get_id(dev); + u8 reg, mask; + + if (ldo < TPS6507X_LDO_1 || ldo > TPS6507X_LDO_2) + return -EINVAL; + else { + reg = (ldo == TPS6507X_LDO_1 ? + TPS6507X_REG_LDO_CTRL1 : TPS6507X_REG_DEFLDO2); + mask = (ldo == TPS6507X_LDO_1 ? + TPS6507X_REG_LDO_CTRL1_LDO1_MASK : + TPS6507X_REG_DEFLDO2_LDO2_MASK); + } + + if (min_uV < tps->info[ldo]->min_uV || min_uV > tps->info[ldo]->max_uV) + return -EINVAL; + if (max_uV < tps->info[ldo]->min_uV || max_uV > tps->info[ldo]->max_uV) + return -EINVAL; + + for (vsel = 0; vsel < tps->info[ldo]->table_len; vsel++) { + int mV = tps->info[ldo]->table[vsel]; + int uV = mV * 1000; + + /* Break at the first in-range value */ + if (min_uV <= uV && uV <= max_uV) + break; + } + + if (vsel == tps->info[ldo]->table_len) + return -EINVAL; + + data = tps_6507x_reg_read(tps, reg); + if (data < 0) + return data; + + data &= ~mask; + data |= vsel; + + return tps_6507x_reg_write(tps, reg, data); +} + +static int tps6507x_dcdc_list_voltage(struct regulator_dev *dev, + unsigned selector) +{ + struct tps_pmic *tps = rdev_get_drvdata(dev); + int dcdc = rdev_get_id(dev); + + if (dcdc < TPS6507X_DCDC_1 || dcdc > TPS6507X_DCDC_3) + return -EINVAL; + + if (selector >= tps->info[dcdc]->table_len) + return -EINVAL; + else + return tps->info[dcdc]->table[selector] * 1000; +} + +static int tps6507x_ldo_list_voltage(struct regulator_dev *dev, + unsigned selector) +{ + struct tps_pmic *tps = rdev_get_drvdata(dev); + int ldo = rdev_get_id(dev); + + if (ldo < TPS6507X_LDO_1 || ldo > TPS6507X_LDO_2) + return -EINVAL; + + if (selector >= tps->info[ldo]->table_len) + return -EINVAL; + else + return tps->info[ldo]->table[selector] * 1000; +} + +/* Operations permitted on VDCDCx */ +static struct regulator_ops tps6507x_dcdc_ops = { + .is_enabled = tps6507x_dcdc_is_enabled, + .enable = tps6507x_dcdc_enable, + .disable = tps6507x_dcdc_disable, + .get_voltage = tps6507x_dcdc_get_voltage, + .set_voltage = tps6507x_dcdc_set_voltage, + .list_voltage = tps6507x_dcdc_list_voltage, +}; + +/* Operations permitted on LDOx */ +static struct regulator_ops tps6507x_ldo_ops = { + .is_enabled = tps6507x_ldo_is_enabled, + .enable = tps6507x_ldo_enable, + .disable = tps6507x_ldo_disable, + .get_voltage = tps6507x_ldo_get_voltage, + .set_voltage = tps6507x_ldo_set_voltage, + .list_voltage = tps6507x_ldo_list_voltage, +}; + +static +int tps_6507x_probe(struct i2c_client *client, const struct i2c_device_id *id) +{ + static int desc_id; + const struct tps_info *info = (void *)id->driver_data; + struct regulator_init_data *init_data; + struct regulator_dev *rdev; + struct tps_pmic *tps; + int i; + + if (!i2c_check_functionality(client->adapter, + I2C_FUNC_SMBUS_BYTE_DATA)) + return -EIO; + + /** + * init_data points to array of regulator_init structures + * coming from the board-evm file. + */ + init_data = client->dev.platform_data; + + if (!init_data) + return -EIO; + + tps = kzalloc(sizeof(*tps), GFP_KERNEL); + if (!tps) + return -ENOMEM; + + mutex_init(&tps->io_lock); + + /* common for all regulators */ + tps->client = client; + + for (i = 0; i < TPS6507X_NUM_REGULATOR; i++, info++, init_data++) { + /* Register the regulators */ + tps->info[i] = info; + tps->desc[i].name = info->name; + tps->desc[i].id = desc_id++; + tps->desc[i].n_voltages = num_voltages[i]; + tps->desc[i].ops = (i > TPS6507X_DCDC_3 ? + &tps6507x_ldo_ops : &tps6507x_dcdc_ops); + tps->desc[i].type = REGULATOR_VOLTAGE; + tps->desc[i].owner = THIS_MODULE; + + rdev = regulator_register(&tps->desc[i], + &client->dev, init_data, tps); + if (IS_ERR(rdev)) { + dev_err(&client->dev, "failed to register %s\n", + id->name); + + /* Unregister */ + while (i) + regulator_unregister(tps->rdev[--i]); + + tps->client = NULL; + + /* clear the client data in i2c */ + i2c_set_clientdata(client, NULL); + + kfree(tps); + return PTR_ERR(rdev); + } + + /* Save regulator for cleanup */ + tps->rdev[i] = rdev; + } + + i2c_set_clientdata(client, tps); + + return 0; +} + +/** + * tps_6507x_remove - TPS6507x driver i2c remove handler + * @client: i2c driver client device structure + * + * Unregister TPS driver as an i2c client device driver + */ +static int __devexit tps_6507x_remove(struct i2c_client *client) +{ + struct tps_pmic *tps = i2c_get_clientdata(client); + int i; + + for (i = 0; i < TPS6507X_NUM_REGULATOR; i++) + regulator_unregister(tps->rdev[i]); + + tps->client = NULL; + + /* clear the client data in i2c */ + i2c_set_clientdata(client, NULL); + kfree(tps); + + return 0; +} + +static const struct tps_info tps6507x_regs[] = { + { + .name = "VDCDC1", + .min_uV = 725000, + .max_uV = 3300000, + .table_len = ARRAY_SIZE(VDCDCx_VSEL_table), + .table = VDCDCx_VSEL_table, + }, + { + .name = "VDCDC2", + .min_uV = 725000, + .max_uV = 3300000, + .table_len = ARRAY_SIZE(VDCDCx_VSEL_table), + .table = VDCDCx_VSEL_table, + }, + { + .name = "VDCDC3", + .min_uV = 725000, + .max_uV = 3300000, + .table_len = ARRAY_SIZE(VDCDCx_VSEL_table), + .table = VDCDCx_VSEL_table, + }, + { + .name = "LDO1", + .min_uV = 1000000, + .max_uV = 3300000, + .table_len = ARRAY_SIZE(LDO1_VSEL_table), + .table = LDO1_VSEL_table, + }, + { + .name = "LDO2", + .min_uV = 725000, + .max_uV = 3300000, + .table_len = ARRAY_SIZE(LDO2_VSEL_table), + .table = LDO2_VSEL_table, + }, +}; + +static const struct i2c_device_id tps_6507x_id = { + .name = "tps6507x", + .driver_data = (unsigned long) &tps6507x_regs[0], +}; +MODULE_DEVICE_TABLE(i2c, tps_6507x_id); + +static struct i2c_driver tps_6507x_i2c_driver = { + .driver = { + .name = "tps6507x", + .owner = THIS_MODULE, + }, + .probe = tps_6507x_probe, + .remove = __devexit_p(tps_6507x_remove), + .id_table = &tps_6507x_id, +}; + +/** + * tps_6507x_init + * + * Module init function + */ +static int __init tps_6507x_init(void) +{ + return i2c_add_driver(&tps_6507x_i2c_driver); +} +subsys_initcall(tps_6507x_init); + +/** + * tps_6507x_cleanup + * + * Module exit function + */ +static void __exit tps_6507x_cleanup(void) +{ + i2c_del_driver(&tps_6507x_i2c_driver); +} +module_exit(tps_6507x_cleanup); + +MODULE_AUTHOR("Texas Instruments"); +MODULE_DESCRIPTION("TPS6507x voltage regulator driver"); +MODULE_LICENSE("GPLv2"); -- cgit v1.2.3 From 2de798506d7300830a102e18d3d299f740475bc8 Mon Sep 17 00:00:00 2001 From: Anuj Aggarwal Date: Fri, 21 Aug 2009 00:39:44 +0530 Subject: Regulator: Adding TPS65023 and TPS6507x in Kconfig and Makefile Adding TPS65023 and TPS6507x regulator driver support in drivers/regulator/Makefile and drivers/regulator/Kconfig Signed-off-by: Anuj Aggarwal Acked-by: Mark Brown Signed-off-by: Liam Girdwood --- drivers/regulator/Kconfig | 16 ++++++++++++++++ drivers/regulator/Makefile | 3 +++ 2 files changed, 19 insertions(+) (limited to 'drivers') diff --git a/drivers/regulator/Kconfig b/drivers/regulator/Kconfig index 2dc42bbf6fe..29910e3a3e4 100644 --- a/drivers/regulator/Kconfig +++ b/drivers/regulator/Kconfig @@ -147,5 +147,21 @@ config REGULATOR_AB3100 AB3100 analog baseband dealing with power regulators for the system. +config REGULATOR_TPS65023 + tristate "TI TPS65023 Power regulators" + depends on I2C + help + This driver supports TPS65023 voltage regulator chips. TPS65023 provides + three step-down converters and two general-purpose LDO voltage regulators. + It supports TI's software based Class-2 SmartReflex implementation. + +config REGULATOR_TPS6507X + tristate "TI TPS6507X Power regulators" + depends on I2C + help + This driver supports TPS6507X voltage regulator chips. TPS6507X provides + three step-down converters and two general-purpose LDO voltage regulators. + It supports TI's software based Class-2 SmartReflex implementation. + endif diff --git a/drivers/regulator/Makefile b/drivers/regulator/Makefile index 768b3316d6e..4257a868377 100644 --- a/drivers/regulator/Makefile +++ b/drivers/regulator/Makefile @@ -23,4 +23,7 @@ obj-$(CONFIG_REGULATOR_PCAP) += pcap-regulator.o obj-$(CONFIG_REGULATOR_MC13783) += mc13783.o obj-$(CONFIG_REGULATOR_AB3100) += ab3100.o +obj-$(CONFIG_REGULATOR_TPS65023) += tps65023-regulator.o +obj-$(CONFIG_REGULATOR_TPS6507X) += tps6507x-regulator.o + ccflags-$(CONFIG_REGULATOR_DEBUG) += -DDEBUG -- cgit v1.2.3 From 9e108d33edcb88bac3db39ba1683fc2c0591d7d4 Mon Sep 17 00:00:00 2001 From: Liam Girdwood Date: Mon, 24 Aug 2009 10:31:34 +0100 Subject: regulator: tps650xx - build fixes for x86_64 Fixes the following errors on both tps650xx regulator drivers :- drivers/regulator/tps65023-regulator: struct i2c_device_id is 32 bytes. The last of 1 is: 0x74 0x70 0x73 0x36 0x35 0x30 0x32 0x33 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 FATAL: drivers/regulator/tps65023-regulator: struct i2c_device_id is not terminated with a NULL entry! This patch also fixes the GPL v2 licence string for both drivers. Signed-off-by: Liam Girdwood --- drivers/regulator/tps65023-regulator.c | 11 ++++++----- drivers/regulator/tps6507x-regulator.c | 11 ++++++----- 2 files changed, 12 insertions(+), 10 deletions(-) (limited to 'drivers') diff --git a/drivers/regulator/tps65023-regulator.c b/drivers/regulator/tps65023-regulator.c index 1e54f46af67..07fda0a75ad 100644 --- a/drivers/regulator/tps65023-regulator.c +++ b/drivers/regulator/tps65023-regulator.c @@ -587,9 +587,10 @@ static const struct tps_info tps65023_regs[] = { }, }; -static const struct i2c_device_id tps_65023_id = { - .name = "tps65023", - .driver_data = (unsigned long) &tps65023_regs[0], +static const struct i2c_device_id tps_65023_id[] = { + {.name = "tps65023", + .driver_data = (unsigned long) tps65023_regs,}, + { }, }; MODULE_DEVICE_TABLE(i2c, tps_65023_id); @@ -601,7 +602,7 @@ static struct i2c_driver tps_65023_i2c_driver = { }, .probe = tps_65023_probe, .remove = __devexit_p(tps_65023_remove), - .id_table = &tps_65023_id, + .id_table = tps_65023_id, }; /** @@ -628,4 +629,4 @@ module_exit(tps_65023_cleanup); MODULE_AUTHOR("Texas Instruments"); MODULE_DESCRIPTION("TPS65023 voltage regulator driver"); -MODULE_LICENSE("GPLv2"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/regulator/tps6507x-regulator.c b/drivers/regulator/tps6507x-regulator.c index 1aa36369512..f8a6dfbef75 100644 --- a/drivers/regulator/tps6507x-regulator.c +++ b/drivers/regulator/tps6507x-regulator.c @@ -670,9 +670,10 @@ static const struct tps_info tps6507x_regs[] = { }, }; -static const struct i2c_device_id tps_6507x_id = { - .name = "tps6507x", - .driver_data = (unsigned long) &tps6507x_regs[0], +static const struct i2c_device_id tps_6507x_id[] = { + {.name = "tps6507x", + .driver_data = (unsigned long) tps6507x_regs,}, + { }, }; MODULE_DEVICE_TABLE(i2c, tps_6507x_id); @@ -683,7 +684,7 @@ static struct i2c_driver tps_6507x_i2c_driver = { }, .probe = tps_6507x_probe, .remove = __devexit_p(tps_6507x_remove), - .id_table = &tps_6507x_id, + .id_table = tps_6507x_id, }; /** @@ -710,4 +711,4 @@ module_exit(tps_6507x_cleanup); MODULE_AUTHOR("Texas Instruments"); MODULE_DESCRIPTION("TPS6507x voltage regulator driver"); -MODULE_LICENSE("GPLv2"); +MODULE_LICENSE("GPL v2"); -- cgit v1.2.3 From a7433cff9ed8e7982de8e0f210f0325d0f3d1949 Mon Sep 17 00:00:00 2001 From: Linus Walleij Date: Wed, 26 Aug 2009 12:54:04 +0200 Subject: REGULATOR Handle positive returncode from enable This makes _regulator_enable() properly handle the case where a regulator is already on when you try to enable it. Currently it will erroneously handle positive return values as an error. Signed-off-by: Linus Walleij Acked-by: Mark Brown Signed-off-by: Liam Girdwood --- drivers/regulator/core.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/regulator/core.c b/drivers/regulator/core.c index dbf27bf028c..744ea1d0b59 100644 --- a/drivers/regulator/core.c +++ b/drivers/regulator/core.c @@ -1236,11 +1236,12 @@ static int _regulator_enable(struct regulator_dev *rdev) } else { return -EINVAL; } - } else { + } else if (ret < 0) { printk(KERN_ERR "%s: is_enabled() failed for %s: %d\n", __func__, rdev->desc->name, ret); return ret; } + /* Fallthrough on positive return values - already enabled */ } rdev->use_count++; -- cgit v1.2.3 From 6f2653e63a4aedf877efbbcdbd4cea7db088bf29 Mon Sep 17 00:00:00 2001 From: Michael Prokop Date: Sat, 5 Sep 2009 02:59:14 +0200 Subject: drivers/regulator/Kconfig: fix typo (s/Usersapce/Userspace/) in REGULATOR_USERSPACE_CONSUMER description Signed-off-by: Michael Prokop Signed-off-by: Liam Girdwood --- 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 29910e3a3e4..2b52a4ffcd3 100644 --- a/drivers/regulator/Kconfig +++ b/drivers/regulator/Kconfig @@ -52,7 +52,7 @@ config REGULATOR_USERSPACE_CONSUMER default n help There are some classes of devices that are controlled entirely - from user space. Usersapce consumer driver provides ability to + from user space. Userspace consumer driver provides ability to control power supplies for such devices. If unsure, say no. -- cgit v1.2.3 From 656d0498ea14c51cd8ec00081b5e0662acc72614 Mon Sep 17 00:00:00 2001 From: Roel Kluin Date: Fri, 18 Sep 2009 12:56:20 -0700 Subject: regulator: fix calculation of voltage range in da9034_set_ldo12_voltage() For val to be greater than 7 or less than 20 is logically always true. Signed-off-by: Roel Kluin Cc: Liam Girdwood Cc: Mark Brown Signed-off-by: Andrew Morton Acked-by: Mark Brown Signed-off-by: Liam Girdwood --- drivers/regulator/da903x.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/regulator/da903x.c b/drivers/regulator/da903x.c index 7d9c2506d21..c9de7309847 100644 --- a/drivers/regulator/da903x.c +++ b/drivers/regulator/da903x.c @@ -301,7 +301,7 @@ static int da9034_set_ldo12_voltage(struct regulator_dev *rdev, } val = (min_uV - info->min_uV + info->step_uV - 1) / info->step_uV; - val = (val > 7 || val < 20) ? 8 : val - 12; + val = (val > 7 && val < 20) ? 8 : val - 12; val <<= info->vol_shift; mask = ((1 << info->vol_nbits) - 1) << info->vol_shift; -- cgit v1.2.3 From a954c487b95e7061d9546f6897edbc20a73454d3 Mon Sep 17 00:00:00 2001 From: Wolfram Sang Date: Fri, 18 Sep 2009 22:44:44 +0200 Subject: regulator: drop 'default n' Specifying 'default n' is superfluous. Signed-off-by: Wolfram Sang Acked-by: Mark Brown Signed-off-by: Liam Girdwood --- drivers/regulator/Kconfig | 6 ------ 1 file changed, 6 deletions(-) (limited to 'drivers') diff --git a/drivers/regulator/Kconfig b/drivers/regulator/Kconfig index 2b52a4ffcd3..bcbb161bde0 100644 --- a/drivers/regulator/Kconfig +++ b/drivers/regulator/Kconfig @@ -1,6 +1,5 @@ menuconfig REGULATOR bool "Voltage and Current Regulator Support" - default n help Generic Voltage and Current Regulator support. @@ -30,7 +29,6 @@ config REGULATOR_DEBUG config REGULATOR_FIXED_VOLTAGE tristate "Fixed voltage regulator support" - default n help This driver provides support for fixed voltage regulators, useful for systems which use a combination of software @@ -38,7 +36,6 @@ config REGULATOR_FIXED_VOLTAGE config REGULATOR_VIRTUAL_CONSUMER tristate "Virtual regulator consumer support" - default n help This driver provides a virtual consumer for the voltage and current regulator API which provides sysfs controls for @@ -49,7 +46,6 @@ config REGULATOR_VIRTUAL_CONSUMER config REGULATOR_USERSPACE_CONSUMER tristate "Userspace regulator consumer support" - default n help There are some classes of devices that are controlled entirely from user space. Userspace consumer driver provides ability to @@ -59,7 +55,6 @@ config REGULATOR_USERSPACE_CONSUMER config REGULATOR_BQ24022 tristate "TI bq24022 Dual Input 1-Cell Li-Ion Charger IC" - default n help This driver controls a TI bq24022 Charger attached via GPIOs. The provided current regulator can enable/disable @@ -69,7 +64,6 @@ config REGULATOR_BQ24022 config REGULATOR_MAX1586 tristate "Maxim 1586/1587 voltage regulator" depends on I2C - default n help This driver controls a Maxim 1586 or 1587 voltage output regulator via I2C bus. The provided regulator is suitable -- cgit v1.2.3 From 12a1d933a99e1a2901575390dceea3819f2a575a Mon Sep 17 00:00:00 2001 From: Wolfram Sang Date: Fri, 18 Sep 2009 22:44:45 +0200 Subject: regulator/lp3971: drop unnecessary initialization Signed-off-by: Wolfram Sang Acked-by: Mark Brown Signed-off-by: Liam Girdwood --- drivers/regulator/lp3971.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/regulator/lp3971.c b/drivers/regulator/lp3971.c index a61018a2769..7803a320543 100644 --- a/drivers/regulator/lp3971.c +++ b/drivers/regulator/lp3971.c @@ -541,7 +541,7 @@ static struct i2c_driver lp3971_i2c_driver = { static int __init lp3971_module_init(void) { - int ret = -ENODEV; + int ret; ret = i2c_add_driver(&lp3971_i2c_driver); if (ret != 0) -- cgit v1.2.3 From 55c1d7c60d9b269551cd7cc31e6be8323e1d94ec Mon Sep 17 00:00:00 2001 From: Haojian Zhuang Date: Mon, 21 Sep 2009 12:14:12 -0400 Subject: regulator: fix voltage range in da9034 ldo12 Signed-off-by: Roel Kluin Signed-off-by: Haojian Zhuang Acked-by: Mark Brown Signed-off-by: Liam Girdwood --- drivers/regulator/da903x.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/regulator/da903x.c b/drivers/regulator/da903x.c index c9de7309847..aa224d936e0 100644 --- a/drivers/regulator/da903x.c +++ b/drivers/regulator/da903x.c @@ -301,7 +301,7 @@ static int da9034_set_ldo12_voltage(struct regulator_dev *rdev, } val = (min_uV - info->min_uV + info->step_uV - 1) / info->step_uV; - val = (val > 7 && val < 20) ? 8 : val - 12; + val = (val >= 20) ? val - 12 : ((val > 7) ? 8 : val); val <<= info->vol_shift; mask = ((1 << info->vol_nbits) - 1) << info->vol_shift; -- cgit v1.2.3