From d4d6373c1109b11c8118340be97ae31b8f94d66a Mon Sep 17 00:00:00 2001 From: Axel Lin Date: Mon, 28 Nov 2011 14:06:31 +0800 Subject: regulator: aat2870: Fix the logic of checking if no id is matched in aat2870_get_regulator In current implementation, the pointer ri is not NULL if no id is matched. Fix it by checking i == ARRAY_SIZE(aat2870_regulators) if no id is matched. Signed-off-by: Axel Lin Signed-off-by: Mark Brown Cc: stable@kernel.org --- drivers/regulator/aat2870-regulator.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/regulator/aat2870-regulator.c b/drivers/regulator/aat2870-regulator.c index 5abeb3ac3e8..298c6c6a279 100644 --- a/drivers/regulator/aat2870-regulator.c +++ b/drivers/regulator/aat2870-regulator.c @@ -160,7 +160,7 @@ static struct aat2870_regulator *aat2870_get_regulator(int id) break; } - if (!ri) + if (i == ARRAY_SIZE(aat2870_regulators)) return NULL; ri->enable_addr = AAT2870_LDO_EN; -- cgit v1.2.3 From 58fb5cf5d1edb7e306574833ee55d732918c89e3 Mon Sep 17 00:00:00 2001 From: Lothar Waßmann Date: Mon, 28 Nov 2011 15:38:37 +0100 Subject: regulator: fix use after free bug MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This is caused by dereferencing 'rdev' after device_unregister() in the regulator_unregister() function. 'rdev' is freed by device_unregister(), so it must not be dereferenced after this call. [Edited commit message for legibility -- broonie] Signed-off-by: Lothar Waßmann Signed-off-by: Mark Brown --- drivers/regulator/core.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/regulator/core.c b/drivers/regulator/core.c index 669d0216022..938398f3e86 100644 --- a/drivers/regulator/core.c +++ b/drivers/regulator/core.c @@ -2799,8 +2799,8 @@ void regulator_unregister(struct regulator_dev *rdev) list_del(&rdev->list); if (rdev->supply) regulator_put(rdev->supply); - device_unregister(&rdev->dev); kfree(rdev->constraints); + device_unregister(&rdev->dev); mutex_unlock(®ulator_list_mutex); } EXPORT_SYMBOL_GPL(regulator_unregister); -- cgit v1.2.3 From ba305e31e88ea5c2f598ff9fbc5424711a429e30 Mon Sep 17 00:00:00 2001 From: Tero Kristo Date: Mon, 28 Nov 2011 16:53:19 +0200 Subject: regulator: twl: fix twl4030 support for smps regulators SMPS regulator voltage control differs from the one of the LDO ones. Current TWL code was using LDO regulator ops for controlling the SMPS regulators, which fails. This was fixed fixed by adding separate regulator type which uses correct logic and calculations for the voltage levels. Signed-off-by: Tero Kristo Signed-off-by: Mark Brown Cc: stable@kernel.org --- drivers/regulator/twl-regulator.c | 46 +++++++++++++++++++++++++++++++++++++-- 1 file changed, 44 insertions(+), 2 deletions(-) diff --git a/drivers/regulator/twl-regulator.c b/drivers/regulator/twl-regulator.c index ee8747f4fa0..11cc308d66e 100644 --- a/drivers/regulator/twl-regulator.c +++ b/drivers/regulator/twl-regulator.c @@ -71,6 +71,7 @@ struct twlreg_info { #define VREG_TYPE 1 #define VREG_REMAP 2 #define VREG_DEDICATED 3 /* LDO control */ +#define VREG_VOLTAGE_SMPS_4030 9 /* TWL6030 register offsets */ #define VREG_TRANS 1 #define VREG_STATE 2 @@ -514,6 +515,32 @@ static struct regulator_ops twl4030ldo_ops = { .get_status = twl4030reg_get_status, }; +static int +twl4030smps_set_voltage(struct regulator_dev *rdev, int min_uV, int max_uV, + unsigned *selector) +{ + struct twlreg_info *info = rdev_get_drvdata(rdev); + int vsel = DIV_ROUND_UP(min_uV - 600000, 12500); + + twlreg_write(info, TWL_MODULE_PM_RECEIVER, VREG_VOLTAGE_SMPS_4030, + vsel); + return 0; +} + +static int twl4030smps_get_voltage(struct regulator_dev *rdev) +{ + struct twlreg_info *info = rdev_get_drvdata(rdev); + int vsel = twlreg_read(info, TWL_MODULE_PM_RECEIVER, + VREG_VOLTAGE_SMPS_4030); + + return vsel * 12500 + 600000; +} + +static struct regulator_ops twl4030smps_ops = { + .set_voltage = twl4030smps_set_voltage, + .get_voltage = twl4030smps_get_voltage, +}; + static int twl6030ldo_list_voltage(struct regulator_dev *rdev, unsigned index) { struct twlreg_info *info = rdev_get_drvdata(rdev); @@ -856,6 +883,21 @@ static struct regulator_ops twlsmps_ops = { }, \ } +#define TWL4030_ADJUSTABLE_SMPS(label, offset, num, turnon_delay, remap_conf) \ + { \ + .base = offset, \ + .id = num, \ + .delay = turnon_delay, \ + .remap = remap_conf, \ + .desc = { \ + .name = #label, \ + .id = TWL4030_REG_##label, \ + .ops = &twl4030smps_ops, \ + .type = REGULATOR_VOLTAGE, \ + .owner = THIS_MODULE, \ + }, \ + } + #define TWL6030_ADJUSTABLE_LDO(label, offset, min_mVolts, max_mVolts) { \ .base = offset, \ .min_mV = min_mVolts, \ @@ -947,8 +989,8 @@ static struct twlreg_info twl_regs[] = { TWL4030_ADJUSTABLE_LDO(VINTANA2, 0x43, 12, 100, 0x08), TWL4030_FIXED_LDO(VINTDIG, 0x47, 1500, 13, 100, 0x08), TWL4030_ADJUSTABLE_LDO(VIO, 0x4b, 14, 1000, 0x08), - TWL4030_ADJUSTABLE_LDO(VDD1, 0x55, 15, 1000, 0x08), - TWL4030_ADJUSTABLE_LDO(VDD2, 0x63, 16, 1000, 0x08), + TWL4030_ADJUSTABLE_SMPS(VDD1, 0x55, 15, 1000, 0x08), + TWL4030_ADJUSTABLE_SMPS(VDD2, 0x63, 16, 1000, 0x08), TWL4030_FIXED_LDO(VUSB1V5, 0x71, 1500, 17, 100, 0x08), TWL4030_FIXED_LDO(VUSB1V8, 0x74, 1800, 18, 100, 0x08), TWL4030_FIXED_LDO(VUSB3V1, 0x77, 3100, 19, 150, 0x08), -- cgit v1.2.3