From c8a28a0dbeef7b8ac459dd84e6580b9e7602e754 Mon Sep 17 00:00:00 2001 From: Axel Lin Date: Mon, 23 May 2016 22:03:23 +0800 Subject: regulator: pv880x0: Clean up unnecessary header inclusion Signed-off-by: Axel Lin Signed-off-by: Mark Brown --- drivers/regulator/pv88060-regulator.c | 3 --- drivers/regulator/pv88080-regulator.c | 3 --- drivers/regulator/pv88090-regulator.c | 3 --- 3 files changed, 9 deletions(-) (limited to 'drivers/regulator') diff --git a/drivers/regulator/pv88060-regulator.c b/drivers/regulator/pv88060-regulator.c index c448b727f5f8..6c4afc73ecac 100644 --- a/drivers/regulator/pv88060-regulator.c +++ b/drivers/regulator/pv88060-regulator.c @@ -14,7 +14,6 @@ */ #include -#include #include #include #include @@ -25,8 +24,6 @@ #include #include #include -#include -#include #include "pv88060-regulator.h" #define PV88060_MAX_REGULATORS 14 diff --git a/drivers/regulator/pv88080-regulator.c b/drivers/regulator/pv88080-regulator.c index d7107566c429..81950bdb1cc4 100644 --- a/drivers/regulator/pv88080-regulator.c +++ b/drivers/regulator/pv88080-regulator.c @@ -14,7 +14,6 @@ */ #include -#include #include #include #include @@ -25,8 +24,6 @@ #include #include #include -#include -#include #include "pv88080-regulator.h" #define PV88080_MAX_REGULATORS 3 diff --git a/drivers/regulator/pv88090-regulator.c b/drivers/regulator/pv88090-regulator.c index 0057c6740d6f..421641175352 100644 --- a/drivers/regulator/pv88090-regulator.c +++ b/drivers/regulator/pv88090-regulator.c @@ -14,7 +14,6 @@ */ #include -#include #include #include #include @@ -25,8 +24,6 @@ #include #include #include -#include -#include #include "pv88090-regulator.h" #define PV88090_MAX_REGULATORS 5 -- cgit v1.2.1 From fb69114b3efc47c2489b2d0a781814c66bcaaf35 Mon Sep 17 00:00:00 2001 From: Henry Chen Date: Mon, 23 May 2016 15:30:16 +0800 Subject: regulator: mt6397: Constify struct regulator_ops Consitify the structure of regulator operations. Signed-off-by: Henry Chen Signed-off-by: Mark Brown --- drivers/regulator/mt6397-regulator.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'drivers/regulator') diff --git a/drivers/regulator/mt6397-regulator.c b/drivers/regulator/mt6397-regulator.c index 17a5b6c2d6a9..1c45abb94409 100644 --- a/drivers/regulator/mt6397-regulator.c +++ b/drivers/regulator/mt6397-regulator.c @@ -160,7 +160,7 @@ static int mt6397_get_status(struct regulator_dev *rdev) return (regval & info->qi) ? REGULATOR_STATUS_ON : REGULATOR_STATUS_OFF; } -static struct regulator_ops mt6397_volt_range_ops = { +static const struct regulator_ops mt6397_volt_range_ops = { .list_voltage = regulator_list_voltage_linear_range, .map_voltage = regulator_map_voltage_linear_range, .set_voltage_sel = regulator_set_voltage_sel_regmap, @@ -172,7 +172,7 @@ static struct regulator_ops mt6397_volt_range_ops = { .get_status = mt6397_get_status, }; -static struct regulator_ops mt6397_volt_table_ops = { +static const struct regulator_ops mt6397_volt_table_ops = { .list_voltage = regulator_list_voltage_table, .map_voltage = regulator_map_voltage_iterate, .set_voltage_sel = regulator_set_voltage_sel_regmap, @@ -184,7 +184,7 @@ static struct regulator_ops mt6397_volt_table_ops = { .get_status = mt6397_get_status, }; -static struct regulator_ops mt6397_volt_fixed_ops = { +static const struct regulator_ops mt6397_volt_fixed_ops = { .list_voltage = regulator_list_voltage_linear, .enable = regulator_enable_regmap, .disable = regulator_disable_regmap, -- cgit v1.2.1 From 056925132722312d9ca7fa686138b87b24b7c04c Mon Sep 17 00:00:00 2001 From: Henry Chen Date: Mon, 23 May 2016 15:13:31 +0800 Subject: regulator: mt6397: Add buck change mode regulator interface for mt6397 BUCKs of mt6397 have auto mode and pwm mode. User can use regulator interfaces to control modes Signed-off-by: Henry Chen Signed-off-by: Mark Brown --- drivers/regulator/mt6397-regulator.c | 89 ++++++++++++++++++++++++++++++++---- 1 file changed, 80 insertions(+), 9 deletions(-) (limited to 'drivers/regulator') diff --git a/drivers/regulator/mt6397-regulator.c b/drivers/regulator/mt6397-regulator.c index 1c45abb94409..c6c6aa85e4e8 100644 --- a/drivers/regulator/mt6397-regulator.c +++ b/drivers/regulator/mt6397-regulator.c @@ -23,6 +23,9 @@ #include #include +#define MT6397_BUCK_MODE_AUTO 0 +#define MT6397_BUCK_MODE_FORCE_PWM 1 + /* * MT6397 regulators' information * @@ -38,10 +41,14 @@ struct mt6397_regulator_info { u32 vselon_reg; u32 vselctrl_reg; u32 vselctrl_mask; + u32 modeset_reg; + u32 modeset_mask; + u32 modeset_shift; }; #define MT6397_BUCK(match, vreg, min, max, step, volt_ranges, enreg, \ - vosel, vosel_mask, voselon, vosel_ctrl) \ + vosel, vosel_mask, voselon, vosel_ctrl, _modeset_reg, \ + _modeset_shift) \ [MT6397_ID_##vreg] = { \ .desc = { \ .name = #vreg, \ @@ -62,6 +69,9 @@ struct mt6397_regulator_info { .vselon_reg = voselon, \ .vselctrl_reg = vosel_ctrl, \ .vselctrl_mask = BIT(1), \ + .modeset_reg = _modeset_reg, \ + .modeset_mask = BIT(_modeset_shift), \ + .modeset_shift = _modeset_shift \ } #define MT6397_LDO(match, vreg, ldo_volt_table, enreg, enbit, vosel, \ @@ -145,6 +155,63 @@ static const u32 ldo_volt_table7[] = { 1300000, 1500000, 1800000, 2000000, 2500000, 2800000, 3000000, 3300000, }; +static int mt6397_regulator_set_mode(struct regulator_dev *rdev, + unsigned int mode) +{ + struct mt6397_regulator_info *info = rdev_get_drvdata(rdev); + int ret, val; + + switch (mode) { + case REGULATOR_MODE_FAST: + val = MT6397_BUCK_MODE_FORCE_PWM; + break; + case REGULATOR_MODE_NORMAL: + val = MT6397_BUCK_MODE_AUTO; + break; + default: + ret = -EINVAL; + goto err_mode; + } + + dev_dbg(&rdev->dev, "mt6397 buck set_mode %#x, %#x, %#x, %#x\n", + info->modeset_reg, info->modeset_mask, + info->modeset_shift, val); + + val <<= info->modeset_shift; + ret = regmap_update_bits(rdev->regmap, info->modeset_reg, + info->modeset_mask, val); +err_mode: + if (ret != 0) { + dev_err(&rdev->dev, + "Failed to set mt6397 buck mode: %d\n", ret); + return ret; + } + + return 0; +} + +static unsigned int mt6397_regulator_get_mode(struct regulator_dev *rdev) +{ + struct mt6397_regulator_info *info = rdev_get_drvdata(rdev); + int ret, regval; + + ret = regmap_read(rdev->regmap, info->modeset_reg, ®val); + if (ret != 0) { + dev_err(&rdev->dev, + "Failed to get mt6397 buck mode: %d\n", ret); + return ret; + } + + switch ((regval & info->modeset_mask) >> info->modeset_shift) { + case MT6397_BUCK_MODE_AUTO: + return REGULATOR_MODE_NORMAL; + case MT6397_BUCK_MODE_FORCE_PWM: + return REGULATOR_MODE_FAST; + default: + return -EINVAL; + } +} + static int mt6397_get_status(struct regulator_dev *rdev) { int ret; @@ -170,6 +237,8 @@ static const struct regulator_ops mt6397_volt_range_ops = { .disable = regulator_disable_regmap, .is_enabled = regulator_is_enabled_regmap, .get_status = mt6397_get_status, + .set_mode = mt6397_regulator_set_mode, + .get_mode = mt6397_regulator_get_mode, }; static const struct regulator_ops mt6397_volt_table_ops = { @@ -196,28 +265,30 @@ static const struct regulator_ops mt6397_volt_fixed_ops = { static struct mt6397_regulator_info mt6397_regulators[] = { MT6397_BUCK("buck_vpca15", VPCA15, 700000, 1493750, 6250, buck_volt_range1, MT6397_VCA15_CON7, MT6397_VCA15_CON9, 0x7f, - MT6397_VCA15_CON10, MT6397_VCA15_CON5), + MT6397_VCA15_CON10, MT6397_VCA15_CON5, MT6397_VCA15_CON2, 11), MT6397_BUCK("buck_vpca7", VPCA7, 700000, 1493750, 6250, buck_volt_range1, MT6397_VPCA7_CON7, MT6397_VPCA7_CON9, 0x7f, - MT6397_VPCA7_CON10, MT6397_VPCA7_CON5), + MT6397_VPCA7_CON10, MT6397_VPCA7_CON5, MT6397_VPCA7_CON2, 8), MT6397_BUCK("buck_vsramca15", VSRAMCA15, 700000, 1493750, 6250, buck_volt_range1, MT6397_VSRMCA15_CON7, MT6397_VSRMCA15_CON9, - 0x7f, MT6397_VSRMCA15_CON10, MT6397_VSRMCA15_CON5), + 0x7f, MT6397_VSRMCA15_CON10, MT6397_VSRMCA15_CON5, + MT6397_VSRMCA15_CON2, 8), MT6397_BUCK("buck_vsramca7", VSRAMCA7, 700000, 1493750, 6250, buck_volt_range1, MT6397_VSRMCA7_CON7, MT6397_VSRMCA7_CON9, - 0x7f, MT6397_VSRMCA7_CON10, MT6397_VSRMCA7_CON5), + 0x7f, MT6397_VSRMCA7_CON10, MT6397_VSRMCA7_CON5, + MT6397_VSRMCA7_CON2, 8), MT6397_BUCK("buck_vcore", VCORE, 700000, 1493750, 6250, buck_volt_range1, MT6397_VCORE_CON7, MT6397_VCORE_CON9, 0x7f, - MT6397_VCORE_CON10, MT6397_VCORE_CON5), + MT6397_VCORE_CON10, MT6397_VCORE_CON5, MT6397_VCORE_CON2, 8), MT6397_BUCK("buck_vgpu", VGPU, 700000, 1493750, 6250, buck_volt_range1, MT6397_VGPU_CON7, MT6397_VGPU_CON9, 0x7f, - MT6397_VGPU_CON10, MT6397_VGPU_CON5), + MT6397_VGPU_CON10, MT6397_VGPU_CON5, MT6397_VGPU_CON2, 8), MT6397_BUCK("buck_vdrm", VDRM, 800000, 1593750, 6250, buck_volt_range2, MT6397_VDRM_CON7, MT6397_VDRM_CON9, 0x7f, - MT6397_VDRM_CON10, MT6397_VDRM_CON5), + MT6397_VDRM_CON10, MT6397_VDRM_CON5, MT6397_VDRM_CON2, 8), MT6397_BUCK("buck_vio18", VIO18, 1500000, 2120000, 20000, buck_volt_range3, MT6397_VIO18_CON7, MT6397_VIO18_CON9, 0x1f, - MT6397_VIO18_CON10, MT6397_VIO18_CON5), + MT6397_VIO18_CON10, MT6397_VIO18_CON5, MT6397_VIO18_CON2, 8), MT6397_REG_FIXED("ldo_vtcxo", VTCXO, MT6397_ANALDO_CON0, 10, 2800000), MT6397_REG_FIXED("ldo_va28", VA28, MT6397_ANALDO_CON1, 14, 2800000), MT6397_LDO("ldo_vcama", VCAMA, ldo_volt_table1, -- cgit v1.2.1 From d0abd6f5f5eac758f4bcf4001f6cc377320ebc84 Mon Sep 17 00:00:00 2001 From: Axel Lin Date: Sun, 29 May 2016 19:20:03 +0800 Subject: regulator: max8973: Fix setting ramp delay Current code can set ramp delay to a wrong setting that the return value from .set_voltage_time_sel is not enough for proper delay. Fix the logic in .set_ramp_delay and also remove unused ret_val variable. Signed-off-by: Axel Lin Signed-off-by: Mark Brown --- drivers/regulator/max8973-regulator.c | 16 ++++++---------- 1 file changed, 6 insertions(+), 10 deletions(-) (limited to 'drivers/regulator') diff --git a/drivers/regulator/max8973-regulator.c b/drivers/regulator/max8973-regulator.c index 08d2f13eca00..3958f50c5975 100644 --- a/drivers/regulator/max8973-regulator.c +++ b/drivers/regulator/max8973-regulator.c @@ -271,22 +271,18 @@ static int max8973_set_ramp_delay(struct regulator_dev *rdev, struct max8973_chip *max = rdev_get_drvdata(rdev); unsigned int control; int ret; - int ret_val; /* Set ramp delay */ - if (ramp_delay < 25000) { + if (ramp_delay <= 12000) control = MAX8973_RAMP_12mV_PER_US; - ret_val = 12000; - } else if (ramp_delay < 50000) { + else if (ramp_delay <= 25000) control = MAX8973_RAMP_25mV_PER_US; - ret_val = 25000; - } else if (ramp_delay < 200000) { + else if (ramp_delay <= 50000) control = MAX8973_RAMP_50mV_PER_US; - ret_val = 50000; - } else { + else if (ramp_delay <= 200000) control = MAX8973_RAMP_200mV_PER_US; - ret_val = 200000; - } + else + return -EINVAL; ret = regmap_update_bits(max->regmap, MAX8973_CONTROL1, MAX8973_RAMP_MASK, control); -- cgit v1.2.1 From c714a588fc39dc8c8f70014f5691217717983fb3 Mon Sep 17 00:00:00 2001 From: Axel Lin Date: Tue, 31 May 2016 17:26:00 +0800 Subject: regulator: tps51632: Fix setting ramp delay According to the datasheet: SLEW Register(Address = 07h) b7 b6 b5 b4 b3 b2 b1 b0 48mV/us 42mV/us 36mV/us 30mV/us 24mV/us 18mV/us 12mV/us 6mV/us Current code does not set correct slew rate in some cases: e.g. Assume ramp_delay is 10000, current code sets slew register to 6mV/us. Fix the logic to set slew register. Signed-off-by: Axel Lin Acked-by: Laxman Dewangan Signed-off-by: Mark Brown --- drivers/regulator/tps51632-regulator.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) (limited to 'drivers/regulator') diff --git a/drivers/regulator/tps51632-regulator.c b/drivers/regulator/tps51632-regulator.c index 572816e30095..c139890c1514 100644 --- a/drivers/regulator/tps51632-regulator.c +++ b/drivers/regulator/tps51632-regulator.c @@ -94,11 +94,14 @@ static int tps51632_dcdc_set_ramp_delay(struct regulator_dev *rdev, int ramp_delay) { struct tps51632_chip *tps = rdev_get_drvdata(rdev); - int bit = ramp_delay/6000; + int bit; int ret; - if (bit) - bit--; + if (ramp_delay == 0) + bit = 0; + else + bit = DIV_ROUND_UP(ramp_delay, 6000) - 1; + ret = regmap_write(tps->regmap, TPS51632_SLEW_REGS, BIT(bit)); if (ret < 0) dev_err(tps->dev, "SLEW reg write failed, err %d\n", ret); -- cgit v1.2.1 From a51f9f4622a34eb19b5658c08b083345d763657b Mon Sep 17 00:00:00 2001 From: Chen-Yu Tsai Date: Wed, 1 Jun 2016 00:23:19 +0800 Subject: regulator: axp20x: support AXP809 variant The X-Powers AXP809 PMIC has a similar set of regulators as the AXP221, though a few LDOs were removed, and a new switch output added. Like the AXP221, AXP809 also has DC1SW and DC5LDO, which are internally chained to DCDC1 and DCDC5, respectively. Add support for this new variant. Also remove the "axp22x_" prefix from DC1SW/DC5LDO supply handling code, as the AXP809 uses it as well. Signed-off-by: Chen-Yu Tsai Signed-off-by: Mark Brown --- drivers/regulator/axp20x-regulator.c | 119 ++++++++++++++++++++++++++--------- 1 file changed, 90 insertions(+), 29 deletions(-) (limited to 'drivers/regulator') diff --git a/drivers/regulator/axp20x-regulator.c b/drivers/regulator/axp20x-regulator.c index 514a5e8fdbab..728be64e817a 100644 --- a/drivers/regulator/axp20x-regulator.c +++ b/drivers/regulator/axp20x-regulator.c @@ -230,6 +230,61 @@ static const struct regulator_desc axp22x_regulators[] = { AXP_DESC_FIXED(AXP22X, RTC_LDO, "rtc_ldo", "ips", 3000), }; +static const struct regulator_linear_range axp809_dcdc4_ranges[] = { + REGULATOR_LINEAR_RANGE(600000, 0x0, 0x2f, 20000), + REGULATOR_LINEAR_RANGE(1800000, 0x30, 0x38, 100000), +}; + +static const struct regulator_linear_range axp809_dldo1_ranges[] = { + REGULATOR_LINEAR_RANGE(700000, 0x0, 0x1a, 100000), + REGULATOR_LINEAR_RANGE(3400000, 0x1b, 0x1f, 200000), +}; + +static const struct regulator_desc axp809_regulators[] = { + AXP_DESC(AXP809, DCDC1, "dcdc1", "vin1", 1600, 3400, 100, + AXP22X_DCDC1_V_OUT, 0x1f, AXP22X_PWR_OUT_CTRL1, BIT(1)), + AXP_DESC(AXP809, DCDC2, "dcdc2", "vin2", 600, 1540, 20, + AXP22X_DCDC2_V_OUT, 0x3f, AXP22X_PWR_OUT_CTRL1, BIT(2)), + AXP_DESC(AXP809, DCDC3, "dcdc3", "vin3", 600, 1860, 20, + AXP22X_DCDC3_V_OUT, 0x3f, AXP22X_PWR_OUT_CTRL1, BIT(3)), + AXP_DESC_RANGES(AXP809, DCDC4, "dcdc4", "vin4", axp809_dcdc4_ranges, + 57, AXP22X_DCDC4_V_OUT, 0x3f, AXP22X_PWR_OUT_CTRL1, + BIT(4)), + AXP_DESC(AXP809, DCDC5, "dcdc5", "vin5", 1000, 2550, 50, + AXP22X_DCDC5_V_OUT, 0x1f, AXP22X_PWR_OUT_CTRL1, BIT(5)), + /* secondary switchable output of DCDC1 */ + AXP_DESC_SW(AXP809, DC1SW, "dc1sw", NULL, AXP22X_PWR_OUT_CTRL2, + BIT(7)), + /* LDO regulator internally chained to DCDC5 */ + AXP_DESC(AXP809, DC5LDO, "dc5ldo", NULL, 700, 1400, 100, + AXP22X_DC5LDO_V_OUT, 0x7, AXP22X_PWR_OUT_CTRL1, BIT(0)), + AXP_DESC(AXP809, ALDO1, "aldo1", "aldoin", 700, 3300, 100, + AXP22X_ALDO1_V_OUT, 0x1f, AXP22X_PWR_OUT_CTRL1, BIT(6)), + AXP_DESC(AXP809, ALDO2, "aldo2", "aldoin", 700, 3300, 100, + AXP22X_ALDO2_V_OUT, 0x1f, AXP22X_PWR_OUT_CTRL1, BIT(7)), + AXP_DESC(AXP809, ALDO3, "aldo3", "aldoin", 700, 3300, 100, + AXP22X_ALDO3_V_OUT, 0x1f, AXP22X_PWR_OUT_CTRL2, BIT(5)), + AXP_DESC_RANGES(AXP809, DLDO1, "dldo1", "dldoin", axp809_dldo1_ranges, + 32, AXP22X_DLDO1_V_OUT, 0x1f, AXP22X_PWR_OUT_CTRL2, + BIT(3)), + AXP_DESC(AXP809, DLDO2, "dldo2", "dldoin", 700, 3300, 100, + AXP22X_DLDO2_V_OUT, 0x1f, AXP22X_PWR_OUT_CTRL2, BIT(4)), + AXP_DESC(AXP809, ELDO1, "eldo1", "eldoin", 700, 3300, 100, + AXP22X_ELDO1_V_OUT, 0x1f, AXP22X_PWR_OUT_CTRL2, BIT(0)), + AXP_DESC(AXP809, ELDO2, "eldo2", "eldoin", 700, 3300, 100, + AXP22X_ELDO2_V_OUT, 0x1f, AXP22X_PWR_OUT_CTRL2, BIT(1)), + AXP_DESC(AXP809, ELDO3, "eldo3", "eldoin", 700, 3300, 100, + AXP22X_ELDO3_V_OUT, 0x1f, AXP22X_PWR_OUT_CTRL2, BIT(2)), + AXP_DESC_IO(AXP809, LDO_IO0, "ldo_io0", "ips", 700, 3300, 100, + AXP22X_LDO_IO0_V_OUT, 0x1f, AXP20X_GPIO0_CTRL, 0x07, + AXP22X_IO_ENABLED, AXP22X_IO_DISABLED), + AXP_DESC_IO(AXP809, LDO_IO1, "ldo_io1", "ips", 700, 3300, 100, + AXP22X_LDO_IO1_V_OUT, 0x1f, AXP20X_GPIO1_CTRL, 0x07, + AXP22X_IO_ENABLED, AXP22X_IO_DISABLED), + AXP_DESC_FIXED(AXP809, RTC_LDO, "rtc_ldo", "ips", 1800), + AXP_DESC_SW(AXP809, SW, "sw", "swin", AXP22X_PWR_OUT_CTRL2, BIT(6)), +}; + static int axp20x_set_dcdc_freq(struct platform_device *pdev, u32 dcdcfreq) { struct axp20x_dev *axp20x = dev_get_drvdata(pdev->dev.parent); @@ -245,6 +300,7 @@ static int axp20x_set_dcdc_freq(struct platform_device *pdev, u32 dcdcfreq) break; case AXP221_ID: case AXP223_ID: + case AXP809_ID: min = 1800; max = 4050; def = 3000; @@ -324,6 +380,7 @@ static int axp20x_set_dcdc_workmode(struct regulator_dev *rdev, int id, u32 work case AXP221_ID: case AXP223_ID: + case AXP809_ID: if (id < AXP22X_DCDC1 || id > AXP22X_DCDC5) return -EINVAL; @@ -352,8 +409,8 @@ static int axp20x_regulator_probe(struct platform_device *pdev) }; int ret, i, nregulators; u32 workmode; - const char *axp22x_dc1_name = axp22x_regulators[AXP22X_DCDC1].name; - const char *axp22x_dc5_name = axp22x_regulators[AXP22X_DCDC5].name; + const char *dcdc1_name = axp22x_regulators[AXP22X_DCDC1].name; + const char *dcdc5_name = axp22x_regulators[AXP22X_DCDC5].name; switch (axp20x->variant) { case AXP202_ID: @@ -366,6 +423,10 @@ static int axp20x_regulator_probe(struct platform_device *pdev) regulators = axp22x_regulators; nregulators = AXP22X_REG_ID_MAX; break; + case AXP809_ID: + regulators = axp809_regulators; + nregulators = AXP809_REG_ID_MAX; + break; default: dev_err(&pdev->dev, "Unsupported AXP variant: %ld\n", axp20x->variant); @@ -388,22 +449,22 @@ static int axp20x_regulator_probe(struct platform_device *pdev) * part of this loop to see where we save the DT defined * name. */ - if (regulators == axp22x_regulators) { - if (i == AXP22X_DC1SW) { - new_desc = devm_kzalloc(&pdev->dev, - sizeof(*desc), - GFP_KERNEL); - *new_desc = regulators[i]; - new_desc->supply_name = axp22x_dc1_name; - desc = new_desc; - } else if (i == AXP22X_DC5LDO) { - new_desc = devm_kzalloc(&pdev->dev, - sizeof(*desc), - GFP_KERNEL); - *new_desc = regulators[i]; - new_desc->supply_name = axp22x_dc5_name; - desc = new_desc; - } + if ((regulators == axp22x_regulators && i == AXP22X_DC1SW) || + (regulators == axp809_regulators && i == AXP809_DC1SW)) { + new_desc = devm_kzalloc(&pdev->dev, sizeof(*desc), + GFP_KERNEL); + *new_desc = regulators[i]; + new_desc->supply_name = dcdc1_name; + desc = new_desc; + } + + if ((regulators == axp22x_regulators && i == AXP22X_DC5LDO) || + (regulators == axp809_regulators && i == AXP809_DC5LDO)) { + new_desc = devm_kzalloc(&pdev->dev, sizeof(*desc), + GFP_KERNEL); + *new_desc = regulators[i]; + new_desc->supply_name = dcdc5_name; + desc = new_desc; } rdev = devm_regulator_register(&pdev->dev, desc, &config); @@ -426,17 +487,17 @@ static int axp20x_regulator_probe(struct platform_device *pdev) /* * Save AXP22X DCDC1 / DCDC5 regulator names for later. */ - if (regulators == axp22x_regulators) { - /* Can we use rdev->constraints->name instead? */ - if (i == AXP22X_DCDC1) - of_property_read_string(rdev->dev.of_node, - "regulator-name", - &axp22x_dc1_name); - else if (i == AXP22X_DCDC5) - of_property_read_string(rdev->dev.of_node, - "regulator-name", - &axp22x_dc5_name); - } + if ((regulators == axp22x_regulators && i == AXP22X_DCDC1) || + (regulators == axp809_regulators && i == AXP809_DCDC1)) + of_property_read_string(rdev->dev.of_node, + "regulator-name", + &dcdc1_name); + + if ((regulators == axp22x_regulators && i == AXP22X_DCDC5) || + (regulators == axp809_regulators && i == AXP809_DCDC5)) + of_property_read_string(rdev->dev.of_node, + "regulator-name", + &dcdc5_name); } return 0; -- cgit v1.2.1 From 830583004e615a4637eacc77866b84908414d7a0 Mon Sep 17 00:00:00 2001 From: Boris Brezillon Date: Fri, 3 Jun 2016 10:23:00 +0200 Subject: regulator: pwm: Drop unneeded pwm_enable() call Now that the PWM regulator driver implements the ->enable/disable() hooks we can remove the pwm_enable() call from pwm_regulator_set_voltage(). Signed-off-by: Boris Brezillon Signed-off-by: Mark Brown --- drivers/regulator/pwm-regulator.c | 5 ----- 1 file changed, 5 deletions(-) (limited to 'drivers/regulator') diff --git a/drivers/regulator/pwm-regulator.c b/drivers/regulator/pwm-regulator.c index fafa3488e960..ab3cc0235843 100644 --- a/drivers/regulator/pwm-regulator.c +++ b/drivers/regulator/pwm-regulator.c @@ -159,11 +159,6 @@ static int pwm_regulator_set_voltage(struct regulator_dev *rdev, return ret; } - ret = pwm_enable(drvdata->pwm); - if (ret) { - dev_err(&rdev->dev, "Failed to enable PWM: %d\n", ret); - return ret; - } drvdata->volt_uV = min_uV; /* Delay required by PWM regulator to settle to the new voltage */ -- cgit v1.2.1 From 636e2a39cf904946a0e062bc05445149b366ba2e Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Fri, 3 Jun 2016 18:59:44 +0200 Subject: regulator: axp20x: Add support for the (external) drivebus regulator The axp20x pmics have 2 power inputs, one called ACIN which is intended for to be supplied via a powerbarrel on the board and one called VBUS which is intended to be supplied via an otg connector. In the VBUS case the pmic needs to know if the board is supplying power to the otg connector, because then it should not take any power from its VBUS pin. The axp209 pmic has a N_VBUSEN input pin via which the board can signal to the pmic whether the board is supplying power to the otg connector or not. On the axp221/axp223 this pin can alternatively be used as an output which controls an external regulator which (optionally) supplies power to the otg connector from the board. When the pin is used as output it is called DRIVEVBUS in the datasheet. This commit adds support for the DRIVEVBUS pin as an extra pmic controlled regulator. Since this is optional a new x-powers,drivebus dt property is added. When this is present the misc-control register is written to change the N_VBUSEN input pin to DRIVEVBUS output pin mode and the extra drivebus regulator is registered with the regulator subsystem. Signed-off-by: Hans de Goede Acked-by: Chen-Yu Tsai Signed-off-by: Mark Brown --- drivers/regulator/axp20x-regulator.c | 30 ++++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) (limited to 'drivers/regulator') diff --git a/drivers/regulator/axp20x-regulator.c b/drivers/regulator/axp20x-regulator.c index 728be64e817a..6d9ac76a772f 100644 --- a/drivers/regulator/axp20x-regulator.c +++ b/drivers/regulator/axp20x-regulator.c @@ -36,6 +36,8 @@ #define AXP20X_FREQ_DCDC_MASK 0x0f +#define AXP22X_MISC_N_VBUSEN_FUNC BIT(4) + #define AXP_DESC_IO(_family, _id, _match, _supply, _min, _max, _step, _vreg, \ _vmask, _ereg, _emask, _enable_val, _disable_val) \ [_family##_##_id] = { \ @@ -230,6 +232,18 @@ static const struct regulator_desc axp22x_regulators[] = { AXP_DESC_FIXED(AXP22X, RTC_LDO, "rtc_ldo", "ips", 3000), }; +static const struct regulator_desc axp22x_drivevbus_regulator = { + .name = "drivevbus", + .supply_name = "drivevbus", + .of_match = of_match_ptr("drivevbus"), + .regulators_node = of_match_ptr("regulators"), + .type = REGULATOR_VOLTAGE, + .owner = THIS_MODULE, + .enable_reg = AXP20X_VBUS_IPSOUT_MGMT, + .enable_mask = BIT(2), + .ops = &axp20x_ops_sw, +}; + static const struct regulator_linear_range axp809_dcdc4_ranges[] = { REGULATOR_LINEAR_RANGE(600000, 0x0, 0x2f, 20000), REGULATOR_LINEAR_RANGE(1800000, 0x30, 0x38, 100000), @@ -411,6 +425,7 @@ static int axp20x_regulator_probe(struct platform_device *pdev) u32 workmode; const char *dcdc1_name = axp22x_regulators[AXP22X_DCDC1].name; const char *dcdc5_name = axp22x_regulators[AXP22X_DCDC5].name; + bool drivevbus = false; switch (axp20x->variant) { case AXP202_ID: @@ -422,6 +437,8 @@ static int axp20x_regulator_probe(struct platform_device *pdev) case AXP223_ID: regulators = axp22x_regulators; nregulators = AXP22X_REG_ID_MAX; + drivevbus = of_property_read_bool(pdev->dev.parent->of_node, + "x-powers,drive-vbus-en"); break; case AXP809_ID: regulators = axp809_regulators; @@ -500,6 +517,19 @@ static int axp20x_regulator_probe(struct platform_device *pdev) &dcdc5_name); } + if (drivevbus) { + /* Change N_VBUSEN sense pin to DRIVEVBUS output pin */ + regmap_update_bits(axp20x->regmap, AXP20X_OVER_TMP, + AXP22X_MISC_N_VBUSEN_FUNC, 0); + rdev = devm_regulator_register(&pdev->dev, + &axp22x_drivevbus_regulator, + &config); + if (IS_ERR(rdev)) { + dev_err(&pdev->dev, "Failed to register drivevbus\n"); + return PTR_ERR(rdev); + } + } + return 0; } -- cgit v1.2.1 From 124256548f4e7d3ff81a37a64acb439778bcdbfb Mon Sep 17 00:00:00 2001 From: Fabio Estevam Date: Sun, 5 Jun 2016 19:17:38 -0300 Subject: regulator: pfuze100-regulator: Remove global variable We should better not use a global 'struct pfuze_regulator' variable, as this could cause problems if multiple regulator chips are used. Place it inside the private struct instead. Signed-off-by: Fabio Estevam Signed-off-by: Mark Brown --- drivers/regulator/pfuze100-regulator.c | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) (limited to 'drivers/regulator') diff --git a/drivers/regulator/pfuze100-regulator.c b/drivers/regulator/pfuze100-regulator.c index 2a44e5dd9c2a..bcdf9206f3ee 100644 --- a/drivers/regulator/pfuze100-regulator.c +++ b/drivers/regulator/pfuze100-regulator.c @@ -70,6 +70,7 @@ struct pfuze_chip { struct device *dev; struct pfuze_regulator regulator_descs[PFUZE100_MAX_REGULATOR]; struct regulator_dev *regulators[PFUZE100_MAX_REGULATOR]; + struct pfuze_regulator *pfuze_regulators; }; static const int pfuze100_swbst[] = { @@ -334,8 +335,6 @@ static struct pfuze_regulator pfuze3000_regulators[] = { PFUZE100_VGEN_REG(PFUZE3000, VLDO4, PFUZE100_VGEN6VOL, 1800000, 3300000, 100000), }; -static struct pfuze_regulator *pfuze_regulators; - #ifdef CONFIG_OF /* PFUZE100 */ static struct of_regulator_match pfuze100_matches[] = { @@ -563,21 +562,21 @@ static int pfuze100_regulator_probe(struct i2c_client *client, /* use the right regulators after identify the right device */ switch (pfuze_chip->chip_id) { case PFUZE3000: - pfuze_regulators = pfuze3000_regulators; + pfuze_chip->pfuze_regulators = pfuze3000_regulators; regulator_num = ARRAY_SIZE(pfuze3000_regulators); sw_check_start = PFUZE3000_SW2; sw_check_end = PFUZE3000_SW2; sw_hi = 1 << 3; break; case PFUZE200: - pfuze_regulators = pfuze200_regulators; + pfuze_chip->pfuze_regulators = pfuze200_regulators; regulator_num = ARRAY_SIZE(pfuze200_regulators); sw_check_start = PFUZE200_SW2; sw_check_end = PFUZE200_SW3B; break; case PFUZE100: default: - pfuze_regulators = pfuze100_regulators; + pfuze_chip->pfuze_regulators = pfuze100_regulators; regulator_num = ARRAY_SIZE(pfuze100_regulators); sw_check_start = PFUZE100_SW2; sw_check_end = PFUZE100_SW4; @@ -587,7 +586,7 @@ static int pfuze100_regulator_probe(struct i2c_client *client, (pfuze_chip->chip_id == PFUZE100) ? "100" : ((pfuze_chip->chip_id == PFUZE200) ? "200" : "3000")); - memcpy(pfuze_chip->regulator_descs, pfuze_regulators, + memcpy(pfuze_chip->regulator_descs, pfuze_chip->pfuze_regulators, sizeof(pfuze_chip->regulator_descs)); ret = pfuze_parse_regulators_dt(pfuze_chip); @@ -631,7 +630,7 @@ static int pfuze100_regulator_probe(struct i2c_client *client, devm_regulator_register(&client->dev, desc, &config); if (IS_ERR(pfuze_chip->regulators[i])) { dev_err(&client->dev, "register regulator%s failed\n", - pfuze_regulators[i].desc.name); + pfuze_chip->pfuze_regulators[i].desc.name); return PTR_ERR(pfuze_chip->regulators[i]); } } -- cgit v1.2.1 From af2c55cd4752d77699453ff5550dc316e86d6c77 Mon Sep 17 00:00:00 2001 From: Fabio Estevam Date: Sun, 5 Jun 2016 19:17:39 -0300 Subject: regulator: Kconfig: Mention that PFUZE3000 is also supported The CONFIG_REGULATOR_PFUZE100 option also supports PFUZE3000, so mention that in the Kconfig text. Signed-off-by: Fabio Estevam Signed-off-by: Mark Brown --- drivers/regulator/Kconfig | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers/regulator') diff --git a/drivers/regulator/Kconfig b/drivers/regulator/Kconfig index 144cbf5b3e5a..bd87820d7e61 100644 --- a/drivers/regulator/Kconfig +++ b/drivers/regulator/Kconfig @@ -543,12 +543,12 @@ config REGULATOR_PCF50633 on PCF50633 config REGULATOR_PFUZE100 - tristate "Freescale PFUZE100/PFUZE200 regulator driver" + tristate "Freescale PFUZE100/200/3000 regulator driver" depends on I2C select REGMAP_I2C help Say y here to support the regulators found on the Freescale - PFUZE100/PFUZE200 PMIC. + PFUZE100/200/3000 PMIC. config REGULATOR_PV88060 tristate "Powerventure Semiconductor PV88060 regulator" -- cgit v1.2.1 From 7eeeab8c02c546207be971283adfca1ebf18e387 Mon Sep 17 00:00:00 2001 From: Fabio Estevam Date: Sun, 5 Jun 2016 19:17:40 -0300 Subject: regulator: pfuze100-regulator: Adjust MODULE_DESCRIPTION() Adjust the MODULE_DESCRIPTION() text to also include the PFUZE3000 as a supported device. Signed-off-by: Fabio Estevam Signed-off-by: Mark Brown --- drivers/regulator/pfuze100-regulator.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/regulator') diff --git a/drivers/regulator/pfuze100-regulator.c b/drivers/regulator/pfuze100-regulator.c index bcdf9206f3ee..cb18b5c4f2db 100644 --- a/drivers/regulator/pfuze100-regulator.c +++ b/drivers/regulator/pfuze100-regulator.c @@ -649,5 +649,5 @@ static struct i2c_driver pfuze_driver = { module_i2c_driver(pfuze_driver); MODULE_AUTHOR("Robin Gong "); -MODULE_DESCRIPTION("Regulator Driver for Freescale PFUZE100/PFUZE200 PMIC"); +MODULE_DESCRIPTION("Regulator Driver for Freescale PFUZE100/200/3000 PMIC"); MODULE_LICENSE("GPL v2"); -- cgit v1.2.1 From a8a47540ebe32f1733eebc3e5699af580ceaa3f5 Mon Sep 17 00:00:00 2001 From: Srinivas Kandagatla Date: Thu, 2 Jun 2016 11:23:15 +0100 Subject: regulator: qcom_smd: add list_voltage callback This patch adds support to list_voltage callback, so that consumers like mmc core, can get information of supported voltage range. Without this patch there is no way for mmc core to know this voltage range. Signed-off-by: Srinivas Kandagatla Signed-off-by: Mark Brown Cc: stable@vger.kernel.org # v4.6 --- drivers/regulator/qcom_smd-regulator.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers/regulator') diff --git a/drivers/regulator/qcom_smd-regulator.c b/drivers/regulator/qcom_smd-regulator.c index 56a17ec5b5ef..b11b627a50db 100644 --- a/drivers/regulator/qcom_smd-regulator.c +++ b/drivers/regulator/qcom_smd-regulator.c @@ -140,6 +140,7 @@ static const struct regulator_ops rpm_smps_ldo_ops = { .enable = rpm_reg_enable, .disable = rpm_reg_disable, .is_enabled = rpm_reg_is_enabled, + .list_voltage = regulator_list_voltage_linear_range, .get_voltage = rpm_reg_get_voltage, .set_voltage = rpm_reg_set_voltage, -- cgit v1.2.1 From d1e44b6b2823f1751ffe7e7589f545f05cfe2095 Mon Sep 17 00:00:00 2001 From: Srinivas Kandagatla Date: Fri, 3 Jun 2016 12:23:09 +0100 Subject: regulator: qcom_smd: add regulator ops for pm8941 lnldo After "regulator: qcom_smd: add list_voltage callback" patch adding pm8941 lnldo regulators would bug on list_voltages as it is a fixed regulator without any linear range. This patch fixes that issue by adding dedicated ops for pm8941 lnldo without list_voltages callback. Signed-off-by: Srinivas Kandagatla Signed-off-by: Mark Brown Cc: stable@vger.kernel.org # v4.6 --- drivers/regulator/qcom_smd-regulator.c | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) (limited to 'drivers/regulator') diff --git a/drivers/regulator/qcom_smd-regulator.c b/drivers/regulator/qcom_smd-regulator.c index b11b627a50db..6c7fe4778793 100644 --- a/drivers/regulator/qcom_smd-regulator.c +++ b/drivers/regulator/qcom_smd-regulator.c @@ -148,6 +148,17 @@ static const struct regulator_ops rpm_smps_ldo_ops = { .set_load = rpm_reg_set_load, }; +static const struct regulator_ops rpm_smps_ldo_ops_fixed = { + .enable = rpm_reg_enable, + .disable = rpm_reg_disable, + .is_enabled = rpm_reg_is_enabled, + + .get_voltage = rpm_reg_get_voltage, + .set_voltage = rpm_reg_set_voltage, + + .set_load = rpm_reg_set_load, +}; + static const struct regulator_ops rpm_switch_ops = { .enable = rpm_reg_enable, .disable = rpm_reg_disable, @@ -248,7 +259,7 @@ static const struct regulator_desc pm8941_nldo = { static const struct regulator_desc pm8941_lnldo = { .fixed_uV = 1740000, .n_voltages = 1, - .ops = &rpm_smps_ldo_ops, + .ops = &rpm_smps_ldo_ops_fixed, }; static const struct regulator_desc pm8941_switch = { -- cgit v1.2.1 From 2ac1ea2c4a8c714d8994ce35d0f6f9fec5e8cdc5 Mon Sep 17 00:00:00 2001 From: Ben Dooks Date: Tue, 7 Jun 2016 18:40:01 +0100 Subject: regulator: twl: fix use of integer as pointer The TWL6030_FIXED_LDO() macro passes the TWL_FIXED_LDO() macro an 0x0 instead of a NULL. Changing this to a NULL fixes the following warnings: drivers/regulator/twl-regulator.c:1068:1: warning: Using plain integer as NULL pointer drivers/regulator/twl-regulator.c:1069:1: warning: Using plain integer as NULL pointer drivers/regulator/twl-regulator.c:1070:1: warning: Using plain integer as NULL pointer drivers/regulator/twl-regulator.c:1071:1: warning: Using plain integer as NULL pointer drivers/regulator/twl-regulator.c:1072:1: warning: Using plain integer as NULL pointer drivers/regulator/twl-regulator.c:1073:1: warning: Using plain integer as NULL pointer Signed-off-by: Ben Dooks Signed-off-by: Mark Brown --- drivers/regulator/twl-regulator.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/regulator') diff --git a/drivers/regulator/twl-regulator.c b/drivers/regulator/twl-regulator.c index faeb5ee92c9e..210681d6b743 100644 --- a/drivers/regulator/twl-regulator.c +++ b/drivers/regulator/twl-regulator.c @@ -905,7 +905,7 @@ static struct regulator_ops twlsmps_ops = { twl4030reg_map_mode) #define TWL6030_FIXED_LDO(label, offset, mVolts, turnon_delay) \ TWL_FIXED_LDO(label, offset, mVolts, 0x0, turnon_delay, \ - 0x0, TWL6030, twl6030fixed_ops, 0x0) + 0x0, TWL6030, twl6030fixed_ops, NULL) #define TWL4030_ADJUSTABLE_LDO(label, offset, num, turnon_delay, remap_conf) \ static const struct twlreg_info TWL4030_INFO_##label = { \ -- cgit v1.2.1 From fc1e1c4a249e8bf0aff68576fad776dd5adc0562 Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Thu, 9 Jun 2016 10:49:02 +0100 Subject: regulator: Remove regulator_can_change_voltage() There is little obvious use case for a regualtor driver to know if it is possible to vary voltages at all by itself. If a consumer needs to limit what voltages it tries to set based on the system configuration then it will need to enumerate the possible voltages, and without that even if it is possible to change voltages that doesn't mean that constraints or other consumers will allow whatever change the driver is trying to do at a given time. It doesn't even indicate if _set_voltage() calls will work as noop _set_voltage() calls return success. There were no users of this API that weren't abusing it and now they're all gone so remove the API. Signed-off-by: Mark Brown --- drivers/regulator/core.c | 27 --------------------------- 1 file changed, 27 deletions(-) (limited to 'drivers/regulator') diff --git a/drivers/regulator/core.c b/drivers/regulator/core.c index ec8184d53f13..db320e8fa865 100644 --- a/drivers/regulator/core.c +++ b/drivers/regulator/core.c @@ -2508,33 +2508,6 @@ int regulator_is_enabled(struct regulator *regulator) } EXPORT_SYMBOL_GPL(regulator_is_enabled); -/** - * regulator_can_change_voltage - check if regulator can change voltage - * @regulator: regulator source - * - * Returns positive if the regulator driver backing the source/client - * can change its voltage, false otherwise. Useful for detecting fixed - * or dummy regulators and disabling voltage change logic in the client - * driver. - */ -int regulator_can_change_voltage(struct regulator *regulator) -{ - struct regulator_dev *rdev = regulator->rdev; - - if (regulator_ops_is_valid(rdev, REGULATOR_CHANGE_VOLTAGE)) { - if (rdev->desc->n_voltages - rdev->desc->linear_min_sel > 1) - return 1; - - if (rdev->desc->continuous_voltage_range && - rdev->constraints->min_uV && rdev->constraints->max_uV && - rdev->constraints->min_uV != rdev->constraints->max_uV) - return 1; - } - - return 0; -} -EXPORT_SYMBOL_GPL(regulator_can_change_voltage); - /** * regulator_count_voltages - count regulator_list_voltage() selectors * @regulator: regulator source -- cgit v1.2.1 From 3bfbb4d1a480cc17f6ccfce13b76eb6c0dbeaf8c Mon Sep 17 00:00:00 2001 From: Srinivas Kandagatla Date: Thu, 2 Jun 2016 11:23:15 +0100 Subject: regulator: qcom_smd: add list_voltage callback This patch adds support to list_voltage callback, so that consumers like mmc core, can get information of supported voltage range. Without this patch there is no way for mmc core to know this voltage range. Signed-off-by: Srinivas Kandagatla Signed-off-by: Mark Brown --- drivers/regulator/qcom_smd-regulator.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers/regulator') diff --git a/drivers/regulator/qcom_smd-regulator.c b/drivers/regulator/qcom_smd-regulator.c index 6c7fe4778793..526bf23dcb49 100644 --- a/drivers/regulator/qcom_smd-regulator.c +++ b/drivers/regulator/qcom_smd-regulator.c @@ -152,6 +152,7 @@ static const struct regulator_ops rpm_smps_ldo_ops_fixed = { .enable = rpm_reg_enable, .disable = rpm_reg_disable, .is_enabled = rpm_reg_is_enabled, + .list_voltage = regulator_list_voltage_linear_range, .get_voltage = rpm_reg_get_voltage, .set_voltage = rpm_reg_set_voltage, -- cgit v1.2.1 From 43160ffd12c8d1d331362362eea3c70e04b6f9c4 Mon Sep 17 00:00:00 2001 From: Axel Lin Date: Wed, 15 Jun 2016 10:21:34 +0800 Subject: regulator: qcom_smd: Remove list_voltage callback for rpm_smps_ldo_ops_fixed Use regulator_list_voltage_linear_range in rpm_smps_ldo_ops_fixed is wrong because it is used for fixed regulator without any linear range. The rpm_smps_ldo_ops_fixed is used for pm8941_lnldo which has fixed_uV set and n_voltages = 1. In this case, regulator_list_voltage() can return rdev->desc->fixed_uV without .list_voltage implementation. Fixes: 3bfbb4d1a480 ("regulator: qcom_smd: add list_voltage callback") Signed-off-by: Axel Lin Signed-off-by: Mark Brown --- drivers/regulator/qcom_smd-regulator.c | 1 - 1 file changed, 1 deletion(-) (limited to 'drivers/regulator') diff --git a/drivers/regulator/qcom_smd-regulator.c b/drivers/regulator/qcom_smd-regulator.c index 526bf23dcb49..6c7fe4778793 100644 --- a/drivers/regulator/qcom_smd-regulator.c +++ b/drivers/regulator/qcom_smd-regulator.c @@ -152,7 +152,6 @@ static const struct regulator_ops rpm_smps_ldo_ops_fixed = { .enable = rpm_reg_enable, .disable = rpm_reg_disable, .is_enabled = rpm_reg_is_enabled, - .list_voltage = regulator_list_voltage_linear_range, .get_voltage = rpm_reg_get_voltage, .set_voltage = rpm_reg_set_voltage, -- cgit v1.2.1 From 8a092e682f20f193f2070dba2ea1904e95814126 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mika=20B=C3=A5tsman?= Date: Fri, 17 Jun 2016 13:31:37 +0300 Subject: regulator: anatop: allow regulator to be in bypass mode MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Bypass support was added in commit d38018f2019c ("regulator: anatop: Add bypass support to digital LDOs"). A check for valid voltage selectors was added in commit da0607c8df5c ("regulator: anatop: Fail on invalid voltage selector") but it also discards all regulators that are in bypass mode. Add check for the bypass setting. Errors below were seen on a Variscite mx6 board. anatop_regulator 20c8000.anatop:regulator-vddcore@140: Failed to read a valid default voltage selector. anatop_regulator: probe of 20c8000.anatop:regulator-vddcore@140 failed with error -22 anatop_regulator 20c8000.anatop:regulator-vddsoc@140: Failed to read a valid default voltage selector. anatop_regulator: probe of 20c8000.anatop:regulator-vddsoc@140 failed with error -22 Fixes: da0607c8df5c ("regulator: anatop: Fail on invalid voltage selector") Signed-off-by: Mika Båtsman Signed-off-by: Mark Brown --- drivers/regulator/anatop-regulator.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/regulator') diff --git a/drivers/regulator/anatop-regulator.c b/drivers/regulator/anatop-regulator.c index 63cd5e68c864..3a6d0290c54c 100644 --- a/drivers/regulator/anatop-regulator.c +++ b/drivers/regulator/anatop-regulator.c @@ -296,7 +296,7 @@ static int anatop_regulator_probe(struct platform_device *pdev) if (!sreg->sel && !strcmp(sreg->name, "vddpu")) sreg->sel = 22; - if (!sreg->sel) { + if (!sreg->bypass && !sreg->sel) { dev_err(&pdev->dev, "Failed to read a valid default voltage selector.\n"); return -EINVAL; } -- cgit v1.2.1 From 4335f6537a62df50c049427134fe07d9bc6354ab Mon Sep 17 00:00:00 2001 From: Axel Lin Date: Tue, 21 Jun 2016 14:59:11 +0800 Subject: regulator: lp873x: Drop _nlr parameter from LP873X_REGULATOR() No need to pass _nlr to LP873X_REGULATOR(), use ARRAY_SIZE to calculate it. Signed-off-by: Axel Lin Acked-by: Keerthy Signed-off-by: Mark Brown --- drivers/regulator/lp873x-regulator.c | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) (limited to 'drivers/regulator') diff --git a/drivers/regulator/lp873x-regulator.c b/drivers/regulator/lp873x-regulator.c index b4ffd113ba21..e504b9148226 100644 --- a/drivers/regulator/lp873x-regulator.c +++ b/drivers/regulator/lp873x-regulator.c @@ -20,7 +20,7 @@ #include #define LP873X_REGULATOR(_name, _id, _of, _ops, _n, _vr, _vm, _er, _em, \ - _delay, _lr, _nlr, _cr) \ + _delay, _lr, _cr) \ [_id] = { \ .desc = { \ .name = _name, \ @@ -37,7 +37,7 @@ .enable_mask = _em, \ .ramp_delay = _delay, \ .linear_ranges = _lr, \ - .n_linear_ranges = _nlr, \ + .n_linear_ranges = ARRAY_SIZE(_lr), \ }, \ .ctrl2_reg = _cr, \ } @@ -175,22 +175,20 @@ static const struct lp873x_regulator regulators[] = { 256, LP873X_REG_BUCK0_VOUT, LP873X_BUCK0_VOUT_BUCK0_VSET, LP873X_REG_BUCK0_CTRL_1, LP873X_BUCK0_CTRL_1_BUCK0_EN, 10000, - buck0_buck1_ranges, 4, LP873X_REG_BUCK0_CTRL_2), + buck0_buck1_ranges, LP873X_REG_BUCK0_CTRL_2), LP873X_REGULATOR("BUCK1", LP873X_BUCK_1, "buck1", lp873x_buck01_ops, 256, LP873X_REG_BUCK1_VOUT, LP873X_BUCK1_VOUT_BUCK1_VSET, LP873X_REG_BUCK1_CTRL_1, LP873X_BUCK1_CTRL_1_BUCK1_EN, 10000, - buck0_buck1_ranges, 4, LP873X_REG_BUCK1_CTRL_2), + buck0_buck1_ranges, LP873X_REG_BUCK1_CTRL_2), LP873X_REGULATOR("LDO0", LP873X_LDO_0, "ldo0", lp873x_ldo01_ops, 26, LP873X_REG_LDO0_VOUT, LP873X_LDO0_VOUT_LDO0_VSET, LP873X_REG_LDO0_CTRL, - LP873X_LDO0_CTRL_LDO0_EN, 0, ldo0_ldo1_ranges, 1, - 0xFF), + LP873X_LDO0_CTRL_LDO0_EN, 0, ldo0_ldo1_ranges, 0xFF), LP873X_REGULATOR("LDO1", LP873X_LDO_1, "ldo1", lp873x_ldo01_ops, 26, LP873X_REG_LDO1_VOUT, LP873X_LDO1_VOUT_LDO1_VSET, LP873X_REG_LDO1_CTRL, - LP873X_LDO1_CTRL_LDO1_EN, 0, ldo0_ldo1_ranges, 1, - 0xFF), + LP873X_LDO1_CTRL_LDO1_EN, 0, ldo0_ldo1_ranges, 0xFF), }; static int lp873x_regulator_probe(struct platform_device *pdev) -- cgit v1.2.1 From a0f78bc89c0396d14b6102c6f72485e14c8821f3 Mon Sep 17 00:00:00 2001 From: Keerthy Date: Mon, 20 Jun 2016 14:13:31 +0530 Subject: regulator: of: setup initial suspend state Setup initial suspend state to mem, if suspend state is defined for mem state. This makes sure that the regulators are in proper mode already from boot. Signed-off-by: Tero Kristo Signed-off-by: Dave Gerlach Signed-off-by: Keerthy Signed-off-by: Mark Brown --- drivers/regulator/of_regulator.c | 3 +++ 1 file changed, 3 insertions(+) (limited to 'drivers/regulator') diff --git a/drivers/regulator/of_regulator.c b/drivers/regulator/of_regulator.c index cd828dbf9d52..4f613ec99500 100644 --- a/drivers/regulator/of_regulator.c +++ b/drivers/regulator/of_regulator.c @@ -163,6 +163,9 @@ static void of_get_regulation_constraints(struct device_node *np, "regulator-suspend-microvolt", &pval)) suspend_state->uV = pval; + if (i == PM_SUSPEND_MEM) + constraints->initial_state = PM_SUSPEND_MEM; + of_node_put(suspend_np); suspend_state = NULL; suspend_np = NULL; -- cgit v1.2.1 From 27bfa8893b15a3fa22a593c90a48c8bcb1f9c75b Mon Sep 17 00:00:00 2001 From: Alexandre Courbot Date: Thu, 23 Jun 2016 16:39:44 +0900 Subject: regulator: pwm: Support for enable GPIO Add an optional enable GPIO to the pwm-regulator driver. Signed-off-by: Alexandre Courbot Signed-off-by: Mark Brown --- drivers/regulator/pwm-regulator.c | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) (limited to 'drivers/regulator') diff --git a/drivers/regulator/pwm-regulator.c b/drivers/regulator/pwm-regulator.c index ab3cc0235843..90f8b7fd0437 100644 --- a/drivers/regulator/pwm-regulator.c +++ b/drivers/regulator/pwm-regulator.c @@ -20,6 +20,7 @@ #include #include #include +#include struct pwm_regulator_data { /* Shared */ @@ -38,6 +39,9 @@ struct pwm_regulator_data { /* Continuous voltage */ int volt_uV; + + /* Enable GPIO */ + struct gpio_desc *enb_gpio; }; struct pwm_voltages { @@ -94,6 +98,9 @@ static int pwm_regulator_enable(struct regulator_dev *dev) { struct pwm_regulator_data *drvdata = rdev_get_drvdata(dev); + if (drvdata->enb_gpio) + gpiod_set_value_cansleep(drvdata->enb_gpio, 1); + return pwm_enable(drvdata->pwm); } @@ -103,6 +110,9 @@ static int pwm_regulator_disable(struct regulator_dev *dev) pwm_disable(drvdata->pwm); + if (drvdata->enb_gpio) + gpiod_set_value_cansleep(drvdata->enb_gpio, 0); + return 0; } @@ -110,6 +120,9 @@ static int pwm_regulator_is_enabled(struct regulator_dev *dev) { struct pwm_regulator_data *drvdata = rdev_get_drvdata(dev); + if (drvdata->enb_gpio && !gpiod_get_value_cansleep(drvdata->enb_gpio)) + return false; + return pwm_is_enabled(drvdata->pwm); } @@ -248,6 +261,7 @@ static int pwm_regulator_probe(struct platform_device *pdev) struct regulator_dev *regulator; struct regulator_config config = { }; struct device_node *np = pdev->dev.of_node; + enum gpiod_flags gpio_flags; int ret; if (!np) { @@ -285,6 +299,18 @@ static int pwm_regulator_probe(struct platform_device *pdev) return ret; } + if (init_data->constraints.boot_on || init_data->constraints.always_on) + gpio_flags = GPIOD_OUT_HIGH; + else + gpio_flags = GPIOD_OUT_LOW; + drvdata->enb_gpio = devm_gpiod_get_optional(&pdev->dev, "enable", + gpio_flags); + if (IS_ERR(drvdata->enb_gpio)) { + ret = PTR_ERR(drvdata->enb_gpio); + dev_err(&pdev->dev, "Failed to get enable GPIO: %d\n", ret); + return ret; + } + /* * FIXME: pwm_apply_args() should be removed when switching to the * atomic PWM API. -- cgit v1.2.1 From c333dfe8dba7d3e47e97e1cee3c38123e19ae73c Mon Sep 17 00:00:00 2001 From: Stephen Boyd Date: Sat, 25 Jun 2016 22:52:11 -0700 Subject: regulator: qcom_spmi: Add support for S4 supply on pm8941 The S4 supply is sometimes called the boost regulator because it outputs 5V. Typically it's connected to the 5vs1 and 5vs2 switches for use in USB OTG and HDMI applications. Add support for this regulator which was mistakenly left out from the initial submission of this driver. Cc: Bjorn Andersson Fixes: e92a4047419c ("regulator: Add QCOM SPMI regulator driver") Signed-off-by: Stephen Boyd Signed-off-by: Mark Brown --- drivers/regulator/qcom_spmi-regulator.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers/regulator') diff --git a/drivers/regulator/qcom_spmi-regulator.c b/drivers/regulator/qcom_spmi-regulator.c index 84cce21e98cd..fe09407b150b 100644 --- a/drivers/regulator/qcom_spmi-regulator.c +++ b/drivers/regulator/qcom_spmi-regulator.c @@ -1496,6 +1496,7 @@ static const struct spmi_regulator_data pm8941_regulators[] = { { "s1", 0x1400, "vdd_s1", }, { "s2", 0x1700, "vdd_s2", }, { "s3", 0x1a00, "vdd_s3", }, + { "s4", 0xa000, }, { "l1", 0x4000, "vdd_l1_l3", }, { "l2", 0x4100, "vdd_l2_lvs_1_2_3", }, { "l3", 0x4200, "vdd_l1_l3", }, -- cgit v1.2.1 From 93bfe79b03365f410aa91caf04263173c008ecdf Mon Sep 17 00:00:00 2001 From: Stephen Boyd Date: Sat, 25 Jun 2016 22:52:12 -0700 Subject: regulator: qcom_spmi: Update mvs1/mvs2 switches on pm8941 The mvs1 and mvs2 switches are actually called 5vs1 and 5vs2 on some datasheets. Let's rename them to match the datasheets and also match the RPM based regulator driver which calls these by their 5vs names (see qcom_smd-regulator.c). There aren't any users of these regulators so far, so there aren't any concerns of DT ABI breakage here. While we're here making updates to the switches, also mandate usage of the OCP irq for these switches too. Cc: Bjorn Andersson Fixes: e92a4047419c ("regulator: Add QCOM SPMI regulator driver") Signed-off-by: Stephen Boyd Signed-off-by: Mark Brown --- drivers/regulator/qcom_spmi-regulator.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers/regulator') diff --git a/drivers/regulator/qcom_spmi-regulator.c b/drivers/regulator/qcom_spmi-regulator.c index fe09407b150b..43f8f20b82e9 100644 --- a/drivers/regulator/qcom_spmi-regulator.c +++ b/drivers/regulator/qcom_spmi-regulator.c @@ -1524,8 +1524,8 @@ static const struct spmi_regulator_data pm8941_regulators[] = { { "lvs1", 0x8000, "vdd_l2_lvs_1_2_3", }, { "lvs2", 0x8100, "vdd_l2_lvs_1_2_3", }, { "lvs3", 0x8200, "vdd_l2_lvs_1_2_3", }, - { "mvs1", 0x8300, "vin_5vs", }, - { "mvs2", 0x8400, "vin_5vs", }, + { "5vs1", 0x8300, "vin_5vs", "ocp-5vs1", }, + { "5vs2", 0x8400, "vin_5vs", "ocp-5vs2", }, { } }; -- cgit v1.2.1 From 919163f6362ac23138d31fc8befdd52e5d7e488d Mon Sep 17 00:00:00 2001 From: Stephen Boyd Date: Sat, 25 Jun 2016 22:52:13 -0700 Subject: regulator: qcom_spmi: Add support for get_mode/set_mode on switches The voltage switches support mode switching, so add support for these ops to those types of regulators. Cc: Bjorn Andersson Fixes: e92a4047419c ("regulator: Add QCOM SPMI regulator driver") Signed-off-by: Stephen Boyd Signed-off-by: Mark Brown --- drivers/regulator/qcom_spmi-regulator.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'drivers/regulator') diff --git a/drivers/regulator/qcom_spmi-regulator.c b/drivers/regulator/qcom_spmi-regulator.c index 43f8f20b82e9..16c5f84e06a7 100644 --- a/drivers/regulator/qcom_spmi-regulator.c +++ b/drivers/regulator/qcom_spmi-regulator.c @@ -1085,6 +1085,8 @@ static struct regulator_ops spmi_vs_ops = { .set_pull_down = spmi_regulator_common_set_pull_down, .set_soft_start = spmi_regulator_common_set_soft_start, .set_over_current_protection = spmi_regulator_vs_ocp, + .set_mode = spmi_regulator_common_set_mode, + .get_mode = spmi_regulator_common_get_mode, }; static struct regulator_ops spmi_boost_ops = { -- cgit v1.2.1 From 3de56099591a4042556a2d05d4703387ad950c6f Mon Sep 17 00:00:00 2001 From: Russ Dill Date: Fri, 24 Jun 2016 13:58:07 +0530 Subject: regulator: tps65217: Enable suspend configuration The TPS65217 has a pre-defined power-up / power-down sequence which in a typical application does not need to be changed. However, it is possible to define custom sequences under I2C control. The power-up sequence is defined by strobes and delay times. Each output rail is assigned to a strobe to determine the order in which the rails are enabled. Every regulator of tps65217 PMIC has sequence registers and every regulator has a default strobe value and gets disabled when a particular power down sequence occurs. To keep a regulator on during suspend we write value 0 to strobe so that the regulator is out of all sequencers and is not impacted by any power down sequence. Hence saving the default strobe value during probe so that when we want to regulator to be enabled during suspend we write 0 to strobe and when we want it to get disabled during suspend we write the default saved strobe value. This allows platform data to specify which power rails should be on or off during RTC only suspend. This is necessary to keep DDR state while in RTC only suspend. Signed-off-by: Russ Dill [Enhanced commit log and added dynamic allocation for strobes] Signed-off-by: Keerthy Signed-off-by: Mark Brown --- drivers/regulator/tps65217-regulator.c | 69 +++++++++++++++++++++++++++++----- 1 file changed, 60 insertions(+), 9 deletions(-) (limited to 'drivers/regulator') diff --git a/drivers/regulator/tps65217-regulator.c b/drivers/regulator/tps65217-regulator.c index adbe4fc5cf07..2d12b9af3540 100644 --- a/drivers/regulator/tps65217-regulator.c +++ b/drivers/regulator/tps65217-regulator.c @@ -28,7 +28,7 @@ #include #define TPS65217_REGULATOR(_name, _id, _of_match, _ops, _n, _vr, _vm, _em, \ - _t, _lr, _nlr) \ + _t, _lr, _nlr, _sr, _sm) \ { \ .name = _name, \ .id = _id, \ @@ -45,6 +45,8 @@ .volt_table = _t, \ .linear_ranges = _lr, \ .n_linear_ranges = _nlr, \ + .bypass_reg = _sr, \ + .bypass_mask = _sm, \ } \ static const unsigned int LDO1_VSEL_table[] = { @@ -118,6 +120,35 @@ static int tps65217_pmic_set_voltage_sel(struct regulator_dev *dev, return ret; } +static int tps65217_pmic_set_suspend_enable(struct regulator_dev *dev) +{ + struct tps65217 *tps = rdev_get_drvdata(dev); + unsigned int rid = rdev_get_id(dev); + + if (rid < TPS65217_DCDC_1 || rid > TPS65217_LDO_4) + return -EINVAL; + + return tps65217_clear_bits(tps, dev->desc->bypass_reg, + dev->desc->bypass_mask, + TPS65217_PROTECT_L1); +} + +static int tps65217_pmic_set_suspend_disable(struct regulator_dev *dev) +{ + struct tps65217 *tps = rdev_get_drvdata(dev); + unsigned int rid = rdev_get_id(dev); + + if (rid < TPS65217_DCDC_1 || rid > TPS65217_LDO_4) + return -EINVAL; + + if (!tps->strobes[rid]) + return -EINVAL; + + return tps65217_set_bits(tps, dev->desc->bypass_reg, + dev->desc->bypass_mask, + tps->strobes[rid], TPS65217_PROTECT_L1); +} + /* Operations permitted on DCDCx, LDO2, LDO3 and LDO4 */ static struct regulator_ops tps65217_pmic_ops = { .is_enabled = regulator_is_enabled_regmap, @@ -127,6 +158,8 @@ static struct regulator_ops tps65217_pmic_ops = { .set_voltage_sel = tps65217_pmic_set_voltage_sel, .list_voltage = regulator_list_voltage_linear_range, .map_voltage = regulator_map_voltage_linear_range, + .set_suspend_enable = tps65217_pmic_set_suspend_enable, + .set_suspend_disable = tps65217_pmic_set_suspend_disable, }; /* Operations permitted on LDO1 */ @@ -138,41 +171,50 @@ static struct regulator_ops tps65217_pmic_ldo1_ops = { .set_voltage_sel = tps65217_pmic_set_voltage_sel, .list_voltage = regulator_list_voltage_table, .map_voltage = regulator_map_voltage_ascend, + .set_suspend_enable = tps65217_pmic_set_suspend_enable, + .set_suspend_disable = tps65217_pmic_set_suspend_disable, }; static const struct regulator_desc regulators[] = { TPS65217_REGULATOR("DCDC1", TPS65217_DCDC_1, "dcdc1", tps65217_pmic_ops, 64, TPS65217_REG_DEFDCDC1, TPS65217_DEFDCDCX_DCDC_MASK, TPS65217_ENABLE_DC1_EN, - NULL, tps65217_uv1_ranges, 2), + NULL, tps65217_uv1_ranges, 2, TPS65217_REG_SEQ1, + TPS65217_SEQ1_DC1_SEQ_MASK), TPS65217_REGULATOR("DCDC2", TPS65217_DCDC_2, "dcdc2", tps65217_pmic_ops, 64, TPS65217_REG_DEFDCDC2, TPS65217_DEFDCDCX_DCDC_MASK, TPS65217_ENABLE_DC2_EN, NULL, tps65217_uv1_ranges, - ARRAY_SIZE(tps65217_uv1_ranges)), + ARRAY_SIZE(tps65217_uv1_ranges), TPS65217_REG_SEQ1, + TPS65217_SEQ1_DC2_SEQ_MASK), TPS65217_REGULATOR("DCDC3", TPS65217_DCDC_3, "dcdc3", tps65217_pmic_ops, 64, TPS65217_REG_DEFDCDC3, TPS65217_DEFDCDCX_DCDC_MASK, TPS65217_ENABLE_DC3_EN, - NULL, tps65217_uv1_ranges, 1), + NULL, tps65217_uv1_ranges, 1, TPS65217_REG_SEQ2, + TPS65217_SEQ2_DC3_SEQ_MASK), TPS65217_REGULATOR("LDO1", TPS65217_LDO_1, "ldo1", tps65217_pmic_ldo1_ops, 16, TPS65217_REG_DEFLDO1, TPS65217_DEFLDO1_LDO1_MASK, TPS65217_ENABLE_LDO1_EN, - LDO1_VSEL_table, NULL, 0), + LDO1_VSEL_table, NULL, 0, TPS65217_REG_SEQ2, + TPS65217_SEQ2_LDO1_SEQ_MASK), TPS65217_REGULATOR("LDO2", TPS65217_LDO_2, "ldo2", tps65217_pmic_ops, 64, TPS65217_REG_DEFLDO2, TPS65217_DEFLDO2_LDO2_MASK, TPS65217_ENABLE_LDO2_EN, NULL, tps65217_uv1_ranges, - ARRAY_SIZE(tps65217_uv1_ranges)), + ARRAY_SIZE(tps65217_uv1_ranges), TPS65217_REG_SEQ3, + TPS65217_SEQ3_LDO2_SEQ_MASK), TPS65217_REGULATOR("LDO3", TPS65217_LDO_3, "ldo3", tps65217_pmic_ops, 32, TPS65217_REG_DEFLS1, TPS65217_DEFLDO3_LDO3_MASK, TPS65217_ENABLE_LS1_EN | TPS65217_DEFLDO3_LDO3_EN, NULL, tps65217_uv2_ranges, - ARRAY_SIZE(tps65217_uv2_ranges)), + ARRAY_SIZE(tps65217_uv2_ranges), TPS65217_REG_SEQ3, + TPS65217_SEQ3_LDO3_SEQ_MASK), TPS65217_REGULATOR("LDO4", TPS65217_LDO_4, "ldo4", tps65217_pmic_ops, 32, TPS65217_REG_DEFLS2, TPS65217_DEFLDO4_LDO4_MASK, TPS65217_ENABLE_LS2_EN | TPS65217_DEFLDO4_LDO4_EN, NULL, tps65217_uv2_ranges, - ARRAY_SIZE(tps65217_uv2_ranges)), + ARRAY_SIZE(tps65217_uv2_ranges), TPS65217_REG_SEQ4, + TPS65217_SEQ4_LDO4_SEQ_MASK), }; static int tps65217_regulator_probe(struct platform_device *pdev) @@ -181,13 +223,18 @@ static int tps65217_regulator_probe(struct platform_device *pdev) struct tps65217_board *pdata = dev_get_platdata(tps->dev); struct regulator_dev *rdev; struct regulator_config config = { }; - int i; + int i, ret; + unsigned int val; if (tps65217_chip_id(tps) != TPS65217) { dev_err(&pdev->dev, "Invalid tps chip version\n"); return -ENODEV; } + /* Allocate memory for strobes */ + tps->strobes = devm_kzalloc(&pdev->dev, sizeof(u8) * + TPS65217_NUM_REGULATOR, GFP_KERNEL); + platform_set_drvdata(pdev, tps); for (i = 0; i < TPS65217_NUM_REGULATOR; i++) { @@ -205,6 +252,10 @@ static int tps65217_regulator_probe(struct platform_device *pdev) pdev->name); return PTR_ERR(rdev); } + + /* Store default strobe info */ + ret = tps65217_reg_read(tps, regulators[i].bypass_reg, &val); + tps->strobes[i] = val & regulators[i].bypass_mask; } return 0; -- cgit v1.2.1 From b9a0d359413d7f4e078d81cd59f9d851a6febb7a Mon Sep 17 00:00:00 2001 From: Tero Kristo Date: Fri, 24 Jun 2016 13:58:08 +0530 Subject: regulator: tps65218: Enable suspend configuration TPS65218 has a pre-defined power-up / power-down sequence which in a typical application does not need to be changed. However, it is possible to define custom sequences under I2C control. The power-up sequence is defined by strobes and delay times. Each output rail is assigned to a strobe to determine the order in which the rails are enabled. Every regulator has sequence registers and every regulator has a default strobe value and gets disabled when a particular power down sequence occurs. To keep a regulator on during suspend we write value 0 to strobe so that the regulator is out of all sequencers and is not impacted by any power down sequence. Hence saving the default strobe value during probe so that when we want to regulator to be enabled during suspend we write 0 to strobe and when we want it to get disabled during suspend we write the default saved strobe value. This allows platform data to specify which power rails should be on or off during RTC only suspend. This is necessary to keep DDR state while in RTC only suspend. Signed-off-by: Tero Kristo Signed-off-by: Keerthy Signed-off-by: Mark Brown --- drivers/regulator/tps65218-regulator.c | 72 ++++++++++++++++++++++++++++------ 1 file changed, 61 insertions(+), 11 deletions(-) (limited to 'drivers/regulator') diff --git a/drivers/regulator/tps65218-regulator.c b/drivers/regulator/tps65218-regulator.c index a5e5634eeb9e..8eca1eb4f219 100644 --- a/drivers/regulator/tps65218-regulator.c +++ b/drivers/regulator/tps65218-regulator.c @@ -31,7 +31,7 @@ enum tps65218_regulators { DCDC1, DCDC2, DCDC3, DCDC4, DCDC5, DCDC6, LDO1, LS3 }; #define TPS65218_REGULATOR(_name, _id, _type, _ops, _n, _vr, _vm, _er, _em, \ - _cr, _cm, _lr, _nlr, _delay, _fuv) \ + _cr, _cm, _lr, _nlr, _delay, _fuv, _sr, _sm) \ { \ .name = _name, \ .id = _id, \ @@ -49,7 +49,9 @@ enum tps65218_regulators { DCDC1, DCDC2, DCDC3, DCDC4, .linear_ranges = _lr, \ .n_linear_ranges = _nlr, \ .ramp_delay = _delay, \ - .fixed_uV = _fuv \ + .fixed_uV = _fuv, \ + .bypass_reg = _sr, \ + .bypass_mask = _sm, \ } \ #define TPS65218_INFO(_id, _nm, _min, _max) \ @@ -157,6 +159,36 @@ static int tps65218_pmic_disable(struct regulator_dev *dev) dev->desc->enable_mask, TPS65218_PROTECT_L1); } +static int tps65218_pmic_set_suspend_enable(struct regulator_dev *dev) +{ + struct tps65218 *tps = rdev_get_drvdata(dev); + unsigned int rid = rdev_get_id(dev); + + if (rid < TPS65218_DCDC_1 || rid > TPS65218_LDO_1) + return -EINVAL; + + return tps65218_clear_bits(tps, dev->desc->bypass_reg, + dev->desc->bypass_mask, + TPS65218_PROTECT_L1); +} + +static int tps65218_pmic_set_suspend_disable(struct regulator_dev *dev) +{ + struct tps65218 *tps = rdev_get_drvdata(dev); + unsigned int rid = rdev_get_id(dev); + + if (rid < TPS65218_DCDC_1 || rid > TPS65218_LDO_1) + return -EINVAL; + + if (!tps->info[rid]->strobe) + return -EINVAL; + + return tps65218_set_bits(tps, dev->desc->bypass_reg, + dev->desc->bypass_mask, + tps->info[rid]->strobe, + TPS65218_PROTECT_L1); +} + /* Operations permitted on DCDC1, DCDC2 */ static struct regulator_ops tps65218_dcdc12_ops = { .is_enabled = regulator_is_enabled_regmap, @@ -167,6 +199,8 @@ static struct regulator_ops tps65218_dcdc12_ops = { .list_voltage = regulator_list_voltage_linear_range, .map_voltage = regulator_map_voltage_linear_range, .set_voltage_time_sel = regulator_set_voltage_time_sel, + .set_suspend_enable = tps65218_pmic_set_suspend_enable, + .set_suspend_disable = tps65218_pmic_set_suspend_disable, }; /* Operations permitted on DCDC3, DCDC4 and LDO1 */ @@ -178,6 +212,8 @@ static struct regulator_ops tps65218_ldo1_dcdc34_ops = { .set_voltage_sel = tps65218_pmic_set_voltage_sel, .list_voltage = regulator_list_voltage_linear_range, .map_voltage = regulator_map_voltage_linear_range, + .set_suspend_enable = tps65218_pmic_set_suspend_enable, + .set_suspend_disable = tps65218_pmic_set_suspend_disable, }; static const int ls3_currents[] = { 100, 200, 500, 1000 }; @@ -247,6 +283,8 @@ static struct regulator_ops tps65218_dcdc56_pmic_ops = { .is_enabled = regulator_is_enabled_regmap, .enable = tps65218_pmic_enable, .disable = tps65218_pmic_disable, + .set_suspend_enable = tps65218_pmic_set_suspend_enable, + .set_suspend_disable = tps65218_pmic_set_suspend_disable, }; static const struct regulator_desc regulators[] = { @@ -254,42 +292,47 @@ static const struct regulator_desc regulators[] = { tps65218_dcdc12_ops, 64, TPS65218_REG_CONTROL_DCDC1, TPS65218_CONTROL_DCDC1_MASK, TPS65218_REG_ENABLE1, TPS65218_ENABLE1_DC1_EN, 0, 0, dcdc1_dcdc2_ranges, - 2, 4000, 0), + 2, 4000, 0, TPS65218_REG_SEQ3, + TPS65218_SEQ3_DC1_SEQ_MASK), TPS65218_REGULATOR("DCDC2", TPS65218_DCDC_2, REGULATOR_VOLTAGE, tps65218_dcdc12_ops, 64, TPS65218_REG_CONTROL_DCDC2, TPS65218_CONTROL_DCDC2_MASK, TPS65218_REG_ENABLE1, TPS65218_ENABLE1_DC2_EN, 0, 0, dcdc1_dcdc2_ranges, - 2, 4000, 0), + 2, 4000, 0, TPS65218_REG_SEQ3, + TPS65218_SEQ3_DC2_SEQ_MASK), TPS65218_REGULATOR("DCDC3", TPS65218_DCDC_3, REGULATOR_VOLTAGE, tps65218_ldo1_dcdc34_ops, 64, TPS65218_REG_CONTROL_DCDC3, TPS65218_CONTROL_DCDC3_MASK, TPS65218_REG_ENABLE1, TPS65218_ENABLE1_DC3_EN, 0, 0, ldo1_dcdc3_ranges, 2, - 0, 0), + 0, 0, TPS65218_REG_SEQ4, TPS65218_SEQ4_DC3_SEQ_MASK), TPS65218_REGULATOR("DCDC4", TPS65218_DCDC_4, REGULATOR_VOLTAGE, tps65218_ldo1_dcdc34_ops, 53, TPS65218_REG_CONTROL_DCDC4, TPS65218_CONTROL_DCDC4_MASK, TPS65218_REG_ENABLE1, TPS65218_ENABLE1_DC4_EN, 0, 0, dcdc4_ranges, 2, - 0, 0), + 0, 0, TPS65218_REG_SEQ4, TPS65218_SEQ4_DC4_SEQ_MASK), TPS65218_REGULATOR("DCDC5", TPS65218_DCDC_5, REGULATOR_VOLTAGE, tps65218_dcdc56_pmic_ops, 1, -1, -1, TPS65218_REG_ENABLE1, TPS65218_ENABLE1_DC5_EN, 0, 0, - NULL, 0, 0, 1000000), + NULL, 0, 0, 1000000, TPS65218_REG_SEQ5, + TPS65218_SEQ5_DC5_SEQ_MASK), TPS65218_REGULATOR("DCDC6", TPS65218_DCDC_6, REGULATOR_VOLTAGE, tps65218_dcdc56_pmic_ops, 1, -1, -1, TPS65218_REG_ENABLE1, TPS65218_ENABLE1_DC6_EN, 0, 0, - NULL, 0, 0, 1800000), + NULL, 0, 0, 1800000, TPS65218_REG_SEQ5, + TPS65218_SEQ5_DC6_SEQ_MASK), TPS65218_REGULATOR("LDO1", TPS65218_LDO_1, REGULATOR_VOLTAGE, tps65218_ldo1_dcdc34_ops, 64, TPS65218_REG_CONTROL_LDO1, TPS65218_CONTROL_LDO1_MASK, TPS65218_REG_ENABLE2, TPS65218_ENABLE2_LDO1_EN, 0, 0, ldo1_dcdc3_ranges, - 2, 0, 0), + 2, 0, 0, TPS65218_REG_SEQ6, + TPS65218_SEQ6_LDO1_SEQ_MASK), TPS65218_REGULATOR("LS3", TPS65218_LS_3, REGULATOR_CURRENT, tps65218_ls3_ops, 0, 0, 0, TPS65218_REG_ENABLE2, TPS65218_ENABLE2_LS3_EN, TPS65218_REG_CONFIG2, - TPS65218_CONFIG2_LS3ILIM_MASK, NULL, 0, 0, 0), + TPS65218_CONFIG2_LS3ILIM_MASK, NULL, 0, 0, 0, 0, 0), }; static int tps65218_regulator_probe(struct platform_device *pdev) @@ -300,7 +343,8 @@ static int tps65218_regulator_probe(struct platform_device *pdev) struct regulator_dev *rdev; const struct of_device_id *match; struct regulator_config config = { }; - int id; + int id, ret; + unsigned int val; match = of_match_device(tps65218_of_match, &pdev->dev); if (!match) @@ -327,6 +371,12 @@ static int tps65218_regulator_probe(struct platform_device *pdev) return PTR_ERR(rdev); } + ret = tps65218_reg_read(tps, regulators[id].bypass_reg, &val); + if (ret) + return ret; + + tps->info[id]->strobe = val & regulators[id].bypass_mask; + return 0; } -- cgit v1.2.1 From 3fb2ef111d6f799f3da8860c1a90ef3d9c36ea55 Mon Sep 17 00:00:00 2001 From: Tero Kristo Date: Fri, 24 Jun 2016 13:58:09 +0530 Subject: regulator: tps65218: force set power-up/down strobe to 3 for dcdc3 The reset value for this register seems broken on certain versions of tps65218 chip, so make sure the dcdc3 settings is proper. Needed for proper functionality of rtc+ddr / rtc-only modes. Signed-off-by: Tero Kristo Signed-off-by: Dave Gerlach Signed-off-by: Keerthy Signed-off-by: Mark Brown --- drivers/regulator/tps65218-regulator.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) (limited to 'drivers/regulator') diff --git a/drivers/regulator/tps65218-regulator.c b/drivers/regulator/tps65218-regulator.c index 8eca1eb4f219..d1e631d64a20 100644 --- a/drivers/regulator/tps65218-regulator.c +++ b/drivers/regulator/tps65218-regulator.c @@ -180,8 +180,12 @@ static int tps65218_pmic_set_suspend_disable(struct regulator_dev *dev) if (rid < TPS65218_DCDC_1 || rid > TPS65218_LDO_1) return -EINVAL; - if (!tps->info[rid]->strobe) - return -EINVAL; + if (!tps->info[rid]->strobe) { + if (rid == TPS65218_DCDC_3) + tps->info[rid]->strobe = 3; + else + return -EINVAL; + } return tps65218_set_bits(tps, dev->desc->bypass_reg, dev->desc->bypass_mask, -- cgit v1.2.1 From ed6d362d8dbc3494cd98cd771737ea8b1407ed61 Mon Sep 17 00:00:00 2001 From: Stefan Agner Date: Tue, 28 Jun 2016 22:53:20 -0700 Subject: regulator: rn5t618: Add RN5T567 PMIC support Extend the driver to support Ricoh RN5T567. Support the additional DCDC and slightly different voltage range of LDORTC1. Signed-off-by: Stefan Agner Reviewed-by: Marcel Ziswiler Acked-by: Mark Brown Signed-off-by: Lee Jones --- drivers/regulator/Kconfig | 5 +++-- drivers/regulator/rn5t618-regulator.c | 40 +++++++++++++++++++++++++++++++---- 2 files changed, 39 insertions(+), 6 deletions(-) (limited to 'drivers/regulator') diff --git a/drivers/regulator/Kconfig b/drivers/regulator/Kconfig index 144cbf5b3e5a..547269416950 100644 --- a/drivers/regulator/Kconfig +++ b/drivers/regulator/Kconfig @@ -636,10 +636,11 @@ config REGULATOR_RK808 outputs which can be controlled by i2c communication. config REGULATOR_RN5T618 - tristate "Ricoh RN5T618 voltage regulators" + tristate "Ricoh RN5T567/618 voltage regulators" depends on MFD_RN5T618 help - Say y here to support the regulators found on Ricoh RN5T618 PMIC. + Say y here to support the regulators found on Ricoh RN5T567 or + RN5T618 PMIC. config REGULATOR_RT5033 tristate "Richtek RT5033 Regulators" diff --git a/drivers/regulator/rn5t618-regulator.c b/drivers/regulator/rn5t618-regulator.c index b85ceb8ff911..9c930eb68cda 100644 --- a/drivers/regulator/rn5t618-regulator.c +++ b/drivers/regulator/rn5t618-regulator.c @@ -46,6 +46,23 @@ static struct regulator_ops rn5t618_reg_ops = { .vsel_mask = (vmask), \ } +static struct regulator_desc rn5t567_regulators[] = { + /* DCDC */ + REG(DCDC1, DC1CTL, BIT(0), DC1DAC, 0xff, 600000, 3500000, 12500), + REG(DCDC2, DC2CTL, BIT(0), DC2DAC, 0xff, 600000, 3500000, 12500), + REG(DCDC3, DC3CTL, BIT(0), DC3DAC, 0xff, 600000, 3500000, 12500), + REG(DCDC4, DC4CTL, BIT(0), DC4DAC, 0xff, 600000, 3500000, 12500), + /* LDO */ + REG(LDO1, LDOEN1, BIT(0), LDO1DAC, 0x7f, 900000, 3500000, 25000), + REG(LDO2, LDOEN1, BIT(1), LDO2DAC, 0x7f, 900000, 3500000, 25000), + REG(LDO3, LDOEN1, BIT(2), LDO3DAC, 0x7f, 600000, 3500000, 25000), + REG(LDO4, LDOEN1, BIT(3), LDO4DAC, 0x7f, 900000, 3500000, 25000), + REG(LDO5, LDOEN1, BIT(4), LDO5DAC, 0x7f, 900000, 3500000, 25000), + /* LDO RTC */ + REG(LDORTC1, LDOEN2, BIT(4), LDORTCDAC, 0x7f, 1200000, 3500000, 25000), + REG(LDORTC2, LDOEN2, BIT(5), LDORTC2DAC, 0x7f, 900000, 3500000, 25000), +}; + static struct regulator_desc rn5t618_regulators[] = { /* DCDC */ REG(DCDC1, DC1CTL, BIT(0), DC1DAC, 0xff, 600000, 3500000, 12500), @@ -67,18 +84,33 @@ static int rn5t618_regulator_probe(struct platform_device *pdev) struct rn5t618 *rn5t618 = dev_get_drvdata(pdev->dev.parent); struct regulator_config config = { }; struct regulator_dev *rdev; + struct regulator_desc *regulators; int i; + switch (rn5t618->variant) { + case RN5T567: + regulators = rn5t567_regulators; + break; + case RN5T618: + regulators = rn5t618_regulators; + break; + default: + return -EINVAL; + } + + config.dev = pdev->dev.parent; + config.regmap = rn5t618->regmap; + for (i = 0; i < RN5T618_REG_NUM; i++) { - config.dev = pdev->dev.parent; - config.regmap = rn5t618->regmap; + if (!regulators[i].name) + continue; rdev = devm_regulator_register(&pdev->dev, - &rn5t618_regulators[i], + ®ulators[i], &config); if (IS_ERR(rdev)) { dev_err(&pdev->dev, "failed to register %s regulator\n", - rn5t618_regulators[i].name); + regulators[i].name); return PTR_ERR(rdev); } } -- cgit v1.2.1 From 7524c1cebc0a4e2ab186fcb5f87116f3d9018ee4 Mon Sep 17 00:00:00 2001 From: James Ban Date: Wed, 29 Jun 2016 16:49:32 +0900 Subject: regulator: da9211: add descriptions for da9212/da9214 This is a patch for adding description for da9212/da9214. Signed-off-by: James Ban Signed-off-by: Mark Brown --- drivers/regulator/da9211-regulator.c | 13 +++++++++---- drivers/regulator/da9211-regulator.h | 3 ++- 2 files changed, 11 insertions(+), 5 deletions(-) (limited to 'drivers/regulator') diff --git a/drivers/regulator/da9211-regulator.c b/drivers/regulator/da9211-regulator.c index 236abf473db5..aa47280efd32 100644 --- a/drivers/regulator/da9211-regulator.c +++ b/drivers/regulator/da9211-regulator.c @@ -1,5 +1,6 @@ /* - * da9211-regulator.c - Regulator device driver for DA9211/DA9213/DA9215 + * da9211-regulator.c - Regulator device driver for DA9211/DA9212 + * /DA9213/DA9214/DA9215 * Copyright (C) 2015 Dialog Semiconductor Ltd. * * This library is free software; you can redistribute it and/or @@ -493,7 +494,9 @@ static int da9211_i2c_probe(struct i2c_client *i2c, static const struct i2c_device_id da9211_i2c_id[] = { {"da9211", DA9211}, + {"da9212", DA9212}, {"da9213", DA9213}, + {"da9214", DA9214}, {"da9215", DA9215}, {}, }; @@ -502,8 +505,10 @@ MODULE_DEVICE_TABLE(i2c, da9211_i2c_id); #ifdef CONFIG_OF static const struct of_device_id da9211_dt_ids[] = { { .compatible = "dlg,da9211", .data = &da9211_i2c_id[0] }, - { .compatible = "dlg,da9213", .data = &da9211_i2c_id[1] }, - { .compatible = "dlg,da9215", .data = &da9211_i2c_id[2] }, + { .compatible = "dlg,da9212", .data = &da9211_i2c_id[1] }, + { .compatible = "dlg,da9213", .data = &da9211_i2c_id[2] }, + { .compatible = "dlg,da9214", .data = &da9211_i2c_id[3] }, + { .compatible = "dlg,da9215", .data = &da9211_i2c_id[4] }, {}, }; MODULE_DEVICE_TABLE(of, da9211_dt_ids); @@ -521,5 +526,5 @@ static struct i2c_driver da9211_regulator_driver = { module_i2c_driver(da9211_regulator_driver); MODULE_AUTHOR("James Ban "); -MODULE_DESCRIPTION("Regulator device driver for Dialog DA9211/DA9213/DA9215"); +MODULE_DESCRIPTION("DA9211/DA9212/DA9213/DA9214/DA9215 regulator driver"); MODULE_LICENSE("GPL"); diff --git a/drivers/regulator/da9211-regulator.h b/drivers/regulator/da9211-regulator.h index d6ad96fc64d3..b841bbf330cc 100644 --- a/drivers/regulator/da9211-regulator.h +++ b/drivers/regulator/da9211-regulator.h @@ -1,5 +1,6 @@ /* - * da9211-regulator.h - Regulator definitions for DA9211/DA9213/DA9215 + * da9211-regulator.h - Regulator definitions for DA9211/DA9212 + * /DA9213/DA9214/DA9215 * Copyright (C) 2015 Dialog Semiconductor Ltd. * * This program is free software; you can redistribute it and/or -- cgit v1.2.1 From 91ff811f32763ea3135e832f7c1aeafc85ae1c98 Mon Sep 17 00:00:00 2001 From: Venkat Reddy Talla Date: Wed, 29 Jun 2016 15:31:27 +0530 Subject: regulator: max77620: check for valid regulator info SD4 regulator is not registered with regulator core framework in probe as there is no support in MAX77620 PMIC, removing SD4 entry from MAX77620 regulator information list and checking for valid regulator information data before configuring FPS source and FPS power up/down period to avoid NULL pointer exception if regulator not registered with core. Signed-off-by: Venkat Reddy Talla Signed-off-by: Mark Brown --- drivers/regulator/max77620-regulator.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) (limited to 'drivers/regulator') diff --git a/drivers/regulator/max77620-regulator.c b/drivers/regulator/max77620-regulator.c index 321e804aeab0..a1b49a6d538f 100644 --- a/drivers/regulator/max77620-regulator.c +++ b/drivers/regulator/max77620-regulator.c @@ -123,6 +123,9 @@ static int max77620_regulator_set_fps_src(struct max77620_regulator *pmic, unsigned int val; int ret; + if (!rinfo) + return 0; + switch (fps_src) { case MAX77620_FPS_SRC_0: case MAX77620_FPS_SRC_1: @@ -171,6 +174,9 @@ static int max77620_regulator_set_fps_slots(struct max77620_regulator *pmic, int pd = rpdata->active_fps_pd_slot; int ret = 0; + if (!rinfo) + return 0; + if (is_suspend) { pu = rpdata->suspend_fps_pu_slot; pd = rpdata->suspend_fps_pd_slot; @@ -680,7 +686,6 @@ static struct max77620_regulator_info max77620_regs_info[MAX77620_NUM_REGS] = { RAIL_SD(SD1, sd1, "in-sd1", SD1, 600000, 1550000, 12500, 0x22, SD1), RAIL_SD(SD2, sd2, "in-sd2", SDX, 600000, 3787500, 12500, 0xFF, NONE), RAIL_SD(SD3, sd3, "in-sd3", SDX, 600000, 3787500, 12500, 0xFF, NONE), - RAIL_SD(SD4, sd4, "in-sd4", SDX, 600000, 3787500, 12500, 0xFF, NONE), RAIL_LDO(LDO0, ldo0, "in-ldo0-1", N, 800000, 2375000, 25000), RAIL_LDO(LDO1, ldo1, "in-ldo0-1", N, 800000, 2375000, 25000), -- cgit v1.2.1 From c2588393e6315ab68207323d37d2a73713d6bc81 Mon Sep 17 00:00:00 2001 From: Douglas Anderson Date: Wed, 6 Jul 2016 11:42:01 -0700 Subject: regulator: pwm: Fix regulator ramp delay for continuous mode The original commit adding support for continuous voltage mode didn't handle the regulator ramp delay properly. It treated the delay as a fixed delay in uS despite the property being defined as uV / uS. Let's adjust it. Luckily there appear to be no users of this ramp delay for PWM regulators (as per grepping through device trees in linuxnext). Note also that the upper bound of usleep_range probably shouldn't be a full 1 ms longer than the lower bound since I've seen plenty of hardware with a ramp rate of ~5000 uS / uV and for small jumps the total delays are in the tens of uS. 1000 is way too much. We'll try to be dynamic and use 10%. NOTE: This commit doesn't add support for regulator-enable-ramp-delay. That could be done in a future patch when someone has a user of that featre. Though this patch is shows as "fixing" a bug, there are no actual known users of continuous mode PWM regulator w/ ramp delay in mainline and so this likely won't have any effect on anyone unless they are working out-of-tree with private patches. For anyone in this state, it is highly encouraged to also pick Boris Brezillon's WIP patches to get yourself a reliable and glitch-free regulator. Fixes: 4773be185a0f ("regulator: pwm-regulator: Add support for continuous-voltage") Signed-off-by: Douglas Anderson Acked-by: Laxman Dewangan Signed-off-by: Mark Brown --- drivers/regulator/pwm-regulator.c | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) (limited to 'drivers/regulator') diff --git a/drivers/regulator/pwm-regulator.c b/drivers/regulator/pwm-regulator.c index 90f8b7fd0437..666bc3bb52ef 100644 --- a/drivers/regulator/pwm-regulator.c +++ b/drivers/regulator/pwm-regulator.c @@ -145,6 +145,7 @@ static int pwm_regulator_set_voltage(struct regulator_dev *rdev, unsigned int duty_pulse; u64 req_period; u32 rem; + int old_uV = pwm_regulator_get_voltage(rdev); int ret; pwm_get_args(drvdata->pwm, &pargs); @@ -174,8 +175,12 @@ static int pwm_regulator_set_voltage(struct regulator_dev *rdev, drvdata->volt_uV = min_uV; - /* Delay required by PWM regulator to settle to the new voltage */ - usleep_range(ramp_delay, ramp_delay + 1000); + if ((ramp_delay == 0) || !pwm_regulator_is_enabled(rdev)) + return 0; + + /* Ramp delay is in uV/uS. Adjust to uS and delay */ + ramp_delay = DIV_ROUND_UP(abs(min_uV - old_uV), ramp_delay); + usleep_range(ramp_delay, ramp_delay + DIV_ROUND_UP(ramp_delay, 10)); return 0; } -- cgit v1.2.1 From fd4f99c4c3ce8ccd9b8ea751afc614a7624ecef2 Mon Sep 17 00:00:00 2001 From: Boris Brezillon Date: Tue, 14 Jun 2016 11:13:17 +0200 Subject: regulator: pwm: Adjust PWM config at probe time The PWM attached to a PWM regulator device might have been previously configured by the bootloader. Make sure the bootloader and linux config are in sync, and adjust the PWM config if that's not the case. Signed-off-by: Boris Brezillon Acked-by: Mark Brown Acked-by: Brian Norris Tested-by: Brian Norris Tested-by: Heiko Stuebner Signed-off-by: Thierry Reding --- drivers/regulator/pwm-regulator.c | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) (limited to 'drivers/regulator') diff --git a/drivers/regulator/pwm-regulator.c b/drivers/regulator/pwm-regulator.c index 666bc3bb52ef..cb2f22c02469 100644 --- a/drivers/regulator/pwm-regulator.c +++ b/drivers/regulator/pwm-regulator.c @@ -316,11 +316,9 @@ static int pwm_regulator_probe(struct platform_device *pdev) return ret; } - /* - * FIXME: pwm_apply_args() should be removed when switching to the - * atomic PWM API. - */ - pwm_apply_args(drvdata->pwm); + ret = pwm_adjust_config(drvdata->pwm); + if (ret) + return ret; regulator = devm_regulator_register(&pdev->dev, &drvdata->desc, &config); -- cgit v1.2.1 From 3f4eb39be9b1402ea01a5c67441d0b0bcb74b4b2 Mon Sep 17 00:00:00 2001 From: Boris Brezillon Date: Tue, 14 Jun 2016 11:13:18 +0200 Subject: regulator: pwm: Switch to the atomic PWM API Use the atomic API wherever appropriate and get rid of pwm_apply_args() call (the reference period and polarity are now explicitly set when calling pwm_apply_state()). We also make use of the pwm_set_relative_duty_cycle() helper to ease relative to absolute duty_cycle conversion. Note that changes introduced by commit fd786fb0276a ("regulator: pwm: Try to avoid voltage error in duty cycle calculation") are no longer needed because pwm_set_relative_duty_cycle() takes care of all rounding approximation for us. Signed-off-by: Boris Brezillon Reviewed-by: Brian Norris Tested-by: Brian Norris Acked-by: Laxman Dewangan Tested-by: Heiko Stuebner Acked-by: Mark Brown Signed-off-by: Thierry Reding --- drivers/regulator/pwm-regulator.c | 38 ++++++++++---------------------------- 1 file changed, 10 insertions(+), 28 deletions(-) (limited to 'drivers/regulator') diff --git a/drivers/regulator/pwm-regulator.c b/drivers/regulator/pwm-regulator.c index cb2f22c02469..7920411057af 100644 --- a/drivers/regulator/pwm-regulator.c +++ b/drivers/regulator/pwm-regulator.c @@ -63,16 +63,14 @@ static int pwm_regulator_set_voltage_sel(struct regulator_dev *rdev, unsigned selector) { struct pwm_regulator_data *drvdata = rdev_get_drvdata(rdev); - struct pwm_args pargs; - int dutycycle; + struct pwm_state pstate; int ret; - pwm_get_args(drvdata->pwm, &pargs); + pwm_init_state(drvdata->pwm, &pstate); + pwm_set_relative_duty_cycle(&pstate, + drvdata->duty_cycle_table[selector].dutycycle, 100); - dutycycle = (pargs.period * - drvdata->duty_cycle_table[selector].dutycycle) / 100; - - ret = pwm_config(drvdata->pwm, dutycycle, pargs.period); + ret = pwm_apply_state(drvdata->pwm, &pstate); if (ret) { dev_err(&rdev->dev, "Failed to configure PWM: %d\n", ret); return ret; @@ -139,35 +137,19 @@ static int pwm_regulator_set_voltage(struct regulator_dev *rdev, { struct pwm_regulator_data *drvdata = rdev_get_drvdata(rdev); unsigned int ramp_delay = rdev->constraints->ramp_delay; - struct pwm_args pargs; unsigned int req_diff = min_uV - rdev->constraints->min_uV; + struct pwm_state pstate; unsigned int diff; - unsigned int duty_pulse; - u64 req_period; - u32 rem; int old_uV = pwm_regulator_get_voltage(rdev); int ret; - pwm_get_args(drvdata->pwm, &pargs); + pwm_init_state(drvdata->pwm, &pstate); diff = rdev->constraints->max_uV - rdev->constraints->min_uV; - /* First try to find out if we get the iduty cycle time which is - * factor of PWM period time. If (request_diff_to_min * pwm_period) - * is perfect divided by voltage_range_diff then it is possible to - * get duty cycle time which is factor of PWM period. This will help - * to get output voltage nearer to requested value as there is no - * calculation loss. - */ - req_period = req_diff * pargs.period; - div_u64_rem(req_period, diff, &rem); - if (!rem) { - do_div(req_period, diff); - duty_pulse = (unsigned int)req_period; - } else { - duty_pulse = (pargs.period / 100) * ((req_diff * 100) / diff); - } + /* We pass diff as the scale to get a uV precision. */ + pwm_set_relative_duty_cycle(&pstate, req_diff, diff); - ret = pwm_config(drvdata->pwm, duty_pulse, pargs.period); + ret = pwm_apply_state(drvdata->pwm, &pstate); if (ret) { dev_err(&rdev->dev, "Failed to configure PWM: %d\n", ret); return ret; -- cgit v1.2.1 From 87248991a1de28e73dc30057e82d831bc11cdd44 Mon Sep 17 00:00:00 2001 From: Boris Brezillon Date: Tue, 14 Jun 2016 11:13:19 +0200 Subject: regulator: pwm: Properly initialize the ->state field The ->state field is currently initialized to 0, thus referencing the voltage selector at index 0, which might not reflect the current voltage value. If possible, retrieve the current voltage selector from the PWM state, else return -EINVAL. Signed-off-by: Boris Brezillon Tested-by: Brian Norris Tested-by: Heiko Stuebner Acked-by: Mark Brown Signed-off-by: Thierry Reding --- drivers/regulator/pwm-regulator.c | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) (limited to 'drivers/regulator') diff --git a/drivers/regulator/pwm-regulator.c b/drivers/regulator/pwm-regulator.c index 7920411057af..7d26d3b0eed6 100644 --- a/drivers/regulator/pwm-regulator.c +++ b/drivers/regulator/pwm-regulator.c @@ -52,10 +52,31 @@ struct pwm_voltages { /** * Voltage table call-backs */ +static void pwm_regulator_init_state(struct regulator_dev *rdev) +{ + struct pwm_regulator_data *drvdata = rdev_get_drvdata(rdev); + struct pwm_state pwm_state; + unsigned int dutycycle; + int i; + + pwm_get_state(drvdata->pwm, &pwm_state); + dutycycle = pwm_get_relative_duty_cycle(&pwm_state, 100); + + for (i = 0; i < rdev->desc->n_voltages; i++) { + if (dutycycle == drvdata->duty_cycle_table[i].dutycycle) { + drvdata->state = i; + return; + } + } +} + static int pwm_regulator_get_voltage_sel(struct regulator_dev *rdev) { struct pwm_regulator_data *drvdata = rdev_get_drvdata(rdev); + if (drvdata->state < 0) + pwm_regulator_init_state(rdev); + return drvdata->state; } @@ -221,6 +242,7 @@ static int pwm_regulator_init_table(struct platform_device *pdev, return ret; } + drvdata->state = -EINVAL; drvdata->duty_cycle_table = duty_cycle_table; memcpy(&drvdata->ops, &pwm_regulator_voltage_table_ops, sizeof(drvdata->ops)); -- cgit v1.2.1 From d9070fdbe40a04b61262bac0f7ff0c7c29a68015 Mon Sep 17 00:00:00 2001 From: Boris Brezillon Date: Tue, 14 Jun 2016 11:13:20 +0200 Subject: regulator: pwm: Retrieve correct voltage The continuous PWM voltage regulator is caching the voltage value in the ->volt_uV field. While most of the time this value should reflect the real voltage, sometime it can be sightly different if the PWM device rounded the set_duty_cycle request. Moreover, this value is not valid until someone has modified the regulator output. Remove the ->volt_uV field and always rely on the PWM state to calculate the regulator output. Signed-off-by: Boris Brezillon Reviewed-by: Brian Norris Tested-by: Brian Norris Tested-by: Heiko Stuebner Acked-by: Mark Brown Signed-off-by: Thierry Reding --- drivers/regulator/pwm-regulator.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) (limited to 'drivers/regulator') diff --git a/drivers/regulator/pwm-regulator.c b/drivers/regulator/pwm-regulator.c index 7d26d3b0eed6..ae0bebbfda9d 100644 --- a/drivers/regulator/pwm-regulator.c +++ b/drivers/regulator/pwm-regulator.c @@ -37,9 +37,6 @@ struct pwm_regulator_data { int state; - /* Continuous voltage */ - int volt_uV; - /* Enable GPIO */ struct gpio_desc *enb_gpio; }; @@ -148,8 +145,13 @@ static int pwm_regulator_is_enabled(struct regulator_dev *dev) static int pwm_regulator_get_voltage(struct regulator_dev *rdev) { struct pwm_regulator_data *drvdata = rdev_get_drvdata(rdev); + int min_uV = rdev->constraints->min_uV; + int diff = rdev->constraints->max_uV - min_uV; + struct pwm_state pstate; - return drvdata->volt_uV; + pwm_get_state(drvdata->pwm, &pstate); + + return min_uV + pwm_get_relative_duty_cycle(&pstate, diff); } static int pwm_regulator_set_voltage(struct regulator_dev *rdev, @@ -176,8 +178,6 @@ static int pwm_regulator_set_voltage(struct regulator_dev *rdev, return ret; } - drvdata->volt_uV = min_uV; - if ((ramp_delay == 0) || !pwm_regulator_is_enabled(rdev)) return 0; -- cgit v1.2.1 From 04c16b84e49a6d609c88f4f5523237ece3612b74 Mon Sep 17 00:00:00 2001 From: Alim Akhtar Date: Tue, 12 Jul 2016 11:26:43 +0530 Subject: regulator: s2mps11: Fix the voltage linear range for s2mps15 This patch fixes some of the LDOs and BUCKs voltage range as per user manual of s2mps15 (REV0.4). Fixes: 51af20675800 ("regulator: s2mps11: Add support for S2MPS15 regulators") Signed-off-by: Alim Akhtar Signed-off-by: Mark Brown Cc: --- drivers/regulator/s2mps11.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'drivers/regulator') diff --git a/drivers/regulator/s2mps11.c b/drivers/regulator/s2mps11.c index 02fb6b4ea820..d838e77dd947 100644 --- a/drivers/regulator/s2mps11.c +++ b/drivers/regulator/s2mps11.c @@ -750,7 +750,7 @@ static const struct regulator_linear_range s2mps15_ldo_voltage_ranges3[] = { /* voltage range for s2mps15 LDO 7, 8, 9 and 10 */ static const struct regulator_linear_range s2mps15_ldo_voltage_ranges4[] = { - REGULATOR_LINEAR_RANGE(700000, 0xc, 0x18, 25000), + REGULATOR_LINEAR_RANGE(700000, 0x10, 0x20, 25000), }; /* voltage range for s2mps15 LDO 1 */ @@ -760,12 +760,12 @@ static const struct regulator_linear_range s2mps15_ldo_voltage_ranges5[] = { /* voltage range for s2mps15 BUCK 1, 2, 3, 4, 5, 6 and 7 */ static const struct regulator_linear_range s2mps15_buck_voltage_ranges1[] = { - REGULATOR_LINEAR_RANGE(500000, 0x20, 0xb0, 6250), + REGULATOR_LINEAR_RANGE(500000, 0x20, 0xc0, 6250), }; /* voltage range for s2mps15 BUCK 8, 9 and 10 */ static const struct regulator_linear_range s2mps15_buck_voltage_ranges2[] = { - REGULATOR_LINEAR_RANGE(1000000, 0x20, 0xc0, 12500), + REGULATOR_LINEAR_RANGE(1000000, 0x20, 0x78, 12500), }; static const struct regulator_desc s2mps15_regulators[] = { -- cgit v1.2.1 From b7a8524cfae0b3bde80be38c171e4ecac8ba527e Mon Sep 17 00:00:00 2001 From: Stephen Boyd Date: Mon, 11 Jul 2016 14:50:09 -0700 Subject: regulator: qcom_smd: Avoid overlapping linear voltage ranges The pm8x41_hfsmps ranges overlap. The first range is from 375000 to 1562500: 375000 + (95 * 12500) == 1562500 and the second range starts at 1550000. Interestingly, the second range ends at the correct value when it's set to be the appropriate start value, 1575000: 1575000 + ((158 - 96) * 25000) == 3125000 Signed-off-by: Stephen Boyd Reviewed-by: Andy Gross Signed-off-by: Mark Brown --- drivers/regulator/qcom_smd-regulator.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/regulator') diff --git a/drivers/regulator/qcom_smd-regulator.c b/drivers/regulator/qcom_smd-regulator.c index 6c7fe4778793..5022fa8d10c6 100644 --- a/drivers/regulator/qcom_smd-regulator.c +++ b/drivers/regulator/qcom_smd-regulator.c @@ -211,7 +211,7 @@ static const struct regulator_desc pma8084_switch = { static const struct regulator_desc pm8x41_hfsmps = { .linear_ranges = (struct regulator_linear_range[]) { REGULATOR_LINEAR_RANGE( 375000, 0, 95, 12500), - REGULATOR_LINEAR_RANGE(1550000, 96, 158, 25000), + REGULATOR_LINEAR_RANGE(1575000, 96, 158, 25000), }, .n_linear_ranges = 2, .n_voltages = 159, -- cgit v1.2.1 From 79886be09751c543155608036134b9948288bfc3 Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Fri, 18 Mar 2016 16:21:36 +0100 Subject: ARM: ux500: move ab8500_regulator_plat_data into driver There is only one instance of ab8500_regulator_platform_data, and it's safe to assume we won't ever merge another one, so it's rather pointless to pass it through multiple levels of platform data pointers. This moves the structure and everything referenced by it into the driver that uses it. Signed-off-by: Arnd Bergmann Acked-by: Mark Brown Signed-off-by: Linus Walleij --- drivers/regulator/ab8500-ext.c | 465 +++++++++++++++++++++++++++++++++++++++-- 1 file changed, 451 insertions(+), 14 deletions(-) (limited to 'drivers/regulator') diff --git a/drivers/regulator/ab8500-ext.c b/drivers/regulator/ab8500-ext.c index 84c1ee39ddae..2ca00045eb99 100644 --- a/drivers/regulator/ab8500-ext.c +++ b/drivers/regulator/ab8500-ext.c @@ -25,6 +25,456 @@ #include #include +static struct regulator_consumer_supply ab8500_vaux1_consumers[] = { + /* Main display, u8500 R3 uib */ + REGULATOR_SUPPLY("vddi", "mcde_disp_sony_acx424akp.0"), + /* Main display, u8500 uib and ST uib */ + REGULATOR_SUPPLY("vdd1", "samsung_s6d16d0.0"), + /* Secondary display, ST uib */ + REGULATOR_SUPPLY("vdd1", "samsung_s6d16d0.1"), + /* SFH7741 proximity sensor */ + REGULATOR_SUPPLY("vcc", "gpio-keys.0"), + /* BH1780GLS ambient light sensor */ + REGULATOR_SUPPLY("vcc", "2-0029"), + /* lsm303dlh accelerometer */ + REGULATOR_SUPPLY("vdd", "2-0018"), + /* lsm303dlhc accelerometer */ + REGULATOR_SUPPLY("vdd", "2-0019"), + /* lsm303dlh magnetometer */ + REGULATOR_SUPPLY("vdd", "2-001e"), + /* Rohm BU21013 Touchscreen devices */ + REGULATOR_SUPPLY("avdd", "3-005c"), + REGULATOR_SUPPLY("avdd", "3-005d"), + /* Synaptics RMI4 Touchscreen device */ + REGULATOR_SUPPLY("vdd", "3-004b"), + /* L3G4200D Gyroscope device */ + REGULATOR_SUPPLY("vdd", "2-0068"), + /* Ambient light sensor device */ + REGULATOR_SUPPLY("vdd", "3-0029"), + /* Pressure sensor device */ + REGULATOR_SUPPLY("vdd", "2-005c"), + /* Cypress TrueTouch Touchscreen device */ + REGULATOR_SUPPLY("vcpin", "spi8.0"), + /* Camera device */ + REGULATOR_SUPPLY("vaux12v5", "mmio_camera"), +}; + +static struct regulator_consumer_supply ab8500_vaux2_consumers[] = { + /* On-board eMMC power */ + REGULATOR_SUPPLY("vmmc", "sdi4"), + /* AB8500 audio codec */ + REGULATOR_SUPPLY("vcc-N2158", "ab8500-codec.0"), + /* AB8500 accessory detect 1 */ + REGULATOR_SUPPLY("vcc-N2158", "ab8500-acc-det.0"), + /* AB8500 Tv-out device */ + REGULATOR_SUPPLY("vcc-N2158", "mcde_tv_ab8500.4"), + /* AV8100 HDMI device */ + REGULATOR_SUPPLY("vcc-N2158", "av8100_hdmi.3"), +}; + +static struct regulator_consumer_supply ab8500_vaux3_consumers[] = { + REGULATOR_SUPPLY("v-SD-STM", "stm"), + /* External MMC slot power */ + REGULATOR_SUPPLY("vmmc", "sdi0"), +}; + +static struct regulator_consumer_supply ab8500_vtvout_consumers[] = { + /* TV-out DENC supply */ + REGULATOR_SUPPLY("vtvout", "ab8500-denc.0"), + /* Internal general-purpose ADC */ + REGULATOR_SUPPLY("vddadc", "ab8500-gpadc.0"), + /* ADC for charger */ + REGULATOR_SUPPLY("vddadc", "ab8500-charger.0"), + /* AB8500 Tv-out device */ + REGULATOR_SUPPLY("vtvout", "mcde_tv_ab8500.4"), +}; + +static struct regulator_consumer_supply ab8500_vaud_consumers[] = { + /* AB8500 audio-codec main supply */ + REGULATOR_SUPPLY("vaud", "ab8500-codec.0"), +}; + +static struct regulator_consumer_supply ab8500_vamic1_consumers[] = { + /* AB8500 audio-codec Mic1 supply */ + REGULATOR_SUPPLY("vamic1", "ab8500-codec.0"), +}; + +static struct regulator_consumer_supply ab8500_vamic2_consumers[] = { + /* AB8500 audio-codec Mic2 supply */ + REGULATOR_SUPPLY("vamic2", "ab8500-codec.0"), +}; + +static struct regulator_consumer_supply ab8500_vdmic_consumers[] = { + /* AB8500 audio-codec DMic supply */ + REGULATOR_SUPPLY("vdmic", "ab8500-codec.0"), +}; + +static struct regulator_consumer_supply ab8500_vintcore_consumers[] = { + /* SoC core supply, no device */ + REGULATOR_SUPPLY("v-intcore", NULL), + /* USB Transceiver */ + REGULATOR_SUPPLY("vddulpivio18", "ab8500-usb.0"), + /* Handled by abx500 clk driver */ + REGULATOR_SUPPLY("v-intcore", "abx500-clk.0"), +}; + +static struct regulator_consumer_supply ab8500_vana_consumers[] = { + /* DB8500 DSI */ + REGULATOR_SUPPLY("vdddsi1v2", "mcde"), + REGULATOR_SUPPLY("vdddsi1v2", "b2r2_core"), + REGULATOR_SUPPLY("vdddsi1v2", "b2r2_1_core"), + REGULATOR_SUPPLY("vdddsi1v2", "dsilink.0"), + REGULATOR_SUPPLY("vdddsi1v2", "dsilink.1"), + REGULATOR_SUPPLY("vdddsi1v2", "dsilink.2"), + /* DB8500 CSI */ + REGULATOR_SUPPLY("vddcsi1v2", "mmio_camera"), +}; + +/* ab8500 regulator register initialization */ +static struct ab8500_regulator_reg_init ab8500_reg_init[] = { + /* + * VanaRequestCtrl = HP/LP depending on VxRequest + * VextSupply1RequestCtrl = HP/LP depending on VxRequest + */ + INIT_REGULATOR_REGISTER(AB8500_REGUREQUESTCTRL2, 0xf0, 0x00), + /* + * VextSupply2RequestCtrl = HP/LP depending on VxRequest + * VextSupply3RequestCtrl = HP/LP depending on VxRequest + * Vaux1RequestCtrl = HP/LP depending on VxRequest + * Vaux2RequestCtrl = HP/LP depending on VxRequest + */ + INIT_REGULATOR_REGISTER(AB8500_REGUREQUESTCTRL3, 0xff, 0x00), + /* + * Vaux3RequestCtrl = HP/LP depending on VxRequest + * SwHPReq = Control through SWValid disabled + */ + INIT_REGULATOR_REGISTER(AB8500_REGUREQUESTCTRL4, 0x07, 0x00), + /* + * VanaSysClkReq1HPValid = disabled + * Vaux1SysClkReq1HPValid = disabled + * Vaux2SysClkReq1HPValid = disabled + * Vaux3SysClkReq1HPValid = disabled + */ + INIT_REGULATOR_REGISTER(AB8500_REGUSYSCLKREQ1HPVALID1, 0xe8, 0x00), + /* + * VextSupply1SysClkReq1HPValid = disabled + * VextSupply2SysClkReq1HPValid = disabled + * VextSupply3SysClkReq1HPValid = SysClkReq1 controlled + */ + INIT_REGULATOR_REGISTER(AB8500_REGUSYSCLKREQ1HPVALID2, 0x70, 0x40), + /* + * VanaHwHPReq1Valid = disabled + * Vaux1HwHPreq1Valid = disabled + * Vaux2HwHPReq1Valid = disabled + * Vaux3HwHPReqValid = disabled + */ + INIT_REGULATOR_REGISTER(AB8500_REGUHWHPREQ1VALID1, 0xe8, 0x00), + /* + * VextSupply1HwHPReq1Valid = disabled + * VextSupply2HwHPReq1Valid = disabled + * VextSupply3HwHPReq1Valid = disabled + */ + INIT_REGULATOR_REGISTER(AB8500_REGUHWHPREQ1VALID2, 0x07, 0x00), + /* + * VanaHwHPReq2Valid = disabled + * Vaux1HwHPReq2Valid = disabled + * Vaux2HwHPReq2Valid = disabled + * Vaux3HwHPReq2Valid = disabled + */ + INIT_REGULATOR_REGISTER(AB8500_REGUHWHPREQ2VALID1, 0xe8, 0x00), + /* + * VextSupply1HwHPReq2Valid = disabled + * VextSupply2HwHPReq2Valid = disabled + * VextSupply3HwHPReq2Valid = HWReq2 controlled + */ + INIT_REGULATOR_REGISTER(AB8500_REGUHWHPREQ2VALID2, 0x07, 0x04), + /* + * VanaSwHPReqValid = disabled + * Vaux1SwHPReqValid = disabled + */ + INIT_REGULATOR_REGISTER(AB8500_REGUSWHPREQVALID1, 0xa0, 0x00), + /* + * Vaux2SwHPReqValid = disabled + * Vaux3SwHPReqValid = disabled + * VextSupply1SwHPReqValid = disabled + * VextSupply2SwHPReqValid = disabled + * VextSupply3SwHPReqValid = disabled + */ + INIT_REGULATOR_REGISTER(AB8500_REGUSWHPREQVALID2, 0x1f, 0x00), + /* + * SysClkReq2Valid1 = SysClkReq2 controlled + * SysClkReq3Valid1 = disabled + * SysClkReq4Valid1 = SysClkReq4 controlled + * SysClkReq5Valid1 = disabled + * SysClkReq6Valid1 = SysClkReq6 controlled + * SysClkReq7Valid1 = disabled + * SysClkReq8Valid1 = disabled + */ + INIT_REGULATOR_REGISTER(AB8500_REGUSYSCLKREQVALID1, 0xfe, 0x2a), + /* + * SysClkReq2Valid2 = disabled + * SysClkReq3Valid2 = disabled + * SysClkReq4Valid2 = disabled + * SysClkReq5Valid2 = disabled + * SysClkReq6Valid2 = SysClkReq6 controlled + * SysClkReq7Valid2 = disabled + * SysClkReq8Valid2 = disabled + */ + INIT_REGULATOR_REGISTER(AB8500_REGUSYSCLKREQVALID2, 0xfe, 0x20), + /* + * VTVoutEna = disabled + * Vintcore12Ena = disabled + * Vintcore12Sel = 1.25 V + * Vintcore12LP = inactive (HP) + * VTVoutLP = inactive (HP) + */ + INIT_REGULATOR_REGISTER(AB8500_REGUMISC1, 0xfe, 0x10), + /* + * VaudioEna = disabled + * VdmicEna = disabled + * Vamic1Ena = disabled + * Vamic2Ena = disabled + */ + INIT_REGULATOR_REGISTER(AB8500_VAUDIOSUPPLY, 0x1e, 0x00), + /* + * Vamic1_dzout = high-Z when Vamic1 is disabled + * Vamic2_dzout = high-Z when Vamic2 is disabled + */ + INIT_REGULATOR_REGISTER(AB8500_REGUCTRL1VAMIC, 0x03, 0x00), + /* + * VPll = Hw controlled (NOTE! PRCMU bits) + * VanaRegu = force off + */ + INIT_REGULATOR_REGISTER(AB8500_VPLLVANAREGU, 0x0f, 0x02), + /* + * VrefDDREna = disabled + * VrefDDRSleepMode = inactive (no pulldown) + */ + INIT_REGULATOR_REGISTER(AB8500_VREFDDR, 0x03, 0x00), + /* + * VextSupply1Regu = force LP + * VextSupply2Regu = force OFF + * VextSupply3Regu = force HP (-> STBB2=LP and TPS=LP) + * ExtSupply2Bypass = ExtSupply12LPn ball is 0 when Ena is 0 + * ExtSupply3Bypass = ExtSupply3LPn ball is 0 when Ena is 0 + */ + INIT_REGULATOR_REGISTER(AB8500_EXTSUPPLYREGU, 0xff, 0x13), + /* + * Vaux1Regu = force HP + * Vaux2Regu = force off + */ + INIT_REGULATOR_REGISTER(AB8500_VAUX12REGU, 0x0f, 0x01), + /* + * Vaux3Regu = force off + */ + INIT_REGULATOR_REGISTER(AB8500_VRF1VAUX3REGU, 0x03, 0x00), + /* + * Vaux1Sel = 2.8 V + */ + INIT_REGULATOR_REGISTER(AB8500_VAUX1SEL, 0x0f, 0x0C), + /* + * Vaux2Sel = 2.9 V + */ + INIT_REGULATOR_REGISTER(AB8500_VAUX2SEL, 0x0f, 0x0d), + /* + * Vaux3Sel = 2.91 V + */ + INIT_REGULATOR_REGISTER(AB8500_VRF1VAUX3SEL, 0x07, 0x07), + /* + * VextSupply12LP = disabled (no LP) + */ + INIT_REGULATOR_REGISTER(AB8500_REGUCTRL2SPARE, 0x01, 0x00), + /* + * Vaux1Disch = short discharge time + * Vaux2Disch = short discharge time + * Vaux3Disch = short discharge time + * Vintcore12Disch = short discharge time + * VTVoutDisch = short discharge time + * VaudioDisch = short discharge time + */ + INIT_REGULATOR_REGISTER(AB8500_REGUCTRLDISCH, 0xfc, 0x00), + /* + * VanaDisch = short discharge time + * VdmicPullDownEna = pulldown disabled when Vdmic is disabled + * VdmicDisch = short discharge time + */ + INIT_REGULATOR_REGISTER(AB8500_REGUCTRLDISCH2, 0x16, 0x00), +}; + +/* AB8500 regulators */ +static struct regulator_init_data ab8500_regulators[AB8500_NUM_REGULATORS] = { + /* supplies to the display/camera */ + [AB8500_LDO_AUX1] = { + .supply_regulator = "ab8500-ext-supply3", + .constraints = { + .name = "V-DISPLAY", + .min_uV = 2800000, + .max_uV = 3300000, + .valid_ops_mask = REGULATOR_CHANGE_VOLTAGE | + REGULATOR_CHANGE_STATUS, + .boot_on = 1, /* display is on at boot */ + }, + .num_consumer_supplies = ARRAY_SIZE(ab8500_vaux1_consumers), + .consumer_supplies = ab8500_vaux1_consumers, + }, + /* supplies to the on-board eMMC */ + [AB8500_LDO_AUX2] = { + .supply_regulator = "ab8500-ext-supply3", + .constraints = { + .name = "V-eMMC1", + .min_uV = 1100000, + .max_uV = 3300000, + .valid_ops_mask = REGULATOR_CHANGE_VOLTAGE | + REGULATOR_CHANGE_STATUS | + REGULATOR_CHANGE_MODE, + .valid_modes_mask = REGULATOR_MODE_NORMAL | + REGULATOR_MODE_IDLE, + }, + .num_consumer_supplies = ARRAY_SIZE(ab8500_vaux2_consumers), + .consumer_supplies = ab8500_vaux2_consumers, + }, + /* supply for VAUX3, supplies to SDcard slots */ + [AB8500_LDO_AUX3] = { + .supply_regulator = "ab8500-ext-supply3", + .constraints = { + .name = "V-MMC-SD", + .min_uV = 1100000, + .max_uV = 3300000, + .valid_ops_mask = REGULATOR_CHANGE_VOLTAGE | + REGULATOR_CHANGE_STATUS | + REGULATOR_CHANGE_MODE, + .valid_modes_mask = REGULATOR_MODE_NORMAL | + REGULATOR_MODE_IDLE, + }, + .num_consumer_supplies = ARRAY_SIZE(ab8500_vaux3_consumers), + .consumer_supplies = ab8500_vaux3_consumers, + }, + /* supply for tvout, gpadc, TVOUT LDO */ + [AB8500_LDO_TVOUT] = { + .constraints = { + .name = "V-TVOUT", + .valid_ops_mask = REGULATOR_CHANGE_STATUS, + }, + .num_consumer_supplies = ARRAY_SIZE(ab8500_vtvout_consumers), + .consumer_supplies = ab8500_vtvout_consumers, + }, + /* supply for ab8500-vaudio, VAUDIO LDO */ + [AB8500_LDO_AUDIO] = { + .constraints = { + .name = "V-AUD", + .valid_ops_mask = REGULATOR_CHANGE_STATUS, + }, + .num_consumer_supplies = ARRAY_SIZE(ab8500_vaud_consumers), + .consumer_supplies = ab8500_vaud_consumers, + }, + /* supply for v-anamic1 VAMic1-LDO */ + [AB8500_LDO_ANAMIC1] = { + .constraints = { + .name = "V-AMIC1", + .valid_ops_mask = REGULATOR_CHANGE_STATUS, + }, + .num_consumer_supplies = ARRAY_SIZE(ab8500_vamic1_consumers), + .consumer_supplies = ab8500_vamic1_consumers, + }, + /* supply for v-amic2, VAMIC2 LDO, reuse constants for AMIC1 */ + [AB8500_LDO_ANAMIC2] = { + .constraints = { + .name = "V-AMIC2", + .valid_ops_mask = REGULATOR_CHANGE_STATUS, + }, + .num_consumer_supplies = ARRAY_SIZE(ab8500_vamic2_consumers), + .consumer_supplies = ab8500_vamic2_consumers, + }, + /* supply for v-dmic, VDMIC LDO */ + [AB8500_LDO_DMIC] = { + .constraints = { + .name = "V-DMIC", + .valid_ops_mask = REGULATOR_CHANGE_STATUS, + }, + .num_consumer_supplies = ARRAY_SIZE(ab8500_vdmic_consumers), + .consumer_supplies = ab8500_vdmic_consumers, + }, + /* supply for v-intcore12, VINTCORE12 LDO */ + [AB8500_LDO_INTCORE] = { + .constraints = { + .name = "V-INTCORE", + .min_uV = 1250000, + .max_uV = 1350000, + .input_uV = 1800000, + .valid_ops_mask = REGULATOR_CHANGE_VOLTAGE | + REGULATOR_CHANGE_STATUS | + REGULATOR_CHANGE_MODE | + REGULATOR_CHANGE_DRMS, + .valid_modes_mask = REGULATOR_MODE_NORMAL | + REGULATOR_MODE_IDLE, + }, + .num_consumer_supplies = ARRAY_SIZE(ab8500_vintcore_consumers), + .consumer_supplies = ab8500_vintcore_consumers, + }, + /* supply for U8500 CSI-DSI, VANA LDO */ + [AB8500_LDO_ANA] = { + .constraints = { + .name = "V-CSI-DSI", + .valid_ops_mask = REGULATOR_CHANGE_STATUS, + }, + .num_consumer_supplies = ARRAY_SIZE(ab8500_vana_consumers), + .consumer_supplies = ab8500_vana_consumers, + }, +}; + +/* supply for VextSupply3 */ +static struct regulator_consumer_supply ab8500_ext_supply3_consumers[] = { + /* SIM supply for 3 V SIM cards */ + REGULATOR_SUPPLY("vinvsim", "sim-detect.0"), +}; + +/* + * AB8500 external regulators + */ +static struct regulator_init_data ab8500_ext_regulators[] = { + /* fixed Vbat supplies VSMPS1_EXT_1V8 */ + [AB8500_EXT_SUPPLY1] = { + .constraints = { + .name = "ab8500-ext-supply1", + .min_uV = 1800000, + .max_uV = 1800000, + .initial_mode = REGULATOR_MODE_IDLE, + .boot_on = 1, + .always_on = 1, + }, + }, + /* fixed Vbat supplies VSMPS2_EXT_1V36 and VSMPS5_EXT_1V15 */ + [AB8500_EXT_SUPPLY2] = { + .constraints = { + .name = "ab8500-ext-supply2", + .min_uV = 1360000, + .max_uV = 1360000, + }, + }, + /* fixed Vbat supplies VSMPS3_EXT_3V4 and VSMPS4_EXT_3V4 */ + [AB8500_EXT_SUPPLY3] = { + .constraints = { + .name = "ab8500-ext-supply3", + .min_uV = 3400000, + .max_uV = 3400000, + .valid_ops_mask = REGULATOR_CHANGE_STATUS, + .boot_on = 1, + }, + .num_consumer_supplies = + ARRAY_SIZE(ab8500_ext_supply3_consumers), + .consumer_supplies = ab8500_ext_supply3_consumers, + }, +}; + +static struct ab8500_regulator_platform_data ab8500_regulator_plat_data = { + .reg_init = ab8500_reg_init, + .num_reg_init = ARRAY_SIZE(ab8500_reg_init), + .regulator = ab8500_regulators, + .num_regulator = ARRAY_SIZE(ab8500_regulators), + .ext_regulator = ab8500_ext_regulators, + .num_ext_regulator = ARRAY_SIZE(ab8500_ext_regulators), +}; + /** * struct ab8500_ext_regulator_info - ab8500 regulator information * @dev: device pointer @@ -344,8 +794,7 @@ static struct of_regulator_match ab8500_ext_regulator_match[] = { static int ab8500_ext_regulator_probe(struct platform_device *pdev) { struct ab8500 *ab8500 = dev_get_drvdata(pdev->dev.parent); - struct ab8500_platform_data *ppdata; - struct ab8500_regulator_platform_data *pdata; + struct ab8500_regulator_platform_data *pdata = &ab8500_regulator_plat_data; struct device_node *np = pdev->dev.of_node; struct regulator_config config = { }; int i, err; @@ -366,18 +815,6 @@ static int ab8500_ext_regulator_probe(struct platform_device *pdev) return -EINVAL; } - ppdata = dev_get_platdata(ab8500->dev); - if (!ppdata) { - dev_err(&pdev->dev, "null parent pdata\n"); - return -EINVAL; - } - - pdata = ppdata->regulator; - if (!pdata) { - dev_err(&pdev->dev, "null pdata\n"); - return -EINVAL; - } - /* make sure the platform data has the correct size */ if (pdata->num_ext_regulator != ARRAY_SIZE(ab8500_ext_regulator_info)) { dev_err(&pdev->dev, "Configuration error: size mismatch.\n"); -- cgit v1.2.1 From 842a8824274de3fbbc8e230355d5c75237453bf5 Mon Sep 17 00:00:00 2001 From: Wei Yongjun Date: Tue, 12 Jul 2016 11:23:50 +0000 Subject: regulator: act8865: Fix missing of_node_put() in act8865_pdata_from_dt() This node pointer is returned by of_get_child_by_name() with refcount incremented in this function. of_node_put() is missing when exitting this function while invalid device type. Fix it by move of_get_child_by_name() code after device type check. Found by Coccinelle. Signed-off-by: Wei Yongjun Signed-off-by: Mark Brown --- drivers/regulator/act8865-regulator.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) (limited to 'drivers/regulator') diff --git a/drivers/regulator/act8865-regulator.c b/drivers/regulator/act8865-regulator.c index a1cd0d4f8257..7652477e6a9d 100644 --- a/drivers/regulator/act8865-regulator.c +++ b/drivers/regulator/act8865-regulator.c @@ -395,12 +395,6 @@ static int act8865_pdata_from_dt(struct device *dev, struct act8865_regulator_data *regulator; struct of_regulator_match *matches; - np = of_get_child_by_name(dev->of_node, "regulators"); - if (!np) { - dev_err(dev, "missing 'regulators' subnode in DT\n"); - return -EINVAL; - } - switch (type) { case ACT8600: matches = act8600_matches; @@ -419,6 +413,12 @@ static int act8865_pdata_from_dt(struct device *dev, return -EINVAL; } + np = of_get_child_by_name(dev->of_node, "regulators"); + if (!np) { + dev_err(dev, "missing 'regulators' subnode in DT\n"); + return -EINVAL; + } + matched = of_regulator_match(dev, np, matches, num_matches); of_node_put(np); if (matched <= 0) -- cgit v1.2.1 From 2d0cf04ce166581c617f8943a116587a730f40b6 Mon Sep 17 00:00:00 2001 From: Steve Twiss Date: Fri, 15 Jul 2016 10:29:41 +0100 Subject: regulator: da9210: addition of device tree support Addition of device tree support for DA9210. Two files are modified, the driver source file and the binding document. Updates for the regulator source file include an .of_match_table entry and node match checking in the probe() function for a compatible da9210 string. Minor binding documentation changes have been made to the title and the example. Tested-by: Steve Twiss Signed-off-by: Steve Twiss Signed-off-by: Mark Brown --- drivers/regulator/da9210-regulator.c | 21 +++++++++++++++++++-- 1 file changed, 19 insertions(+), 2 deletions(-) (limited to 'drivers/regulator') diff --git a/drivers/regulator/da9210-regulator.c b/drivers/regulator/da9210-regulator.c index 01c0e3709b66..d0496d6b0934 100644 --- a/drivers/regulator/da9210-regulator.c +++ b/drivers/regulator/da9210-regulator.c @@ -21,12 +21,11 @@ #include #include #include -#include #include #include -#include #include #include +#include #include #include @@ -179,6 +178,13 @@ error_i2c: /* * I2C driver interface functions */ + +static const struct of_device_id da9210_dt_ids[] = { + { .compatible = "dlg,da9210", }, + { } +}; +MODULE_DEVICE_TABLE(of, da9210_dt_ids); + static int da9210_i2c_probe(struct i2c_client *i2c, const struct i2c_device_id *id) { @@ -188,6 +194,16 @@ static int da9210_i2c_probe(struct i2c_client *i2c, struct regulator_dev *rdev = NULL; struct regulator_config config = { }; int error; + const struct of_device_id *match; + + if (i2c->dev.of_node && !pdata) { + match = of_match_device(of_match_ptr(da9210_dt_ids), + &i2c->dev); + if (!match) { + dev_err(&i2c->dev, "Error: No device match found\n"); + return -ENODEV; + } + } chip = devm_kzalloc(&i2c->dev, sizeof(struct da9210), GFP_KERNEL); if (!chip) @@ -264,6 +280,7 @@ MODULE_DEVICE_TABLE(i2c, da9210_i2c_id); static struct i2c_driver da9210_regulator_driver = { .driver = { .name = "da9210", + .of_match_table = of_match_ptr(da9210_dt_ids), }, .probe = da9210_i2c_probe, .id_table = da9210_i2c_id, -- cgit v1.2.1 From 2fdf829236183e5be559a2b4d13c29926b79b2d4 Mon Sep 17 00:00:00 2001 From: Chen Zhong Date: Mon, 18 Jul 2016 14:40:51 +0200 Subject: regulator: mt6323: Add support for MT6323 regulator The MT6323 is a regulator found on boards based on MediaTek MT7623 and probably other SoCs. It is a so called pmic and connects as a slave to SoC using SPI, wrapped inside the pmic-wrapper. Signed-off-by: Chen Zhong Signed-off-by: John Crispin Signed-off-by: Mark Brown --- drivers/regulator/Kconfig | 9 + drivers/regulator/Makefile | 1 + drivers/regulator/mt6323-regulator.c | 425 +++++++++++++++++++++++++++++++++++ 3 files changed, 435 insertions(+) create mode 100644 drivers/regulator/mt6323-regulator.c (limited to 'drivers/regulator') diff --git a/drivers/regulator/Kconfig b/drivers/regulator/Kconfig index 144cbf5b3e5a..53b30b46c1c5 100644 --- a/drivers/regulator/Kconfig +++ b/drivers/regulator/Kconfig @@ -498,6 +498,15 @@ config REGULATOR_MT6311 This driver supports the control of different power rails of device through regulator interface. +config REGULATOR_MT6323 + tristate "MediaTek MT6323 PMIC" + depends on MFD_MT6397 + help + Say y here to select this option to enable the power regulator of + MediaTek MT6323 PMIC. + This driver supports the control of different power rails of device + through regulator interface. + config REGULATOR_MT6397 tristate "MediaTek MT6397 PMIC" depends on MFD_MT6397 diff --git a/drivers/regulator/Makefile b/drivers/regulator/Makefile index 85a1d44a3939..f3da9eea9ab6 100644 --- a/drivers/regulator/Makefile +++ b/drivers/regulator/Makefile @@ -65,6 +65,7 @@ obj-$(CONFIG_REGULATOR_MC13783) += mc13783-regulator.o obj-$(CONFIG_REGULATOR_MC13892) += mc13892-regulator.o obj-$(CONFIG_REGULATOR_MC13XXX_CORE) += mc13xxx-regulator-core.o obj-$(CONFIG_REGULATOR_MT6311) += mt6311-regulator.o +obj-$(CONFIG_REGULATOR_MT6323) += mt6323-regulator.o obj-$(CONFIG_REGULATOR_MT6397) += mt6397-regulator.o obj-$(CONFIG_REGULATOR_QCOM_RPM) += qcom_rpm-regulator.o obj-$(CONFIG_REGULATOR_QCOM_SMD_RPM) += qcom_smd-regulator.o diff --git a/drivers/regulator/mt6323-regulator.c b/drivers/regulator/mt6323-regulator.c new file mode 100644 index 000000000000..927cc23b1c30 --- /dev/null +++ b/drivers/regulator/mt6323-regulator.c @@ -0,0 +1,425 @@ +/* + * Copyright (c) 2016 MediaTek Inc. + * Author: Chen Zhong + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define MT6323_LDO_MODE_NORMAL 0 +#define MT6323_LDO_MODE_LP 1 + +/* + * MT6323 regulators' information + * + * @desc: standard fields of regulator description. + * @qi: Mask for query enable signal status of regulators + * @vselon_reg: Register sections for hardware control mode of bucks + * @vselctrl_reg: Register for controlling the buck control mode. + * @vselctrl_mask: Mask for query buck's voltage control mode. + */ +struct mt6323_regulator_info { + struct regulator_desc desc; + u32 qi; + u32 vselon_reg; + u32 vselctrl_reg; + u32 vselctrl_mask; + u32 modeset_reg; + u32 modeset_mask; +}; + +#define MT6323_BUCK(match, vreg, min, max, step, volt_ranges, enreg, \ + vosel, vosel_mask, voselon, vosel_ctrl) \ +[MT6323_ID_##vreg] = { \ + .desc = { \ + .name = #vreg, \ + .of_match = of_match_ptr(match), \ + .ops = &mt6323_volt_range_ops, \ + .type = REGULATOR_VOLTAGE, \ + .id = MT6323_ID_##vreg, \ + .owner = THIS_MODULE, \ + .n_voltages = (max - min)/step + 1, \ + .linear_ranges = volt_ranges, \ + .n_linear_ranges = ARRAY_SIZE(volt_ranges), \ + .vsel_reg = vosel, \ + .vsel_mask = vosel_mask, \ + .enable_reg = enreg, \ + .enable_mask = BIT(0), \ + }, \ + .qi = BIT(13), \ + .vselon_reg = voselon, \ + .vselctrl_reg = vosel_ctrl, \ + .vselctrl_mask = BIT(1), \ +} + +#define MT6323_LDO(match, vreg, ldo_volt_table, enreg, enbit, vosel, \ + vosel_mask, _modeset_reg, _modeset_mask) \ +[MT6323_ID_##vreg] = { \ + .desc = { \ + .name = #vreg, \ + .of_match = of_match_ptr(match), \ + .ops = &mt6323_volt_table_ops, \ + .type = REGULATOR_VOLTAGE, \ + .id = MT6323_ID_##vreg, \ + .owner = THIS_MODULE, \ + .n_voltages = ARRAY_SIZE(ldo_volt_table), \ + .volt_table = ldo_volt_table, \ + .vsel_reg = vosel, \ + .vsel_mask = vosel_mask, \ + .enable_reg = enreg, \ + .enable_mask = BIT(enbit), \ + }, \ + .qi = BIT(15), \ + .modeset_reg = _modeset_reg, \ + .modeset_mask = _modeset_mask, \ +} + +#define MT6323_REG_FIXED(match, vreg, enreg, enbit, volt, \ + _modeset_reg, _modeset_mask) \ +[MT6323_ID_##vreg] = { \ + .desc = { \ + .name = #vreg, \ + .of_match = of_match_ptr(match), \ + .ops = &mt6323_volt_fixed_ops, \ + .type = REGULATOR_VOLTAGE, \ + .id = MT6323_ID_##vreg, \ + .owner = THIS_MODULE, \ + .n_voltages = 1, \ + .enable_reg = enreg, \ + .enable_mask = BIT(enbit), \ + .min_uV = volt, \ + }, \ + .qi = BIT(15), \ + .modeset_reg = _modeset_reg, \ + .modeset_mask = _modeset_mask, \ +} + +static const struct regulator_linear_range buck_volt_range1[] = { + REGULATOR_LINEAR_RANGE(700000, 0, 0x7f, 6250), +}; + +static const struct regulator_linear_range buck_volt_range2[] = { + REGULATOR_LINEAR_RANGE(1400000, 0, 0x7f, 12500), +}; + +static const struct regulator_linear_range buck_volt_range3[] = { + REGULATOR_LINEAR_RANGE(500000, 0, 0x3f, 50000), +}; + +static const u32 ldo_volt_table1[] = { + 3300000, 3400000, 3500000, 3600000, +}; + +static const u32 ldo_volt_table2[] = { + 1500000, 1800000, 2500000, 2800000, +}; + +static const u32 ldo_volt_table3[] = { + 1800000, 3300000, +}; + +static const u32 ldo_volt_table4[] = { + 3000000, 3300000, +}; + +static const u32 ldo_volt_table5[] = { + 1200000, 1300000, 1500000, 1800000, 2000000, 2800000, 3000000, 3300000, +}; + +static const u32 ldo_volt_table6[] = { + 1200000, 1300000, 1500000, 1800000, 2500000, 2800000, 3000000, 2000000, +}; + +static const u32 ldo_volt_table7[] = { + 1200000, 1300000, 1500000, 1800000, +}; + +static const u32 ldo_volt_table8[] = { + 1800000, 3000000, +}; + +static const u32 ldo_volt_table9[] = { + 1200000, 1350000, 1500000, 1800000, +}; + +static const u32 ldo_volt_table10[] = { + 1200000, 1300000, 1500000, 1800000, +}; + +static int mt6323_get_status(struct regulator_dev *rdev) +{ + int ret; + u32 regval; + struct mt6323_regulator_info *info = rdev_get_drvdata(rdev); + + ret = regmap_read(rdev->regmap, info->desc.enable_reg, ®val); + if (ret != 0) { + dev_err(&rdev->dev, "Failed to get enable reg: %d\n", ret); + return ret; + } + + return (regval & info->qi) ? REGULATOR_STATUS_ON : REGULATOR_STATUS_OFF; +} + +static int mt6323_ldo_set_mode(struct regulator_dev *rdev, unsigned int mode) +{ + int ret, val = 0; + struct mt6323_regulator_info *info = rdev_get_drvdata(rdev); + + if (!info->modeset_mask) { + dev_err(&rdev->dev, "regulator %s doesn't support set_mode\n", + info->desc.name); + return -EINVAL; + } + + switch (mode) { + case REGULATOR_MODE_STANDBY: + val = MT6323_LDO_MODE_LP; + break; + case REGULATOR_MODE_NORMAL: + val = MT6323_LDO_MODE_NORMAL; + break; + default: + return -EINVAL; + } + + val <<= ffs(info->modeset_mask) - 1; + + ret = regmap_update_bits(rdev->regmap, info->modeset_reg, + info->modeset_mask, val); + + return ret; +} + +static unsigned int mt6323_ldo_get_mode(struct regulator_dev *rdev) +{ + unsigned int val; + unsigned int mode; + int ret; + struct mt6323_regulator_info *info = rdev_get_drvdata(rdev); + + if (!info->modeset_mask) { + dev_err(&rdev->dev, "regulator %s doesn't support get_mode\n", + info->desc.name); + return -EINVAL; + } + + ret = regmap_read(rdev->regmap, info->modeset_reg, &val); + if (ret < 0) + return ret; + + val &= info->modeset_mask; + val >>= ffs(info->modeset_mask) - 1; + + if (val & 0x1) + mode = REGULATOR_MODE_STANDBY; + else + mode = REGULATOR_MODE_NORMAL; + + return mode; +} + +static struct regulator_ops mt6323_volt_range_ops = { + .list_voltage = regulator_list_voltage_linear_range, + .map_voltage = regulator_map_voltage_linear_range, + .set_voltage_sel = regulator_set_voltage_sel_regmap, + .get_voltage_sel = regulator_get_voltage_sel_regmap, + .set_voltage_time_sel = regulator_set_voltage_time_sel, + .enable = regulator_enable_regmap, + .disable = regulator_disable_regmap, + .is_enabled = regulator_is_enabled_regmap, + .get_status = mt6323_get_status, +}; + +static struct regulator_ops mt6323_volt_table_ops = { + .list_voltage = regulator_list_voltage_table, + .map_voltage = regulator_map_voltage_iterate, + .set_voltage_sel = regulator_set_voltage_sel_regmap, + .get_voltage_sel = regulator_get_voltage_sel_regmap, + .set_voltage_time_sel = regulator_set_voltage_time_sel, + .enable = regulator_enable_regmap, + .disable = regulator_disable_regmap, + .is_enabled = regulator_is_enabled_regmap, + .get_status = mt6323_get_status, + .set_mode = mt6323_ldo_set_mode, + .get_mode = mt6323_ldo_get_mode, +}; + +static struct regulator_ops mt6323_volt_fixed_ops = { + .list_voltage = regulator_list_voltage_linear, + .enable = regulator_enable_regmap, + .disable = regulator_disable_regmap, + .is_enabled = regulator_is_enabled_regmap, + .get_status = mt6323_get_status, + .set_mode = mt6323_ldo_set_mode, + .get_mode = mt6323_ldo_get_mode, +}; + +/* The array is indexed by id(MT6323_ID_XXX) */ +static struct mt6323_regulator_info mt6323_regulators[] = { + MT6323_BUCK("buck_vproc", VPROC, 700000, 1493750, 6250, + buck_volt_range1, MT6323_VPROC_CON7, MT6323_VPROC_CON9, 0x7f, + MT6323_VPROC_CON10, MT6323_VPROC_CON5), + MT6323_BUCK("buck_vsys", VSYS, 1400000, 2987500, 12500, + buck_volt_range2, MT6323_VSYS_CON7, MT6323_VSYS_CON9, 0x7f, + MT6323_VSYS_CON10, MT6323_VSYS_CON5), + MT6323_BUCK("buck_vpa", VPA, 500000, 3650000, 50000, + buck_volt_range3, MT6323_VPA_CON7, MT6323_VPA_CON9, + 0x3f, MT6323_VPA_CON10, MT6323_VPA_CON5), + MT6323_REG_FIXED("ldo_vtcxo", VTCXO, MT6323_ANALDO_CON1, 10, 2800000, + MT6323_ANALDO_CON1, 0x2), + MT6323_REG_FIXED("ldo_vcn28", VCN28, MT6323_ANALDO_CON19, 12, 2800000, + MT6323_ANALDO_CON20, 0x2), + MT6323_LDO("ldo_vcn33_bt", VCN33_BT, ldo_volt_table1, + MT6323_ANALDO_CON16, 7, MT6323_ANALDO_CON16, 0xC, + MT6323_ANALDO_CON21, 0x2), + MT6323_LDO("ldo_vcn33_wifi", VCN33_WIFI, ldo_volt_table1, + MT6323_ANALDO_CON17, 12, MT6323_ANALDO_CON16, 0xC, + MT6323_ANALDO_CON21, 0x2), + MT6323_REG_FIXED("ldo_va", VA, MT6323_ANALDO_CON2, 14, 2800000, + MT6323_ANALDO_CON2, 0x2), + MT6323_LDO("ldo_vcama", VCAMA, ldo_volt_table2, + MT6323_ANALDO_CON4, 15, MT6323_ANALDO_CON10, 0x60, -1, 0), + MT6323_REG_FIXED("ldo_vio28", VIO28, MT6323_DIGLDO_CON0, 14, 2800000, + MT6323_DIGLDO_CON0, 0x2), + MT6323_REG_FIXED("ldo_vusb", VUSB, MT6323_DIGLDO_CON2, 14, 3300000, + MT6323_DIGLDO_CON2, 0x2), + MT6323_LDO("ldo_vmc", VMC, ldo_volt_table3, + MT6323_DIGLDO_CON3, 12, MT6323_DIGLDO_CON24, 0x10, + MT6323_DIGLDO_CON3, 0x2), + MT6323_LDO("ldo_vmch", VMCH, ldo_volt_table4, + MT6323_DIGLDO_CON5, 14, MT6323_DIGLDO_CON26, 0x80, + MT6323_DIGLDO_CON5, 0x2), + MT6323_LDO("ldo_vemc3v3", VEMC3V3, ldo_volt_table4, + MT6323_DIGLDO_CON6, 14, MT6323_DIGLDO_CON27, 0x80, + MT6323_DIGLDO_CON6, 0x2), + MT6323_LDO("ldo_vgp1", VGP1, ldo_volt_table5, + MT6323_DIGLDO_CON7, 15, MT6323_DIGLDO_CON28, 0xE0, + MT6323_DIGLDO_CON7, 0x2), + MT6323_LDO("ldo_vgp2", VGP2, ldo_volt_table6, + MT6323_DIGLDO_CON8, 15, MT6323_DIGLDO_CON29, 0xE0, + MT6323_DIGLDO_CON8, 0x2), + MT6323_LDO("ldo_vgp3", VGP3, ldo_volt_table7, + MT6323_DIGLDO_CON9, 15, MT6323_DIGLDO_CON30, 0x60, + MT6323_DIGLDO_CON9, 0x2), + MT6323_REG_FIXED("ldo_vcn18", VCN18, MT6323_DIGLDO_CON11, 14, 1800000, + MT6323_DIGLDO_CON11, 0x2), + MT6323_LDO("ldo_vsim1", VSIM1, ldo_volt_table8, + MT6323_DIGLDO_CON13, 15, MT6323_DIGLDO_CON34, 0x20, + MT6323_DIGLDO_CON13, 0x2), + MT6323_LDO("ldo_vsim2", VSIM2, ldo_volt_table8, + MT6323_DIGLDO_CON14, 15, MT6323_DIGLDO_CON35, 0x20, + MT6323_DIGLDO_CON14, 0x2), + MT6323_REG_FIXED("ldo_vrtc", VRTC, MT6323_DIGLDO_CON15, 8, 2800000, + -1, 0), + MT6323_LDO("ldo_vcamaf", VCAMAF, ldo_volt_table5, + MT6323_DIGLDO_CON31, 15, MT6323_DIGLDO_CON32, 0xE0, + MT6323_DIGLDO_CON31, 0x2), + MT6323_LDO("ldo_vibr", VIBR, ldo_volt_table5, + MT6323_DIGLDO_CON39, 15, MT6323_DIGLDO_CON40, 0xE0, + MT6323_DIGLDO_CON39, 0x2), + MT6323_REG_FIXED("ldo_vrf18", VRF18, MT6323_DIGLDO_CON45, 15, 1825000, + MT6323_DIGLDO_CON45, 0x2), + MT6323_LDO("ldo_vm", VM, ldo_volt_table9, + MT6323_DIGLDO_CON47, 14, MT6323_DIGLDO_CON48, 0x30, + MT6323_DIGLDO_CON47, 0x2), + MT6323_REG_FIXED("ldo_vio18", VIO18, MT6323_DIGLDO_CON49, 14, 1800000, + MT6323_DIGLDO_CON49, 0x2), + MT6323_LDO("ldo_vcamd", VCAMD, ldo_volt_table10, + MT6323_DIGLDO_CON51, 14, MT6323_DIGLDO_CON52, 0x60, + MT6323_DIGLDO_CON51, 0x2), + MT6323_REG_FIXED("ldo_vcamio", VCAMIO, MT6323_DIGLDO_CON53, 14, 1800000, + MT6323_DIGLDO_CON53, 0x2), +}; + +static int mt6323_set_buck_vosel_reg(struct platform_device *pdev) +{ + struct mt6397_chip *mt6323 = dev_get_drvdata(pdev->dev.parent); + int i; + u32 regval; + + for (i = 0; i < MT6323_MAX_REGULATOR; i++) { + if (mt6323_regulators[i].vselctrl_reg) { + if (regmap_read(mt6323->regmap, + mt6323_regulators[i].vselctrl_reg, + ®val) < 0) { + dev_err(&pdev->dev, + "Failed to read buck ctrl\n"); + return -EIO; + } + + if (regval & mt6323_regulators[i].vselctrl_mask) { + mt6323_regulators[i].desc.vsel_reg = + mt6323_regulators[i].vselon_reg; + } + } + } + + return 0; +} + +static int mt6323_regulator_probe(struct platform_device *pdev) +{ + struct mt6397_chip *mt6323 = dev_get_drvdata(pdev->dev.parent); + struct regulator_config config = {}; + struct regulator_dev *rdev; + int i; + u32 reg_value; + + /* Query buck controller to select activated voltage register part */ + if (mt6323_set_buck_vosel_reg(pdev)) + return -EIO; + + /* Read PMIC chip revision to update constraints and voltage table */ + if (regmap_read(mt6323->regmap, MT6323_CID, ®_value) < 0) { + dev_err(&pdev->dev, "Failed to read Chip ID\n"); + return -EIO; + } + dev_info(&pdev->dev, "Chip ID = 0x%x\n", reg_value); + + for (i = 0; i < MT6323_MAX_REGULATOR; i++) { + config.dev = &pdev->dev; + config.driver_data = &mt6323_regulators[i]; + config.regmap = mt6323->regmap; + rdev = devm_regulator_register(&pdev->dev, + &mt6323_regulators[i].desc, &config); + if (IS_ERR(rdev)) { + dev_err(&pdev->dev, "failed to register %s\n", + mt6323_regulators[i].desc.name); + return PTR_ERR(rdev); + } + } + return 0; +} + +static const struct platform_device_id mt6323_platform_ids[] = { + {"mt6323-regulator", 0}, + { /* sentinel */ }, +}; +MODULE_DEVICE_TABLE(platform, mt6323_platform_ids); + +static struct platform_driver mt6323_regulator_driver = { + .driver = { + .name = "mt6323-regulator", + }, + .probe = mt6323_regulator_probe, + .id_table = mt6323_platform_ids, +}; + +module_platform_driver(mt6323_regulator_driver); + +MODULE_AUTHOR("Chen Zhong "); +MODULE_DESCRIPTION("Regulator Driver for MediaTek MT6397 PMIC"); +MODULE_LICENSE("GPL v2"); -- cgit v1.2.1 From 15b1dc982394cb74d9e1df00b49d1991e7c4f47d Mon Sep 17 00:00:00 2001 From: Axel Lin Date: Tue, 19 Jul 2016 22:02:28 +0800 Subject: regulator: mt6323: Fix module description Signed-off-by: Axel Lin Signed-off-by: Mark Brown --- drivers/regulator/mt6323-regulator.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/regulator') diff --git a/drivers/regulator/mt6323-regulator.c b/drivers/regulator/mt6323-regulator.c index 927cc23b1c30..f7831f3d1744 100644 --- a/drivers/regulator/mt6323-regulator.c +++ b/drivers/regulator/mt6323-regulator.c @@ -421,5 +421,5 @@ static struct platform_driver mt6323_regulator_driver = { module_platform_driver(mt6323_regulator_driver); MODULE_AUTHOR("Chen Zhong "); -MODULE_DESCRIPTION("Regulator Driver for MediaTek MT6397 PMIC"); +MODULE_DESCRIPTION("Regulator Driver for MediaTek MT6323 PMIC"); MODULE_LICENSE("GPL v2"); -- cgit v1.2.1 From 634f41dcecc9dfe4d74420789b0a54f382aa45ea Mon Sep 17 00:00:00 2001 From: Axel Lin Date: Tue, 19 Jul 2016 22:02:29 +0800 Subject: regulator: mt6323: Constify struct regulator_ops Signed-off-by: Axel Lin Signed-off-by: Mark Brown --- drivers/regulator/mt6323-regulator.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'drivers/regulator') diff --git a/drivers/regulator/mt6323-regulator.c b/drivers/regulator/mt6323-regulator.c index f7831f3d1744..b7b9670f0979 100644 --- a/drivers/regulator/mt6323-regulator.c +++ b/drivers/regulator/mt6323-regulator.c @@ -231,7 +231,7 @@ static unsigned int mt6323_ldo_get_mode(struct regulator_dev *rdev) return mode; } -static struct regulator_ops mt6323_volt_range_ops = { +static const struct regulator_ops mt6323_volt_range_ops = { .list_voltage = regulator_list_voltage_linear_range, .map_voltage = regulator_map_voltage_linear_range, .set_voltage_sel = regulator_set_voltage_sel_regmap, @@ -243,7 +243,7 @@ static struct regulator_ops mt6323_volt_range_ops = { .get_status = mt6323_get_status, }; -static struct regulator_ops mt6323_volt_table_ops = { +static const struct regulator_ops mt6323_volt_table_ops = { .list_voltage = regulator_list_voltage_table, .map_voltage = regulator_map_voltage_iterate, .set_voltage_sel = regulator_set_voltage_sel_regmap, @@ -257,7 +257,7 @@ static struct regulator_ops mt6323_volt_table_ops = { .get_mode = mt6323_ldo_get_mode, }; -static struct regulator_ops mt6323_volt_fixed_ops = { +static const struct regulator_ops mt6323_volt_fixed_ops = { .list_voltage = regulator_list_voltage_linear, .enable = regulator_enable_regmap, .disable = regulator_disable_regmap, -- cgit v1.2.1 From 707319b60ade4fefa4fc31138f4147f2a5abb88b Mon Sep 17 00:00:00 2001 From: Steve Twiss Date: Wed, 20 Jul 2016 15:53:58 +0100 Subject: regulator: da9053/52: Fix incorrectly stated minimum and maximum voltage limits This fix alters the minimum and maximum BUCK voltage limits for DA9052 and DA9053. It does so for the following cases: DA9052 - BUCK3 (MEM) min: 0.925V -> 0.950V max: 2.500V -> 2.525V DA9053 - BUCK3 (MEM) min: 0.925V -> 0.950V max: 2.500V -> 2.525V - BUCK4 (PERI) min: 0.925V -> 0.950V max: 2.500V -> 2.525V The voltage range remains the same, but the limits are shifted by +0.025V. This change is provided on DA9052:MEM, DA9053:MEM and DA9053:PERI and is a voltage difference of 0.025V, compared to those measured before this fix is applied. The patch has the effect of decreasing *all* measured voltages on those BUCKs when compared against the previously measured values for the same software voltage request. For example, with this fix applied for DA9052:MEM, DA9053:MEM and DA9053:PERI, the following is true. Because the previous software defined slot 0 as being 0.925V, if a request for 0.950V was previously sent, the slot 1 voltage would have been used. This would have corresponded to an actual measured voltage of 0.975V. But, with this patch fix, and with slot 0 properly aligned to 0.950V, if a voltage of 0.950V is requested by software, a measured value of 0.950V will be provided. Tested-by: Steve Twiss Signed-off-by: Steve Twiss Signed-off-by: Mark Brown --- drivers/regulator/da9052-regulator.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'drivers/regulator') diff --git a/drivers/regulator/da9052-regulator.c b/drivers/regulator/da9052-regulator.c index 1050cb77561a..9ececfef42d6 100644 --- a/drivers/regulator/da9052-regulator.c +++ b/drivers/regulator/da9052-regulator.c @@ -333,7 +333,7 @@ static const struct regulator_ops da9052_ldo_ops = { static struct da9052_regulator_info da9052_regulator_info[] = { DA9052_DCDC(BUCK1, 25, 500, 2075, 6, 6, DA9052_SUPPLY_VBCOREGO), DA9052_DCDC(BUCK2, 25, 500, 2075, 6, 6, DA9052_SUPPLY_VBPROGO), - DA9052_DCDC(BUCK3, 25, 925, 2500, 6, 6, DA9052_SUPPLY_VBMEMGO), + DA9052_DCDC(BUCK3, 25, 950, 2525, 6, 6, DA9052_SUPPLY_VBMEMGO), DA9052_DCDC(BUCK4, 50, 1800, 3600, 5, 6, 0), DA9052_LDO(LDO1, 50, 600, 1800, 5, 6, 0), DA9052_LDO(LDO2, 25, 600, 1800, 6, 6, DA9052_SUPPLY_VLDO2GO), @@ -350,8 +350,8 @@ static struct da9052_regulator_info da9052_regulator_info[] = { static struct da9052_regulator_info da9053_regulator_info[] = { DA9052_DCDC(BUCK1, 25, 500, 2075, 6, 6, DA9052_SUPPLY_VBCOREGO), DA9052_DCDC(BUCK2, 25, 500, 2075, 6, 6, DA9052_SUPPLY_VBPROGO), - DA9052_DCDC(BUCK3, 25, 925, 2500, 6, 6, DA9052_SUPPLY_VBMEMGO), - DA9052_DCDC(BUCK4, 25, 925, 2500, 6, 6, 0), + DA9052_DCDC(BUCK3, 25, 950, 2525, 6, 6, DA9052_SUPPLY_VBMEMGO), + DA9052_DCDC(BUCK4, 25, 950, 2525, 6, 6, 0), DA9052_LDO(LDO1, 50, 600, 1800, 5, 6, 0), DA9052_LDO(LDO2, 25, 600, 1800, 6, 6, DA9052_SUPPLY_VLDO2GO), DA9052_LDO(LDO3, 25, 1725, 3300, 6, 6, DA9052_SUPPLY_VLDO3GO), -- cgit v1.2.1 From ea398e28739e25651ede7ddf5aeb57cbcbc8ca7d Mon Sep 17 00:00:00 2001 From: Boris Brezillon Date: Tue, 14 Jun 2016 11:13:21 +0200 Subject: regulator: pwm: Support extra continuous mode cases The continuous mode allows one to declare a PWM regulator without having to declare the voltage <-> dutycycle association table. It works fine as long as your voltage(dutycycle) function is linear, but also has the following constraints: - dutycycle for min_uV = 0% - dutycycle for max_uV = 100% - dutycycle for min_uV < dutycycle for max_uV While the linearity constraint is acceptable for now, we sometimes need to restrict of the PWM range (to limit the maximum/minimum voltage for example) or have a min_uV_dutycycle > max_uV_dutycycle (this could be tweaked with PWM polarity, but not all PWMs support inverted polarity). Add the pwm-dutycycle-range and pwm-dutycycle-unit DT properties to define such constraints. If those properties are not defined, the PWM regulator use the default pwm-dutycycle-range = <0 100> and pwm-dutycycle-unit = <100> values (existing behavior). Signed-off-by: Boris Brezillon Reviewed-by: Brian Norris Tested-by: Brian Norris Tested-by: Heiko Stuebner Acked-by: Mark Brown Signed-off-by: Thierry Reding --- drivers/regulator/pwm-regulator.c | 92 ++++++++++++++++++++++++++++++++++----- 1 file changed, 82 insertions(+), 10 deletions(-) (limited to 'drivers/regulator') diff --git a/drivers/regulator/pwm-regulator.c b/drivers/regulator/pwm-regulator.c index ae0bebbfda9d..c24524242da2 100644 --- a/drivers/regulator/pwm-regulator.c +++ b/drivers/regulator/pwm-regulator.c @@ -22,6 +22,12 @@ #include #include +struct pwm_continuous_reg_data { + unsigned int min_uV_dutycycle; + unsigned int max_uV_dutycycle; + unsigned int dutycycle_unit; +}; + struct pwm_regulator_data { /* Shared */ struct pwm_device *pwm; @@ -29,6 +35,9 @@ struct pwm_regulator_data { /* Voltage table */ struct pwm_voltages *duty_cycle_table; + /* Continuous mode info */ + struct pwm_continuous_reg_data continuous; + /* regulator descriptor */ struct regulator_desc desc; @@ -145,32 +154,78 @@ static int pwm_regulator_is_enabled(struct regulator_dev *dev) static int pwm_regulator_get_voltage(struct regulator_dev *rdev) { struct pwm_regulator_data *drvdata = rdev_get_drvdata(rdev); + unsigned int min_uV_duty = drvdata->continuous.min_uV_dutycycle; + unsigned int max_uV_duty = drvdata->continuous.max_uV_dutycycle; + unsigned int duty_unit = drvdata->continuous.dutycycle_unit; int min_uV = rdev->constraints->min_uV; - int diff = rdev->constraints->max_uV - min_uV; + int max_uV = rdev->constraints->max_uV; + int diff_uV = max_uV - min_uV; struct pwm_state pstate; + unsigned int diff_duty; + unsigned int voltage; pwm_get_state(drvdata->pwm, &pstate); - return min_uV + pwm_get_relative_duty_cycle(&pstate, diff); + voltage = pwm_get_relative_duty_cycle(&pstate, duty_unit); + + /* + * The dutycycle for min_uV might be greater than the one for max_uV. + * This is happening when the user needs an inversed polarity, but the + * PWM device does not support inversing it in hardware. + */ + if (max_uV_duty < min_uV_duty) { + voltage = min_uV_duty - voltage; + diff_duty = min_uV_duty - max_uV_duty; + } else { + voltage = voltage - min_uV_duty; + diff_duty = max_uV_duty - min_uV_duty; + } + + voltage = DIV_ROUND_CLOSEST_ULL((u64)voltage * diff_uV, diff_duty); + + return voltage + min_uV; } static int pwm_regulator_set_voltage(struct regulator_dev *rdev, - int min_uV, int max_uV, - unsigned *selector) + int req_min_uV, int req_max_uV, + unsigned int *selector) { struct pwm_regulator_data *drvdata = rdev_get_drvdata(rdev); + unsigned int min_uV_duty = drvdata->continuous.min_uV_dutycycle; + unsigned int max_uV_duty = drvdata->continuous.max_uV_dutycycle; + unsigned int duty_unit = drvdata->continuous.dutycycle_unit; unsigned int ramp_delay = rdev->constraints->ramp_delay; - unsigned int req_diff = min_uV - rdev->constraints->min_uV; + int min_uV = rdev->constraints->min_uV; + int max_uV = rdev->constraints->max_uV; + int diff_uV = max_uV - min_uV; struct pwm_state pstate; - unsigned int diff; int old_uV = pwm_regulator_get_voltage(rdev); + unsigned int diff_duty; + unsigned int dutycycle; int ret; pwm_init_state(drvdata->pwm, &pstate); - diff = rdev->constraints->max_uV - rdev->constraints->min_uV; - /* We pass diff as the scale to get a uV precision. */ - pwm_set_relative_duty_cycle(&pstate, req_diff, diff); + /* + * The dutycycle for min_uV might be greater than the one for max_uV. + * This is happening when the user needs an inversed polarity, but the + * PWM device does not support inversing it in hardware. + */ + if (max_uV_duty < min_uV_duty) + diff_duty = min_uV_duty - max_uV_duty; + else + diff_duty = max_uV_duty - min_uV_duty; + + dutycycle = DIV_ROUND_CLOSEST_ULL((u64)(req_min_uV - min_uV) * + diff_duty, + diff_uV); + + if (max_uV_duty < min_uV_duty) + dutycycle = min_uV_duty - dutycycle; + else + dutycycle = min_uV_duty + dutycycle; + + pwm_set_relative_duty_cycle(&pstate, dutycycle, duty_unit); ret = pwm_apply_state(drvdata->pwm, &pstate); if (ret) { @@ -182,7 +237,7 @@ static int pwm_regulator_set_voltage(struct regulator_dev *rdev, return 0; /* Ramp delay is in uV/uS. Adjust to uS and delay */ - ramp_delay = DIV_ROUND_UP(abs(min_uV - old_uV), ramp_delay); + ramp_delay = DIV_ROUND_UP(abs(req_min_uV - old_uV), ramp_delay); usleep_range(ramp_delay, ramp_delay + DIV_ROUND_UP(ramp_delay, 10)); return 0; @@ -255,11 +310,28 @@ static int pwm_regulator_init_table(struct platform_device *pdev, static int pwm_regulator_init_continuous(struct platform_device *pdev, struct pwm_regulator_data *drvdata) { + u32 dutycycle_range[2] = { 0, 100 }; + u32 dutycycle_unit = 100; + memcpy(&drvdata->ops, &pwm_regulator_voltage_continuous_ops, sizeof(drvdata->ops)); drvdata->desc.ops = &drvdata->ops; drvdata->desc.continuous_voltage_range = true; + of_property_read_u32_array(pdev->dev.of_node, + "pwm-dutycycle-range", + dutycycle_range, 2); + of_property_read_u32(pdev->dev.of_node, "pwm-dutycycle-unit", + &dutycycle_unit); + + if (dutycycle_range[0] > dutycycle_unit || + dutycycle_range[1] > dutycycle_unit) + return -EINVAL; + + drvdata->continuous.dutycycle_unit = dutycycle_unit; + drvdata->continuous.min_uV_dutycycle = dutycycle_range[0]; + drvdata->continuous.max_uV_dutycycle = dutycycle_range[1]; + return 0; } -- cgit v1.2.1 From 290284776bb281759b11faa287b8abccaf74bfcb Mon Sep 17 00:00:00 2001 From: Stephen Boyd Date: Mon, 11 Jul 2016 14:50:07 -0700 Subject: regulator: qcom_smd: Fix voltage ranges for pm8x41 The voltage ranges listed here are wrong. The correct ranges can be seen in the "native" spmi regulator driver qcom_spmi-regulator.c at pldo_ranges[], ftsmps_ranges[] and boost_ranges[] for the pldo, ftsmps, and boost type regulators. Port these ranges over to the RPM SMD regulator driver so that we list the appropriate set of supported voltages on pldos. Doing this allows us to specify a voltage like 3075000 for l24, whereas before that wasn't a supported voltage. Fixes: da65e367b67e ("regulator: Regulator driver for the Qualcomm RPM") Signed-off-by: Stephen Boyd Reviewed-by: Andy Gross Signed-off-by: Mark Brown --- drivers/regulator/qcom_smd-regulator.c | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) (limited to 'drivers/regulator') diff --git a/drivers/regulator/qcom_smd-regulator.c b/drivers/regulator/qcom_smd-regulator.c index 5022fa8d10c6..47cd28e960db 100644 --- a/drivers/regulator/qcom_smd-regulator.c +++ b/drivers/regulator/qcom_smd-regulator.c @@ -221,29 +221,30 @@ static const struct regulator_desc pm8x41_hfsmps = { static const struct regulator_desc pm8841_ftsmps = { .linear_ranges = (struct regulator_linear_range[]) { REGULATOR_LINEAR_RANGE(350000, 0, 184, 5000), - REGULATOR_LINEAR_RANGE(700000, 185, 339, 10000), + REGULATOR_LINEAR_RANGE(1280000, 185, 261, 10000), }, .n_linear_ranges = 2, - .n_voltages = 340, + .n_voltages = 262, .ops = &rpm_smps_ldo_ops, }; static const struct regulator_desc pm8941_boost = { .linear_ranges = (struct regulator_linear_range[]) { - REGULATOR_LINEAR_RANGE(4000000, 0, 15, 100000), + REGULATOR_LINEAR_RANGE(4000000, 0, 30, 50000), }, .n_linear_ranges = 1, - .n_voltages = 16, + .n_voltages = 31, .ops = &rpm_smps_ldo_ops, }; static const struct regulator_desc pm8941_pldo = { .linear_ranges = (struct regulator_linear_range[]) { - REGULATOR_LINEAR_RANGE( 750000, 0, 30, 25000), - REGULATOR_LINEAR_RANGE(1500000, 31, 99, 50000), + REGULATOR_LINEAR_RANGE( 750000, 0, 63, 12500), + REGULATOR_LINEAR_RANGE(1550000, 64, 126, 25000), + REGULATOR_LINEAR_RANGE(3100000, 127, 163, 50000), }, - .n_linear_ranges = 2, - .n_voltages = 100, + .n_linear_ranges = 3, + .n_voltages = 164, .ops = &rpm_smps_ldo_ops, }; -- cgit v1.2.1 From c488f0071eacd10a290df4fb34bbdeb4eb8e7888 Mon Sep 17 00:00:00 2001 From: Stephen Boyd Date: Mon, 11 Jul 2016 14:50:08 -0700 Subject: regulator: qcom_smd: Fix voltage ranges for pma8084 ftsmps and pldo The voltage ranges listed here are wrong. The pma8084 pldo supports three different overlapping voltage ranges with differing step sizes and the pma8084 ftsmps supports two. These ranges can be seen in the "native" spmi regulator driver (qcom_spmi-regulator.c) at pldo_ranges[] and ftsmps_ranges[] respectively. Port these ranges over to the RPM SMD regulator driver so that we list the appropriate set of supported voltages on these types of regulators. Fixes: ee01d0c91ef1 ("regulator: qcom-smd: Add support for PMA8084") Signed-off-by: Stephen Boyd Reviewed-by: Andy Gross Signed-off-by: Mark Brown --- drivers/regulator/qcom_smd-regulator.c | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) (limited to 'drivers/regulator') diff --git a/drivers/regulator/qcom_smd-regulator.c b/drivers/regulator/qcom_smd-regulator.c index 47cd28e960db..8ed46a9a55c8 100644 --- a/drivers/regulator/qcom_smd-regulator.c +++ b/drivers/regulator/qcom_smd-regulator.c @@ -178,20 +178,21 @@ static const struct regulator_desc pma8084_hfsmps = { static const struct regulator_desc pma8084_ftsmps = { .linear_ranges = (struct regulator_linear_range[]) { REGULATOR_LINEAR_RANGE(350000, 0, 184, 5000), - REGULATOR_LINEAR_RANGE(700000, 185, 339, 10000), + REGULATOR_LINEAR_RANGE(1280000, 185, 261, 10000), }, .n_linear_ranges = 2, - .n_voltages = 340, + .n_voltages = 262, .ops = &rpm_smps_ldo_ops, }; static const struct regulator_desc pma8084_pldo = { .linear_ranges = (struct regulator_linear_range[]) { - REGULATOR_LINEAR_RANGE(750000, 0, 30, 25000), - REGULATOR_LINEAR_RANGE(1500000, 31, 99, 50000), + REGULATOR_LINEAR_RANGE( 750000, 0, 63, 12500), + REGULATOR_LINEAR_RANGE(1550000, 64, 126, 25000), + REGULATOR_LINEAR_RANGE(3100000, 127, 163, 50000), }, - .n_linear_ranges = 2, - .n_voltages = 100, + .n_linear_ranges = 3, + .n_voltages = 164, .ops = &rpm_smps_ldo_ops, }; -- cgit v1.2.1 From 23a34f9d03a5d40a6234855bc069da370708cc9e Mon Sep 17 00:00:00 2001 From: Tero Kristo Date: Wed, 10 Aug 2016 17:53:55 +0530 Subject: regulator: tps65218: do not disable DCDC3 during poweroff on broken PMICs Some versions of tps65218 do not seem to support poweroff modes properly if DCDC3 regulator is shut-down. Thus, keep it enabled even during poweroff if the version info matches the broken silicon revision. Signed-off-by: Tero Kristo Signed-off-by: Dave Gerlach Signed-off-by: Keerthy Acked-by: Lee Jones Signed-off-by: Mark Brown --- drivers/regulator/tps65218-regulator.c | 8 ++++++++ 1 file changed, 8 insertions(+) (limited to 'drivers/regulator') diff --git a/drivers/regulator/tps65218-regulator.c b/drivers/regulator/tps65218-regulator.c index d1e631d64a20..eb0f5b13841a 100644 --- a/drivers/regulator/tps65218-regulator.c +++ b/drivers/regulator/tps65218-regulator.c @@ -180,6 +180,14 @@ static int tps65218_pmic_set_suspend_disable(struct regulator_dev *dev) if (rid < TPS65218_DCDC_1 || rid > TPS65218_LDO_1) return -EINVAL; + /* + * Certain revisions of TPS65218 will need to have DCDC3 regulator + * enabled always, otherwise an immediate system reboot will occur + * during poweroff. + */ + if (rid == TPS65218_DCDC_3 && tps->rev == TPS65218_REV_2_1) + return 0; + if (!tps->info[rid]->strobe) { if (rid == TPS65218_DCDC_3) tps->info[rid]->strobe = 3; -- cgit v1.2.1 From 556ae220ac64b6564be8d76d855e26b65fcf75bf Mon Sep 17 00:00:00 2001 From: Markus Elfring Date: Mon, 15 Aug 2016 10:30:31 +0200 Subject: regulator: rk808: Delete owner assignment The field "owner" is set by core. Thus delete an extra initialisation. Generated by: scripts/coccinelle/api/platform_no_drv_owner.cocci Signed-off-by: Markus Elfring Signed-off-by: Mark Brown --- drivers/regulator/rk808-regulator.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'drivers/regulator') diff --git a/drivers/regulator/rk808-regulator.c b/drivers/regulator/rk808-regulator.c index 40d07ba036e7..a6767494d39b 100644 --- a/drivers/regulator/rk808-regulator.c +++ b/drivers/regulator/rk808-regulator.c @@ -533,8 +533,7 @@ static int rk808_regulator_probe(struct platform_device *pdev) static struct platform_driver rk808_regulator_driver = { .probe = rk808_regulator_probe, .driver = { - .name = "rk808-regulator", - .owner = THIS_MODULE, + .name = "rk808-regulator" }, }; -- cgit v1.2.1 From 37b918a034feda1b1ef404acf003812f37ab8da2 Mon Sep 17 00:00:00 2001 From: Tim Harvey Date: Mon, 15 Aug 2016 12:40:23 -0700 Subject: regulator: Add LTC3676 support This patch adds support for the Linear Technology LTC3676 8-output I2C voltage regulator IC. Cc: Jaffer Kapasi Signed-off-by: Tim Harvey Signed-off-by: Mark Brown --- drivers/regulator/Kconfig | 8 + drivers/regulator/Makefile | 1 + drivers/regulator/ltc3676.c | 420 ++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 429 insertions(+) create mode 100644 drivers/regulator/ltc3676.c (limited to 'drivers/regulator') diff --git a/drivers/regulator/Kconfig b/drivers/regulator/Kconfig index 6c88e31c01f7..527bd6a51ef8 100644 --- a/drivers/regulator/Kconfig +++ b/drivers/regulator/Kconfig @@ -353,6 +353,14 @@ config REGULATOR_LTC3589 This enables support for the LTC3589, LTC3589-1, and LTC3589-2 8-output regulators controlled via I2C. +config REGULATOR_LTC3676 + tristate "LTC3676 8-output voltage regulator" + depends on I2C + select REGMAP_I2C + help + This enables support for the LTC3676 + 8-output regulators controlled via I2C. + config REGULATOR_MAX14577 tristate "Maxim 14577/77836 regulator" depends on MFD_MAX14577 diff --git a/drivers/regulator/Makefile b/drivers/regulator/Makefile index f3da9eea9ab6..2142a5d3fc08 100644 --- a/drivers/regulator/Makefile +++ b/drivers/regulator/Makefile @@ -47,6 +47,7 @@ obj-$(CONFIG_REGULATOR_LP8788) += lp8788-buck.o obj-$(CONFIG_REGULATOR_LP8788) += lp8788-ldo.o obj-$(CONFIG_REGULATOR_LP8755) += lp8755.o obj-$(CONFIG_REGULATOR_LTC3589) += ltc3589.o +obj-$(CONFIG_REGULATOR_LTC3676) += ltc3676.o obj-$(CONFIG_REGULATOR_MAX14577) += max14577-regulator.o obj-$(CONFIG_REGULATOR_MAX1586) += max1586.o obj-$(CONFIG_REGULATOR_MAX77620) += max77620-regulator.o diff --git a/drivers/regulator/ltc3676.c b/drivers/regulator/ltc3676.c new file mode 100644 index 000000000000..e2b476ca2b4d --- /dev/null +++ b/drivers/regulator/ltc3676.c @@ -0,0 +1,420 @@ +/* + * Copyright (C) 2016 Gateworks Corporation, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 + * as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; 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 +#include + +#define DRIVER_NAME "ltc3676" + +/* LTC3676 Registers */ +#define LTC3676_BUCK1 0x01 +#define LTC3676_BUCK2 0x02 +#define LTC3676_BUCK3 0x03 +#define LTC3676_BUCK4 0x04 +#define LTC3676_LDOA 0x05 +#define LTC3676_LDOB 0x06 +#define LTC3676_SQD1 0x07 +#define LTC3676_SQD2 0x08 +#define LTC3676_CNTRL 0x09 +#define LTC3676_DVB1A 0x0A +#define LTC3676_DVB1B 0x0B +#define LTC3676_DVB2A 0x0C +#define LTC3676_DVB2B 0x0D +#define LTC3676_DVB3A 0x0E +#define LTC3676_DVB3B 0x0F +#define LTC3676_DVB4A 0x10 +#define LTC3676_DVB4B 0x11 +#define LTC3676_MSKIRQ 0x12 +#define LTC3676_MSKPG 0x13 +#define LTC3676_USER 0x14 +#define LTC3676_IRQSTAT 0x15 +#define LTC3676_PGSTATL 0x16 +#define LTC3676_PGSTATRT 0x17 +#define LTC3676_HRST 0x1E +#define LTC3676_CLIRQ 0x1F + +#define LTC3676_DVBxA_REF_SELECT BIT(5) + +#define LTC3676_IRQSTAT_PGOOD_TIMEOUT BIT(3) +#define LTC3676_IRQSTAT_UNDERVOLT_WARN BIT(4) +#define LTC3676_IRQSTAT_UNDERVOLT_FAULT BIT(5) +#define LTC3676_IRQSTAT_THERMAL_WARN BIT(6) +#define LTC3676_IRQSTAT_THERMAL_FAULT BIT(7) + +enum ltc3676_reg { + LTC3676_SW1, + LTC3676_SW2, + LTC3676_SW3, + LTC3676_SW4, + LTC3676_LDO1, + LTC3676_LDO2, + LTC3676_LDO3, + LTC3676_LDO4, + LTC3676_NUM_REGULATORS, +}; + +struct ltc3676 { + struct regmap *regmap; + struct device *dev; + struct regulator_desc regulator_descs[LTC3676_NUM_REGULATORS]; + struct regulator_dev *regulators[LTC3676_NUM_REGULATORS]; +}; + +static int ltc3676_set_suspend_voltage(struct regulator_dev *rdev, int uV) +{ + struct ltc3676 *ltc3676 = rdev_get_drvdata(rdev); + struct device *dev = ltc3676->dev; + int dcdc = rdev_get_id(rdev); + int sel; + + dev_dbg(dev, "%s id=%d uV=%d\n", __func__, dcdc, uV); + sel = regulator_map_voltage_linear(rdev, uV, uV); + if (sel < 0) + return sel; + + /* DVBB register follows right after the corresponding DVBA register */ + return regmap_update_bits(ltc3676->regmap, rdev->desc->vsel_reg + 1, + rdev->desc->vsel_mask, sel); +} + +static int ltc3676_set_suspend_mode(struct regulator_dev *rdev, + unsigned int mode) +{ + struct ltc3676 *ltc3676= rdev_get_drvdata(rdev); + struct device *dev = ltc3676->dev; + int mask, val; + int dcdc = rdev_get_id(rdev); + + dev_dbg(dev, "%s id=%d mode=%d\n", __func__, dcdc, mode); + + mask = LTC3676_DVBxA_REF_SELECT; + switch (mode) { + case REGULATOR_MODE_STANDBY: + val = 0; /* select DVBxA */ + break; + case REGULATOR_MODE_NORMAL: + val = LTC3676_DVBxA_REF_SELECT; /* select DVBxB */ + break; + default: + dev_warn(&rdev->dev, "%s: regulator mode: 0x%x not supported\n", + rdev->desc->name, mode); + return -EINVAL; + } + + return regmap_update_bits(ltc3676->regmap, rdev->desc->vsel_reg, + mask, val); +} + +static inline unsigned int ltc3676_scale(unsigned int uV, u32 r1, u32 r2) +{ + uint64_t tmp; + if (uV == 0) + return 0; + tmp = (uint64_t)uV * r1; + do_div(tmp, r2); + return uV + (unsigned int)tmp; +} + +static int ltc3676_of_parse_cb(struct device_node *np, + const struct regulator_desc *desc, + struct regulator_config *config) +{ + struct ltc3676 *ltc3676 = config->driver_data; + struct regulator_desc *rdesc = <c3676->regulator_descs[desc->id]; + u32 r[2]; + int ret; + + /* LDO3 has a fixed output */ + if (desc->id == LTC3676_LDO3) + return 0; + + ret = of_property_read_u32_array(np, "lltc,fb-voltage-divider", r, 2); + if (ret) { + dev_err(ltc3676->dev, "Failed to parse voltage divider: %d\n", + ret); + return ret; + } + + rdesc->min_uV = ltc3676_scale(desc->min_uV, r[0], r[1]); + rdesc->uV_step = ltc3676_scale(desc->uV_step, r[0], r[1]); + rdesc->fixed_uV = ltc3676_scale(desc->fixed_uV, r[0], r[1]); + + return 0; +} + +/* SW1, SW2, SW3, SW4 linear 0.8V-3.3V with scalar via R1/R2 feeback res */ +static struct regulator_ops ltc3676_linear_regulator_ops = { + .enable = regulator_enable_regmap, + .disable = regulator_disable_regmap, + .is_enabled = regulator_is_enabled_regmap, + .list_voltage = regulator_list_voltage_linear, + .set_voltage_sel = regulator_set_voltage_sel_regmap, + .get_voltage_sel = regulator_get_voltage_sel_regmap, + .set_suspend_voltage = ltc3676_set_suspend_voltage, + .set_suspend_mode = ltc3676_set_suspend_mode, +}; + +/* LDO1 always on fixed 0.8V-3.3V via scalar via R1/R2 feeback res */ +static struct regulator_ops ltc3676_fixed_standby_regulator_ops = { +}; + +/* LDO2, LDO3 fixed (LDO2 has external scalar via R1/R2 feedback res) */ +static struct regulator_ops ltc3676_fixed_regulator_ops = { + .enable = regulator_enable_regmap, + .disable = regulator_disable_regmap, + .is_enabled = regulator_is_enabled_regmap, +}; + +#define LTC3676_REG(_id, _name, _ops, en_reg, en_bit, dvba_reg, dvb_mask) \ + [LTC3676_ ## _id] = { \ + .name = #_name, \ + .of_match = of_match_ptr(#_name), \ + .regulators_node = of_match_ptr("regulators"), \ + .of_parse_cb = ltc3676_of_parse_cb, \ + .n_voltages = (dvb_mask) + 1, \ + .min_uV = (dvba_reg) ? 412500 : 0, \ + .uV_step = (dvba_reg) ? 12500 : 0, \ + .ramp_delay = (dvba_reg) ? 800 : 0, \ + .fixed_uV = (dvb_mask) ? 0 : 725000, \ + .ops = <c3676_ ## _ops ## _regulator_ops, \ + .type = REGULATOR_VOLTAGE, \ + .id = LTC3676_ ## _id, \ + .owner = THIS_MODULE, \ + .vsel_reg = (dvba_reg), \ + .vsel_mask = (dvb_mask), \ + .enable_reg = (en_reg), \ + .enable_mask = (1 << en_bit), \ + } + +#define LTC3676_LINEAR_REG(_id, _name, _en, _dvba) \ + LTC3676_REG(_id, _name, linear, \ + LTC3676_ ## _en, 7, \ + LTC3676_ ## _dvba, 0x1f) + +#define LTC3676_FIXED_REG(_id, _name, _en_reg, _en_bit) \ + LTC3676_REG(_id, _name, fixed, LTC3676_ ## _en_reg, _en_bit, 0, 0) + +static struct regulator_desc ltc3676_regulators[LTC3676_NUM_REGULATORS] = { + LTC3676_LINEAR_REG(SW1, sw1, BUCK1, DVB1A), + LTC3676_LINEAR_REG(SW2, sw2, BUCK2, DVB2A), + LTC3676_LINEAR_REG(SW3, sw3, BUCK3, DVB3A), + LTC3676_LINEAR_REG(SW4, sw4, BUCK4, DVB4A), + LTC3676_REG(LDO1, ldo1, fixed_standby, 0, 0, 0, 0), + LTC3676_FIXED_REG(LDO2, ldo2, LDOA, 2), + LTC3676_FIXED_REG(LDO3, ldo3, LDOA, 5), + LTC3676_FIXED_REG(LDO4, ldo4, LDOB, 2), +}; + +static bool ltc3676_writeable_reg(struct device *dev, unsigned int reg) +{ + switch (reg) { + case LTC3676_IRQSTAT: + case LTC3676_BUCK1: + case LTC3676_BUCK2: + case LTC3676_BUCK3: + case LTC3676_BUCK4: + case LTC3676_LDOA: + case LTC3676_LDOB: + case LTC3676_SQD1: + case LTC3676_SQD2: + case LTC3676_CNTRL: + case LTC3676_DVB1A: + case LTC3676_DVB1B: + case LTC3676_DVB2A: + case LTC3676_DVB2B: + case LTC3676_DVB3A: + case LTC3676_DVB3B: + case LTC3676_DVB4A: + case LTC3676_DVB4B: + case LTC3676_MSKIRQ: + case LTC3676_MSKPG: + case LTC3676_USER: + case LTC3676_HRST: + case LTC3676_CLIRQ: + return true; + } + return false; +} + +static bool ltc3676_readable_reg(struct device *dev, unsigned int reg) +{ + switch (reg) { + case LTC3676_IRQSTAT: + case LTC3676_BUCK1: + case LTC3676_BUCK2: + case LTC3676_BUCK3: + case LTC3676_BUCK4: + case LTC3676_LDOA: + case LTC3676_LDOB: + case LTC3676_SQD1: + case LTC3676_SQD2: + case LTC3676_CNTRL: + case LTC3676_DVB1A: + case LTC3676_DVB1B: + case LTC3676_DVB2A: + case LTC3676_DVB2B: + case LTC3676_DVB3A: + case LTC3676_DVB3B: + case LTC3676_DVB4A: + case LTC3676_DVB4B: + case LTC3676_MSKIRQ: + case LTC3676_MSKPG: + case LTC3676_USER: + case LTC3676_HRST: + case LTC3676_CLIRQ: + return true; + } + return false; +} + +static bool ltc3676_volatile_reg(struct device *dev, unsigned int reg) +{ + switch (reg) { + case LTC3676_IRQSTAT: + case LTC3676_PGSTATL: + case LTC3676_PGSTATRT: + return true; + } + return false; +} + +static const struct regmap_config ltc3676_regmap_config = { + .reg_bits = 8, + .val_bits = 8, + .writeable_reg = ltc3676_writeable_reg, + .readable_reg = ltc3676_readable_reg, + .volatile_reg = ltc3676_volatile_reg, + .max_register = LTC3676_CLIRQ, + .use_single_rw = true, + .cache_type = REGCACHE_RBTREE, +}; + +static irqreturn_t ltc3676_isr(int irq, void *dev_id) +{ + struct ltc3676 *ltc3676 = dev_id; + struct device *dev = ltc3676->dev; + unsigned int i, irqstat, event; + + regmap_read(ltc3676->regmap, LTC3676_IRQSTAT, &irqstat); + + dev_dbg(dev, "irq%d irqstat=0x%02x\n", irq, irqstat); + if (irqstat & LTC3676_IRQSTAT_THERMAL_WARN) { + dev_warn(dev, "Over-temperature Warning\n"); + event = REGULATOR_EVENT_OVER_TEMP; + for (i = 0; i < LTC3676_NUM_REGULATORS; i++) + regulator_notifier_call_chain(ltc3676->regulators[i], + event, NULL); + } + + if (irqstat & LTC3676_IRQSTAT_UNDERVOLT_WARN) { + dev_info(dev, "Undervoltage Warning\n"); + event = REGULATOR_EVENT_UNDER_VOLTAGE; + for (i = 0; i < LTC3676_NUM_REGULATORS; i++) + regulator_notifier_call_chain(ltc3676->regulators[i], + event, NULL); + } + + /* Clear warning condition */ + regmap_write(ltc3676->regmap, LTC3676_CLIRQ, 0); + + return IRQ_HANDLED; +} + +static int ltc3676_regulator_probe(struct i2c_client *client, + const struct i2c_device_id *id) +{ + struct device *dev = &client->dev; + struct regulator_init_data *init_data = dev_get_platdata(dev); + struct regulator_desc *descs; + struct ltc3676 *ltc3676; + int i, ret; + + ltc3676 = devm_kzalloc(dev, sizeof(*ltc3676), GFP_KERNEL); + if (!ltc3676) + return -ENOMEM; + + i2c_set_clientdata(client, ltc3676); + ltc3676->dev = dev; + + descs = ltc3676->regulator_descs; + memcpy(descs, ltc3676_regulators, sizeof(ltc3676_regulators)); + descs[LTC3676_LDO3].fixed_uV = 1800000; /* LDO3 is fixed 1.8V */ + + ltc3676->regmap = devm_regmap_init_i2c(client, <c3676_regmap_config); + if (IS_ERR(ltc3676->regmap)) { + ret = PTR_ERR(ltc3676->regmap); + dev_err(dev, "failed to initialize regmap: %d\n", ret); + return ret; + } + + for (i = 0; i < LTC3676_NUM_REGULATORS; i++) { + struct regulator_desc *desc = <c3676->regulator_descs[i]; + struct regulator_config config = { }; + + if (init_data) + config.init_data = &init_data[i]; + + config.dev = dev; + config.driver_data = ltc3676; + + ltc3676->regulators[i] = devm_regulator_register(dev, desc, + &config); + if (IS_ERR(ltc3676->regulators[i])) { + ret = PTR_ERR(ltc3676->regulators[i]); + dev_err(dev, "failed to register regulator %s: %d\n", + desc->name, ret); + return ret; + } + } + + regmap_write(ltc3676->regmap, LTC3676_CLIRQ, 0); + if (client->irq) { + ret = devm_request_threaded_irq(dev, client->irq, NULL, + ltc3676_isr, + IRQF_TRIGGER_LOW | IRQF_ONESHOT, + client->name, ltc3676); + if (ret) { + dev_err(dev, "Failed to request IRQ: %d\n", ret); + return ret; + } + } + + return 0; +} + +static const struct i2c_device_id ltc3676_i2c_id[] = { + { "ltc3676" }, + { } +}; +MODULE_DEVICE_TABLE(i2c, ltc3676_i2c_id); + +static struct i2c_driver ltc3676_driver = { + .driver = { + .name = DRIVER_NAME, + }, + .probe = ltc3676_regulator_probe, + .id_table = ltc3676_i2c_id, +}; +module_i2c_driver(ltc3676_driver); + +MODULE_AUTHOR("Tim Harvey "); +MODULE_DESCRIPTION("Regulator driver for Linear Technology LTC1376"); +MODULE_LICENSE("GPL v2"); -- cgit v1.2.1 From 565f9b073f37e5cb6f80ad0ad71ec1144f87fd9f Mon Sep 17 00:00:00 2001 From: Bjorn Andersson Date: Tue, 16 Aug 2016 11:50:32 -0700 Subject: regulator: Remove support for optional supplies in the bulk API The patch was based on my missinterpretation of the API and only accidentally worked for me. Let's clean it out to not confuse others. This reverts commit 3ff3f518a135fa4592fe2817e9ac2cce1fa23dc2. Signed-off-by: Bjorn Andersson Signed-off-by: Mark Brown --- drivers/regulator/core.c | 6 ++---- drivers/regulator/devres.c | 7 ++----- 2 files changed, 4 insertions(+), 9 deletions(-) (limited to 'drivers/regulator') diff --git a/drivers/regulator/core.c b/drivers/regulator/core.c index db320e8fa865..8ccdaf89b1c3 100644 --- a/drivers/regulator/core.c +++ b/drivers/regulator/core.c @@ -3483,10 +3483,8 @@ int regulator_bulk_get(struct device *dev, int num_consumers, consumers[i].consumer = NULL; for (i = 0; i < num_consumers; i++) { - consumers[i].consumer = _regulator_get(dev, - consumers[i].supply, - false, - !consumers[i].optional); + consumers[i].consumer = regulator_get(dev, + consumers[i].supply); if (IS_ERR(consumers[i].consumer)) { ret = PTR_ERR(consumers[i].consumer); dev_err(dev, "Failed to get supply '%s': %d\n", diff --git a/drivers/regulator/devres.c b/drivers/regulator/devres.c index 6ad8ab4c578d..6ec1d400adae 100644 --- a/drivers/regulator/devres.c +++ b/drivers/regulator/devres.c @@ -164,11 +164,8 @@ int devm_regulator_bulk_get(struct device *dev, int num_consumers, consumers[i].consumer = NULL; for (i = 0; i < num_consumers; i++) { - consumers[i].consumer = _devm_regulator_get(dev, - consumers[i].supply, - consumers[i].optional ? - OPTIONAL_GET : - NORMAL_GET); + consumers[i].consumer = devm_regulator_get(dev, + consumers[i].supply); if (IS_ERR(consumers[i].consumer)) { ret = PTR_ERR(consumers[i].consumer); dev_err(dev, "Failed to get supply '%s': %d\n", -- cgit v1.2.1 From cea8aa3a93d1734816e1e3f7b118e1dddf3f4aaa Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Wed, 17 Aug 2016 14:07:46 +0200 Subject: regulator: Change Krzysztof Kozlowski's email to kernel.org Change my email address to kernel.org instead of Samsung one for the purpose of any future contact. The copyrights remain untouched and are attributed to Samsung. Signed-off-by: Krzysztof Kozlowski Signed-off-by: Mark Brown --- drivers/regulator/max14577-regulator.c | 4 ++-- drivers/regulator/max77693-regulator.c | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) (limited to 'drivers/regulator') diff --git a/drivers/regulator/max14577-regulator.c b/drivers/regulator/max14577-regulator.c index b2daa6641417..c9ff26199711 100644 --- a/drivers/regulator/max14577-regulator.c +++ b/drivers/regulator/max14577-regulator.c @@ -2,7 +2,7 @@ * max14577.c - Regulator driver for the Maxim 14577/77836 * * Copyright (C) 2013,2014 Samsung Electronics - * Krzysztof Kozlowski + * Krzysztof Kozlowski * * 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 @@ -331,7 +331,7 @@ static void __exit max14577_regulator_exit(void) } module_exit(max14577_regulator_exit); -MODULE_AUTHOR("Krzysztof Kozlowski "); +MODULE_AUTHOR("Krzysztof Kozlowski "); MODULE_DESCRIPTION("Maxim 14577/77836 regulator driver"); MODULE_LICENSE("GPL"); MODULE_ALIAS("platform:max14577-regulator"); diff --git a/drivers/regulator/max77693-regulator.c b/drivers/regulator/max77693-regulator.c index de730fd3f8a5..cfbb9512e486 100644 --- a/drivers/regulator/max77693-regulator.c +++ b/drivers/regulator/max77693-regulator.c @@ -3,7 +3,7 @@ * * Copyright (C) 2013-2015 Samsung Electronics * Jonghwa Lee - * Krzysztof Kozlowski + * Krzysztof Kozlowski * * 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 @@ -314,5 +314,5 @@ module_exit(max77693_pmic_cleanup); MODULE_DESCRIPTION("MAXIM 77693/77843 regulator driver"); MODULE_AUTHOR("Jonghwa Lee "); -MODULE_AUTHOR("Krzysztof Kozlowski "); +MODULE_AUTHOR("Krzysztof Kozlowski "); MODULE_LICENSE("GPL"); -- cgit v1.2.1 From 3b063496f0dc8eb5bf9c73ee72f9fb42157581ff Mon Sep 17 00:00:00 2001 From: Sebastiaan Schalbroeck Date: Mon, 22 Aug 2016 18:23:14 +0200 Subject: regulator: Kconfig: Fix typo Fix typo in regulator Kconfig for the TPS80031 tristate string (trivial) Signed-off-by: Sebastiaan Schalbroeck Signed-off-by: Mark Brown --- drivers/regulator/Kconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/regulator') diff --git a/drivers/regulator/Kconfig b/drivers/regulator/Kconfig index 6c88e31c01f7..cfb322384505 100644 --- a/drivers/regulator/Kconfig +++ b/drivers/regulator/Kconfig @@ -820,7 +820,7 @@ config REGULATOR_TPS65912 This driver supports TPS65912 voltage regulator chip. config REGULATOR_TPS80031 - tristate "TI TPS80031/TPS80032 power regualtor driver" + tristate "TI TPS80031/TPS80032 power regulator driver" depends on MFD_TPS80031 help TPS80031/ TPS80032 Fully Integrated Power Management with Power -- cgit v1.2.1 From ddc085d44dd001e65eecd0a8bf05064bff063668 Mon Sep 17 00:00:00 2001 From: Neil Armstrong Date: Thu, 11 Aug 2016 15:16:46 +0200 Subject: regulator: qcom_rpm-regulator: Add support for pm8018 rpm regulator In order to support the Qualcomm MDM9615 SoC, add support for the PM8018 RPM regulator in the qcom_rpm-regulator driver. Signed-off-by: Neil Armstrong Acked-by: Mark Brown Signed-off-by: Lee Jones --- drivers/regulator/qcom_rpm-regulator.c | 66 ++++++++++++++++++++++++++++++++++ 1 file changed, 66 insertions(+) (limited to 'drivers/regulator') diff --git a/drivers/regulator/qcom_rpm-regulator.c b/drivers/regulator/qcom_rpm-regulator.c index e254272585b2..1b2acc43fea1 100644 --- a/drivers/regulator/qcom_rpm-regulator.c +++ b/drivers/regulator/qcom_rpm-regulator.c @@ -447,6 +447,44 @@ static struct regulator_ops switch_ops = { .is_enabled = rpm_reg_is_enabled, }; +/* + * PM8018 regulators + */ +static const struct qcom_rpm_reg pm8018_pldo = { + .desc.linear_ranges = pldo_ranges, + .desc.n_linear_ranges = ARRAY_SIZE(pldo_ranges), + .desc.n_voltages = 161, + .desc.ops = &uV_ops, + .parts = &rpm8960_ldo_parts, + .supports_force_mode_auto = false, + .supports_force_mode_bypass = false, +}; + +static const struct qcom_rpm_reg pm8018_nldo = { + .desc.linear_ranges = nldo_ranges, + .desc.n_linear_ranges = ARRAY_SIZE(nldo_ranges), + .desc.n_voltages = 64, + .desc.ops = &uV_ops, + .parts = &rpm8960_ldo_parts, + .supports_force_mode_auto = false, + .supports_force_mode_bypass = false, +}; + +static const struct qcom_rpm_reg pm8018_smps = { + .desc.linear_ranges = smps_ranges, + .desc.n_linear_ranges = ARRAY_SIZE(smps_ranges), + .desc.n_voltages = 154, + .desc.ops = &uV_ops, + .parts = &rpm8960_smps_parts, + .supports_force_mode_auto = false, + .supports_force_mode_bypass = false, +}; + +static const struct qcom_rpm_reg pm8018_switch = { + .desc.ops = &switch_ops, + .parts = &rpm8960_switch_parts, +}; + /* * PM8058 regulators */ @@ -755,6 +793,32 @@ struct rpm_regulator_data { const char *supply; }; +static const struct rpm_regulator_data rpm_pm8018_regulators[] = { + { "s1", QCOM_RPM_PM8018_SMPS1, &pm8018_smps, "vdd_s1" }, + { "s2", QCOM_RPM_PM8018_SMPS2, &pm8018_smps, "vdd_s2" }, + { "s3", QCOM_RPM_PM8018_SMPS3, &pm8018_smps, "vdd_s3" }, + { "s4", QCOM_RPM_PM8018_SMPS4, &pm8018_smps, "vdd_s4" }, + { "s5", QCOM_RPM_PM8018_SMPS5, &pm8018_smps, "vdd_s5" }, + + { "l2", QCOM_RPM_PM8018_LDO2, &pm8018_pldo, "vdd_l2" }, + { "l3", QCOM_RPM_PM8018_LDO3, &pm8018_pldo, "vdd_l3" }, + { "l4", QCOM_RPM_PM8018_LDO4, &pm8018_pldo, "vdd_l4" }, + { "l5", QCOM_RPM_PM8018_LDO5, &pm8018_pldo, "vdd_l5" }, + { "l6", QCOM_RPM_PM8018_LDO6, &pm8018_pldo, "vdd_l7" }, + { "l7", QCOM_RPM_PM8018_LDO7, &pm8018_pldo, "vdd_l7" }, + { "l8", QCOM_RPM_PM8018_LDO8, &pm8018_nldo, "vdd_l8" }, + { "l9", QCOM_RPM_PM8018_LDO9, &pm8921_nldo1200, + "vdd_l9_l10_l11_l12" }, + { "l10", QCOM_RPM_PM8018_LDO10, &pm8018_nldo, "vdd_l9_l10_l11_l12" }, + { "l11", QCOM_RPM_PM8018_LDO11, &pm8018_nldo, "vdd_l9_l10_l11_l12" }, + { "l12", QCOM_RPM_PM8018_LDO12, &pm8018_nldo, "vdd_l9_l10_l11_l12" }, + { "l14", QCOM_RPM_PM8018_LDO14, &pm8018_pldo, "vdd_l14" }, + + { "lvs1", QCOM_RPM_PM8018_LVS1, &pm8018_switch, "lvs1_in" }, + + { } +}; + static const struct rpm_regulator_data rpm_pm8058_regulators[] = { { "l0", QCOM_RPM_PM8058_LDO0, &pm8058_nldo, "vdd_l0_l1_lvs" }, { "l1", QCOM_RPM_PM8058_LDO1, &pm8058_nldo, "vdd_l0_l1_lvs" }, @@ -870,6 +934,8 @@ static const struct rpm_regulator_data rpm_pm8921_regulators[] = { }; static const struct of_device_id rpm_of_match[] = { + { .compatible = "qcom,rpm-pm8018-regulators", + .data = &rpm_pm8018_regulators }, { .compatible = "qcom,rpm-pm8058-regulators", .data = &rpm_pm8058_regulators }, { .compatible = "qcom,rpm-pm8901-regulators", .data = &rpm_pm8901_regulators }, { .compatible = "qcom,rpm-pm8921-regulators", .data = &rpm_pm8921_regulators }, -- cgit v1.2.1 From f618ed218dc01207882a8f02b1310c7daaf5156a Mon Sep 17 00:00:00 2001 From: Keerthy Date: Wed, 31 Aug 2016 14:28:12 +0530 Subject: regulator: lp873x: Change the MFD config option as per latest naming Change the MFD config option as per latest naming Signed-off-by: Keerthy Acked-by: Mark Brown Signed-off-by: Lee Jones --- drivers/regulator/Kconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/regulator') diff --git a/drivers/regulator/Kconfig b/drivers/regulator/Kconfig index 6c88e31c01f7..97dc4cc3ef43 100644 --- a/drivers/regulator/Kconfig +++ b/drivers/regulator/Kconfig @@ -323,7 +323,7 @@ config REGULATOR_LP872X config REGULATOR_LP873X tristate "TI LP873X Power regulators" - depends on MFD_LP873X && OF + depends on MFD_TI_LP873X && OF help This driver supports LP873X voltage regulator chips. LP873X provides two step-down converters and two general-purpose LDO -- cgit v1.2.1 From 11375293530bb8434946c8c043f1adf5ffb6be10 Mon Sep 17 00:00:00 2001 From: Wadim Egorov Date: Mon, 29 Aug 2016 13:07:59 +0200 Subject: regulator: rk808: Add regulator driver for RK818 Add support for the rk818 regulator. The regulator module consists of 4 DCDCs, 9 LDOs, 1 switch and 1 BOOST converter which is used to power OTG and HDMI5V. The output voltages are configurable and are meant to supply power to the main processor and other components. Signed-off-by: Wadim Egorov Acked-by: Mark Brown Signed-off-by: Lee Jones --- drivers/regulator/Kconfig | 4 +- drivers/regulator/rk808-regulator.c | 143 ++++++++++++++++++++++++++++++++++-- 2 files changed, 138 insertions(+), 9 deletions(-) (limited to 'drivers/regulator') diff --git a/drivers/regulator/Kconfig b/drivers/regulator/Kconfig index 6c88e31c01f7..d3a86a8cce86 100644 --- a/drivers/regulator/Kconfig +++ b/drivers/regulator/Kconfig @@ -635,11 +635,11 @@ config REGULATOR_RC5T583 outputs which can be controlled by i2c communication. config REGULATOR_RK808 - tristate "Rockchip RK808 Power regulators" + tristate "Rockchip RK808/RK818 Power regulators" depends on MFD_RK808 help Select this option to enable the power regulator of ROCKCHIP - PMIC RK808. + PMIC RK808 and RK818. This driver supports the control of different power rails of device through regulator interface. The device supports multiple DCDC/LDO outputs which can be controlled by i2c communication. diff --git a/drivers/regulator/rk808-regulator.c b/drivers/regulator/rk808-regulator.c index 40d07ba036e7..5f412a5e35e3 100644 --- a/drivers/regulator/rk808-regulator.c +++ b/drivers/regulator/rk808-regulator.c @@ -1,11 +1,15 @@ /* - * Regulator driver for Rockchip RK808 + * Regulator driver for Rockchip RK808/RK818 * * Copyright (c) 2014, Fuzhou Rockchip Electronics Co., Ltd * * Author: Chris Zhong * Author: Zhang Qing * + * Copyright (C) 2016 PHYTEC Messtechnik GmbH + * + * Author: Wadim Egorov + * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. @@ -32,6 +36,12 @@ #define RK808_BUCK4_VSEL_MASK 0xf #define RK808_LDO_VSEL_MASK 0x1f +#define RK818_BUCK_VSEL_MASK 0x3f +#define RK818_BUCK4_VSEL_MASK 0x1f +#define RK818_LDO_VSEL_MASK 0x1f +#define RK818_LDO3_ON_VSEL_MASK 0xf +#define RK818_BOOST_ON_VSEL_MASK 0xe0 + /* Ramp rate definitions for buck1 / buck2 only */ #define RK808_RAMP_RATE_OFFSET 3 #define RK808_RAMP_RATE_MASK (3 << RK808_RAMP_RATE_OFFSET) @@ -454,6 +464,108 @@ static const struct regulator_desc rk808_reg[] = { RK808_DCDC_EN_REG, BIT(6)), }; +static const struct regulator_desc rk818_reg[] = { + { + .name = "DCDC_REG1", + .supply_name = "vcc1", + .of_match = of_match_ptr("DCDC_REG1"), + .regulators_node = of_match_ptr("regulators"), + .id = RK818_ID_DCDC1, + .ops = &rk808_reg_ops, + .type = REGULATOR_VOLTAGE, + .min_uV = 712500, + .uV_step = 12500, + .n_voltages = 64, + .vsel_reg = RK818_BUCK1_ON_VSEL_REG, + .vsel_mask = RK818_BUCK_VSEL_MASK, + .enable_reg = RK818_DCDC_EN_REG, + .enable_mask = BIT(0), + .owner = THIS_MODULE, + }, { + .name = "DCDC_REG2", + .supply_name = "vcc2", + .of_match = of_match_ptr("DCDC_REG2"), + .regulators_node = of_match_ptr("regulators"), + .id = RK818_ID_DCDC2, + .ops = &rk808_reg_ops, + .type = REGULATOR_VOLTAGE, + .min_uV = 712500, + .uV_step = 12500, + .n_voltages = 64, + .vsel_reg = RK818_BUCK2_ON_VSEL_REG, + .vsel_mask = RK818_BUCK_VSEL_MASK, + .enable_reg = RK818_DCDC_EN_REG, + .enable_mask = BIT(1), + .owner = THIS_MODULE, + }, { + .name = "DCDC_REG3", + .supply_name = "vcc3", + .of_match = of_match_ptr("DCDC_REG3"), + .regulators_node = of_match_ptr("regulators"), + .id = RK818_ID_DCDC3, + .ops = &rk808_switch_ops, + .type = REGULATOR_VOLTAGE, + .n_voltages = 1, + .enable_reg = RK818_DCDC_EN_REG, + .enable_mask = BIT(2), + .owner = THIS_MODULE, + }, + RK8XX_DESC(RK818_ID_DCDC4, "DCDC_REG4", "vcc4", 1800, 3600, 100, + RK818_BUCK4_ON_VSEL_REG, RK818_BUCK4_VSEL_MASK, + RK818_DCDC_EN_REG, BIT(3), 0), + RK8XX_DESC(RK818_ID_BOOST, "DCDC_BOOST", "boost", 4700, 5400, 100, + RK818_BOOST_LDO9_ON_VSEL_REG, RK818_BOOST_ON_VSEL_MASK, + RK818_DCDC_EN_REG, BIT(4), 0), + RK8XX_DESC(RK818_ID_LDO1, "LDO_REG1", "vcc6", 1800, 3400, 100, + RK818_LDO1_ON_VSEL_REG, RK818_LDO_VSEL_MASK, RK818_LDO_EN_REG, + BIT(0), 400), + RK8XX_DESC(RK818_ID_LDO2, "LDO_REG2", "vcc6", 1800, 3400, 100, + RK818_LDO1_ON_VSEL_REG, RK818_LDO_VSEL_MASK, RK818_LDO_EN_REG, + BIT(1), 400), + { + .name = "LDO_REG3", + .supply_name = "vcc7", + .of_match = of_match_ptr("LDO_REG3"), + .regulators_node = of_match_ptr("regulators"), + .id = RK818_ID_LDO3, + .ops = &rk808_reg_ops_ranges, + .type = REGULATOR_VOLTAGE, + .n_voltages = 16, + .linear_ranges = rk808_ldo3_voltage_ranges, + .n_linear_ranges = ARRAY_SIZE(rk808_ldo3_voltage_ranges), + .vsel_reg = RK818_LDO3_ON_VSEL_REG, + .vsel_mask = RK818_LDO3_ON_VSEL_MASK, + .enable_reg = RK818_LDO_EN_REG, + .enable_mask = BIT(2), + .enable_time = 400, + .owner = THIS_MODULE, + }, + RK8XX_DESC(RK818_ID_LDO4, "LDO_REG4", "vcc8", 1800, 3400, 100, + RK818_LDO4_ON_VSEL_REG, RK818_LDO_VSEL_MASK, RK818_LDO_EN_REG, + BIT(3), 400), + RK8XX_DESC(RK818_ID_LDO5, "LDO_REG5", "vcc7", 1800, 3400, 100, + RK818_LDO5_ON_VSEL_REG, RK818_LDO_VSEL_MASK, RK818_LDO_EN_REG, + BIT(4), 400), + RK8XX_DESC(RK818_ID_LDO6, "LDO_REG6", "vcc8", 800, 2500, 100, + RK818_LDO6_ON_VSEL_REG, RK818_LDO_VSEL_MASK, RK818_LDO_EN_REG, + BIT(5), 400), + RK8XX_DESC(RK818_ID_LDO7, "LDO_REG7", "vcc7", 800, 2500, 100, + RK818_LDO7_ON_VSEL_REG, RK818_LDO_VSEL_MASK, RK818_LDO_EN_REG, + BIT(6), 400), + RK8XX_DESC(RK818_ID_LDO8, "LDO_REG8", "vcc8", 1800, 3400, 100, + RK818_LDO8_ON_VSEL_REG, RK818_LDO_VSEL_MASK, RK818_LDO_EN_REG, + BIT(7), 400), + RK8XX_DESC(RK818_ID_LDO9, "LDO_REG9", "vcc9", 1800, 3400, 100, + RK818_BOOST_LDO9_ON_VSEL_REG, RK818_LDO_VSEL_MASK, + RK818_DCDC_EN_REG, BIT(5), 400), + RK8XX_DESC_SWITCH(RK818_ID_SWITCH, "SWITCH_REG", "vcc9", + RK818_DCDC_EN_REG, BIT(6)), + RK8XX_DESC_SWITCH(RK818_ID_HDMI_SWITCH, "HDMI_SWITCH", "h_5v", + RK818_H5V_EN_REG, BIT(0)), + RK8XX_DESC_SWITCH(RK818_ID_OTG_SWITCH, "OTG_SWITCH", "usb", + RK818_DCDC_EN_REG, BIT(7)), +}; + static int rk808_regulator_dt_parse_pdata(struct device *dev, struct device *client_dev, struct regmap *map, @@ -499,7 +611,8 @@ static int rk808_regulator_probe(struct platform_device *pdev) struct regulator_config config = {}; struct regulator_dev *rk808_rdev; struct rk808_regulator_data *pdata; - int ret, i; + const struct regulator_desc *regulators; + int ret, i, nregulators; pdata = devm_kzalloc(&pdev->dev, sizeof(*pdata), GFP_KERNEL); if (!pdata) @@ -512,14 +625,29 @@ static int rk808_regulator_probe(struct platform_device *pdev) platform_set_drvdata(pdev, pdata); + switch (rk808->variant) { + case RK808_ID: + regulators = rk808_reg; + nregulators = RK808_NUM_REGULATORS; + break; + case RK818_ID: + regulators = rk818_reg; + nregulators = RK818_NUM_REGULATORS; + break; + default: + dev_err(&client->dev, "unsupported RK8XX ID %lu\n", + rk808->variant); + return -EINVAL; + } + config.dev = &client->dev; config.driver_data = pdata; config.regmap = rk808->regmap; /* Instantiate the regulators */ - for (i = 0; i < RK808_NUM_REGULATORS; i++) { + for (i = 0; i < nregulators; i++) { rk808_rdev = devm_regulator_register(&pdev->dev, - &rk808_reg[i], &config); + ®ulators[i], &config); if (IS_ERR(rk808_rdev)) { dev_err(&client->dev, "failed to register %d regulator\n", i); @@ -540,8 +668,9 @@ static struct platform_driver rk808_regulator_driver = { module_platform_driver(rk808_regulator_driver); -MODULE_DESCRIPTION("regulator driver for the rk808 series PMICs"); -MODULE_AUTHOR("Chris Zhong"); -MODULE_AUTHOR("Zhang Qing"); +MODULE_DESCRIPTION("regulator driver for the RK808/RK818 series PMICs"); +MODULE_AUTHOR("Chris Zhong "); +MODULE_AUTHOR("Zhang Qing "); +MODULE_AUTHOR("Wadim Egorov "); MODULE_LICENSE("GPL"); MODULE_ALIAS("platform:rk808-regulator"); -- cgit v1.2.1 From ea2f7321a9029194a31ff9f798a8276d45747bcd Mon Sep 17 00:00:00 2001 From: Baoyou Xie Date: Wed, 31 Aug 2016 17:30:31 +0800 Subject: regulator: hi6421: mark hi6421_regulator_ldo_get_optimum_mode() static We get 1 warning when building kernel with W=1: drivers/regulator/hi6421-regulator.c:480:14: warning: no previous prototype for 'hi6421_regulator_ldo_get_optimum_mode' [-Wmissing-prototypes] In fact, this function is only used in the file in which it is declared and don't need a declaration, but can be made static. So this patch marks it 'static'. Signed-off-by: Baoyou Xie Acked-by: Arnd Bergmann Signed-off-by: Mark Brown --- drivers/regulator/hi6421-regulator.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'drivers/regulator') diff --git a/drivers/regulator/hi6421-regulator.c b/drivers/regulator/hi6421-regulator.c index 42dc5fb8c899..62c5f5445d44 100644 --- a/drivers/regulator/hi6421-regulator.c +++ b/drivers/regulator/hi6421-regulator.c @@ -477,7 +477,8 @@ static int hi6421_regulator_buck_set_mode(struct regulator_dev *rdev, return 0; } -unsigned int hi6421_regulator_ldo_get_optimum_mode(struct regulator_dev *rdev, +static unsigned int +hi6421_regulator_ldo_get_optimum_mode(struct regulator_dev *rdev, int input_uV, int output_uV, int load_uA) { struct hi6421_regulator_info *info = rdev_get_drvdata(rdev); -- cgit v1.2.1 From 2ca342d391e3d8b56ed64626db8cfba8101b7c1d Mon Sep 17 00:00:00 2001 From: Chen-Yu Tsai Date: Sat, 27 Aug 2016 15:55:39 +0800 Subject: regulator: axp20x: Support AXP806 variant The X-Powers AXP806 PMIC has a new set of buck and LDO regulators, and also a switch. The buck regulators support teaming into multi-phase groups, with A+B, A+B+C, D+E groupings. Some registers controlling DCDC converter work settings are at different offsets. Deal with them as well. Add support for this new variant. Signed-off-by: Chen-Yu Tsai Acked-by: Mark Brown Signed-off-by: Lee Jones --- drivers/regulator/axp20x-regulator.c | 118 ++++++++++++++++++++++++++++++++--- 1 file changed, 111 insertions(+), 7 deletions(-) (limited to 'drivers/regulator') diff --git a/drivers/regulator/axp20x-regulator.c b/drivers/regulator/axp20x-regulator.c index 6d9ac76a772f..54382ef902c6 100644 --- a/drivers/regulator/axp20x-regulator.c +++ b/drivers/regulator/axp20x-regulator.c @@ -244,16 +244,64 @@ static const struct regulator_desc axp22x_drivevbus_regulator = { .ops = &axp20x_ops_sw, }; -static const struct regulator_linear_range axp809_dcdc4_ranges[] = { - REGULATOR_LINEAR_RANGE(600000, 0x0, 0x2f, 20000), - REGULATOR_LINEAR_RANGE(1800000, 0x30, 0x38, 100000), +static const struct regulator_linear_range axp806_dcdca_ranges[] = { + REGULATOR_LINEAR_RANGE(600000, 0x0, 0x32, 10000), + REGULATOR_LINEAR_RANGE(1120000, 0x33, 0x47, 20000), }; -static const struct regulator_linear_range axp809_dldo1_ranges[] = { +static const struct regulator_linear_range axp806_dcdcd_ranges[] = { + REGULATOR_LINEAR_RANGE(600000, 0x0, 0x2d, 20000), + REGULATOR_LINEAR_RANGE(1600000, 0x2e, 0x3f, 100000), +}; + +static const struct regulator_linear_range axp806_cldo2_ranges[] = { REGULATOR_LINEAR_RANGE(700000, 0x0, 0x1a, 100000), REGULATOR_LINEAR_RANGE(3400000, 0x1b, 0x1f, 200000), }; +static const struct regulator_desc axp806_regulators[] = { + AXP_DESC_RANGES(AXP806, DCDCA, "dcdca", "vina", axp806_dcdca_ranges, + 72, AXP806_DCDCA_V_CTRL, 0x7f, AXP806_PWR_OUT_CTRL1, + BIT(0)), + AXP_DESC(AXP806, DCDCB, "dcdcb", "vinb", 1000, 2550, 50, + AXP806_DCDCB_V_CTRL, 0x1f, AXP806_PWR_OUT_CTRL1, BIT(1)), + AXP_DESC_RANGES(AXP806, DCDCC, "dcdcc", "vinc", axp806_dcdca_ranges, + 72, AXP806_DCDCC_V_CTRL, 0x7f, AXP806_PWR_OUT_CTRL1, + BIT(2)), + AXP_DESC_RANGES(AXP806, DCDCD, "dcdcd", "vind", axp806_dcdcd_ranges, + 64, AXP806_DCDCD_V_CTRL, 0x3f, AXP806_PWR_OUT_CTRL1, + BIT(3)), + AXP_DESC(AXP806, DCDCE, "dcdce", "vine", 1100, 3400, 100, + AXP806_DCDCB_V_CTRL, 0x1f, AXP806_PWR_OUT_CTRL1, BIT(4)), + AXP_DESC(AXP806, ALDO1, "aldo1", "aldoin", 700, 3300, 100, + AXP806_ALDO1_V_CTRL, 0x1f, AXP806_PWR_OUT_CTRL1, BIT(5)), + AXP_DESC(AXP806, ALDO2, "aldo2", "aldoin", 700, 3400, 100, + AXP806_ALDO2_V_CTRL, 0x1f, AXP806_PWR_OUT_CTRL1, BIT(6)), + AXP_DESC(AXP806, ALDO3, "aldo3", "aldoin", 700, 3300, 100, + AXP806_ALDO3_V_CTRL, 0x1f, AXP806_PWR_OUT_CTRL1, BIT(7)), + AXP_DESC(AXP806, BLDO1, "bldo1", "bldoin", 700, 1900, 100, + AXP806_BLDO1_V_CTRL, 0x0f, AXP806_PWR_OUT_CTRL2, BIT(0)), + AXP_DESC(AXP806, BLDO2, "bldo2", "bldoin", 700, 1900, 100, + AXP806_BLDO2_V_CTRL, 0x0f, AXP806_PWR_OUT_CTRL2, BIT(1)), + AXP_DESC(AXP806, BLDO3, "bldo3", "bldoin", 700, 1900, 100, + AXP806_BLDO3_V_CTRL, 0x0f, AXP806_PWR_OUT_CTRL2, BIT(2)), + AXP_DESC(AXP806, BLDO4, "bldo4", "bldoin", 700, 1900, 100, + AXP806_BLDO4_V_CTRL, 0x0f, AXP806_PWR_OUT_CTRL2, BIT(3)), + AXP_DESC(AXP806, CLDO1, "cldo1", "cldoin", 700, 3300, 100, + AXP806_CLDO1_V_CTRL, 0x1f, AXP806_PWR_OUT_CTRL2, BIT(4)), + AXP_DESC_RANGES(AXP806, CLDO2, "cldo2", "cldoin", axp806_cldo2_ranges, + 32, AXP806_CLDO2_V_CTRL, 0x1f, AXP806_PWR_OUT_CTRL2, + BIT(5)), + AXP_DESC(AXP806, CLDO3, "cldo3", "cldoin", 700, 3300, 100, + AXP806_CLDO3_V_CTRL, 0x1f, AXP806_PWR_OUT_CTRL2, BIT(6)), + AXP_DESC_SW(AXP806, SW, "sw", "swin", AXP806_PWR_OUT_CTRL2, BIT(7)), +}; + +static const struct regulator_linear_range axp809_dcdc4_ranges[] = { + REGULATOR_LINEAR_RANGE(600000, 0x0, 0x2f, 20000), + REGULATOR_LINEAR_RANGE(1800000, 0x30, 0x38, 100000), +}; + static const struct regulator_desc axp809_regulators[] = { AXP_DESC(AXP809, DCDC1, "dcdc1", "vin1", 1600, 3400, 100, AXP22X_DCDC1_V_OUT, 0x1f, AXP22X_PWR_OUT_CTRL1, BIT(1)), @@ -278,7 +326,7 @@ static const struct regulator_desc axp809_regulators[] = { AXP22X_ALDO2_V_OUT, 0x1f, AXP22X_PWR_OUT_CTRL1, BIT(7)), AXP_DESC(AXP809, ALDO3, "aldo3", "aldoin", 700, 3300, 100, AXP22X_ALDO3_V_OUT, 0x1f, AXP22X_PWR_OUT_CTRL2, BIT(5)), - AXP_DESC_RANGES(AXP809, DLDO1, "dldo1", "dldoin", axp809_dldo1_ranges, + AXP_DESC_RANGES(AXP809, DLDO1, "dldo1", "dldoin", axp806_cldo2_ranges, 32, AXP22X_DLDO1_V_OUT, 0x1f, AXP22X_PWR_OUT_CTRL2, BIT(3)), AXP_DESC(AXP809, DLDO2, "dldo2", "dldoin", 700, 3300, 100, @@ -302,6 +350,7 @@ static const struct regulator_desc axp809_regulators[] = { static int axp20x_set_dcdc_freq(struct platform_device *pdev, u32 dcdcfreq) { struct axp20x_dev *axp20x = dev_get_drvdata(pdev->dev.parent); + unsigned int reg = AXP20X_DCDC_FREQ; u32 min, max, def, step; switch (axp20x->variant) { @@ -312,6 +361,14 @@ static int axp20x_set_dcdc_freq(struct platform_device *pdev, u32 dcdcfreq) def = 1500; step = 75; break; + case AXP806_ID: + /* + * AXP806 DCDC work frequency setting has the same range and + * step as AXP22X, but at a different register. + * Fall through to the check below. + * (See include/linux/mfd/axp20x.h) + */ + reg = AXP806_DCDC_FREQ_CTRL; case AXP221_ID: case AXP223_ID: case AXP809_ID: @@ -343,7 +400,7 @@ static int axp20x_set_dcdc_freq(struct platform_device *pdev, u32 dcdcfreq) dcdcfreq = (dcdcfreq - min) / step; - return regmap_update_bits(axp20x->regmap, AXP20X_DCDC_FREQ, + return regmap_update_bits(axp20x->regmap, reg, AXP20X_FREQ_DCDC_MASK, dcdcfreq); } @@ -377,6 +434,7 @@ static int axp20x_regulator_parse_dt(struct platform_device *pdev) static int axp20x_set_dcdc_workmode(struct regulator_dev *rdev, int id, u32 workmode) { struct axp20x_dev *axp20x = rdev_get_drvdata(rdev); + unsigned int reg = AXP20X_DCDC_MODE; unsigned int mask; switch (axp20x->variant) { @@ -392,6 +450,13 @@ static int axp20x_set_dcdc_workmode(struct regulator_dev *rdev, int id, u32 work workmode <<= ffs(mask) - 1; break; + case AXP806_ID: + reg = AXP806_DCDC_MODE_CTRL2; + /* + * AXP806 DCDC regulator IDs have the same range as AXP22X. + * Fall through to the check below. + * (See include/linux/mfd/axp20x.h) + */ case AXP221_ID: case AXP223_ID: case AXP809_ID: @@ -408,7 +473,34 @@ static int axp20x_set_dcdc_workmode(struct regulator_dev *rdev, int id, u32 work return -EINVAL; } - return regmap_update_bits(rdev->regmap, AXP20X_DCDC_MODE, mask, workmode); + return regmap_update_bits(rdev->regmap, reg, mask, workmode); +} + +/* + * This function checks whether a regulator is part of a poly-phase + * output setup based on the registers settings. Returns true if it is. + */ +static bool axp20x_is_polyphase_slave(struct axp20x_dev *axp20x, int id) +{ + u32 reg = 0; + + /* Only AXP806 has poly-phase outputs */ + if (axp20x->variant != AXP806_ID) + return false; + + regmap_read(axp20x->regmap, AXP806_DCDC_MODE_CTRL2, ®); + + switch (id) { + case AXP806_DCDCB: + return (((reg & GENMASK(7, 6)) == BIT(6)) || + ((reg & GENMASK(7, 6)) == BIT(7))); + case AXP806_DCDCC: + return ((reg & GENMASK(7, 6)) == BIT(7)); + case AXP806_DCDCE: + return !!(reg & BIT(5)); + } + + return false; } static int axp20x_regulator_probe(struct platform_device *pdev) @@ -440,6 +532,10 @@ static int axp20x_regulator_probe(struct platform_device *pdev) drivevbus = of_property_read_bool(pdev->dev.parent->of_node, "x-powers,drive-vbus-en"); break; + case AXP806_ID: + regulators = axp806_regulators; + nregulators = AXP806_REG_ID_MAX; + break; case AXP809_ID: regulators = axp809_regulators; nregulators = AXP809_REG_ID_MAX; @@ -457,6 +553,14 @@ static int axp20x_regulator_probe(struct platform_device *pdev) const struct regulator_desc *desc = ®ulators[i]; struct regulator_desc *new_desc; + /* + * If this regulator is a slave in a poly-phase setup, + * skip it, as its controls are bound to the master + * regulator and won't work. + */ + if (axp20x_is_polyphase_slave(axp20x, i)) + continue; + /* * Regulators DC1SW and DC5LDO are connected internally, * so we have to handle their supply names separately. -- cgit v1.2.1 From 57995a4860542ea2089558c84f739e12d5ca1059 Mon Sep 17 00:00:00 2001 From: Matthias Kaehlcke Date: Wed, 14 Sep 2016 09:52:05 -0700 Subject: regulator: core: Use local ops variable in _regulator_do_set_voltage() Signed-off-by: Matthias Kaehlcke Signed-off-by: Mark Brown --- drivers/regulator/core.c | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) (limited to 'drivers/regulator') diff --git a/drivers/regulator/core.c b/drivers/regulator/core.c index db320e8fa865..b059e8334567 100644 --- a/drivers/regulator/core.c +++ b/drivers/regulator/core.c @@ -2751,6 +2751,7 @@ static int _regulator_do_set_voltage(struct regulator_dev *rdev, int best_val = 0; unsigned int selector; int old_selector = -1; + const struct regulator_ops *ops = rdev->desc->ops; trace_regulator_set_voltage(rdev_get_name(rdev), min_uV, max_uV); @@ -2762,29 +2763,28 @@ static int _regulator_do_set_voltage(struct regulator_dev *rdev, * info to call set_voltage_time_sel(). */ if (_regulator_is_enabled(rdev) && - rdev->desc->ops->set_voltage_time_sel && - rdev->desc->ops->get_voltage_sel) { - old_selector = rdev->desc->ops->get_voltage_sel(rdev); + ops->set_voltage_time_sel && ops->get_voltage_sel) { + old_selector = ops->get_voltage_sel(rdev); if (old_selector < 0) return old_selector; } - if (rdev->desc->ops->set_voltage) { + if (ops->set_voltage) { ret = _regulator_call_set_voltage(rdev, min_uV, max_uV, &selector); if (ret >= 0) { - if (rdev->desc->ops->list_voltage) - best_val = rdev->desc->ops->list_voltage(rdev, - selector); + if (ops->list_voltage) + best_val = ops->list_voltage(rdev, + selector); else best_val = _regulator_get_voltage(rdev); } - } else if (rdev->desc->ops->set_voltage_sel) { + } else if (ops->set_voltage_sel) { ret = regulator_map_voltage(rdev, min_uV, max_uV); if (ret >= 0) { - best_val = rdev->desc->ops->list_voltage(rdev, ret); + best_val = ops->list_voltage(rdev, ret); if (min_uV <= best_val && max_uV >= best_val) { selector = ret; if (old_selector == selector) @@ -2804,7 +2804,7 @@ static int _regulator_do_set_voltage(struct regulator_dev *rdev, if (ret == 0 && !rdev->constraints->ramp_disable && old_selector >= 0 && old_selector != selector) { - delay = rdev->desc->ops->set_voltage_time_sel(rdev, + delay = ops->set_voltage_time_sel(rdev, old_selector, selector); if (delay < 0) { rdev_warn(rdev, "set_voltage_time_sel() failed: %d\n", -- cgit v1.2.1 From 31dfe686ed0ba5a796bcfc5a6745e77ddb5daa4e Mon Sep 17 00:00:00 2001 From: Matthias Kaehlcke Date: Wed, 14 Sep 2016 09:52:06 -0700 Subject: regulator: core: Simplify error flow in _regulator_do_set_voltage() If the voltage can not be set jump to the end of the function. This avoids having to check for an error multiple times and eliminates one level of nesting in a follow-up change. Signed-off-by: Matthias Kaehlcke Signed-off-by: Mark Brown --- drivers/regulator/core.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) (limited to 'drivers/regulator') diff --git a/drivers/regulator/core.c b/drivers/regulator/core.c index b059e8334567..b0076ccf896b 100644 --- a/drivers/regulator/core.c +++ b/drivers/regulator/core.c @@ -2800,8 +2800,11 @@ static int _regulator_do_set_voltage(struct regulator_dev *rdev, ret = -EINVAL; } + if (ret) + goto out; + /* Call set_voltage_time_sel if successfully obtained old_selector */ - if (ret == 0 && !rdev->constraints->ramp_disable && old_selector >= 0 + if (!rdev->constraints->ramp_disable && old_selector >= 0 && old_selector != selector) { delay = ops->set_voltage_time_sel(rdev, @@ -2821,13 +2824,14 @@ static int _regulator_do_set_voltage(struct regulator_dev *rdev, } } - if (ret == 0 && best_val >= 0) { + if (best_val >= 0) { unsigned long data = best_val; _notifier_call_chain(rdev, REGULATOR_EVENT_VOLTAGE_CHANGE, (void *)data); } +out: trace_regulator_set_voltage_complete(rdev_get_name(rdev), best_val); return ret; -- cgit v1.2.1 From d89564efe79419a093e966a959bf5ba2c94e693f Mon Sep 17 00:00:00 2001 From: Matthias Kaehlcke Date: Wed, 14 Sep 2016 09:52:07 -0700 Subject: regulator: core: Don't skip set_voltage_time when ramp delay disabled The current code assumes that only the ramp_delay is used to determine the time needed for the voltage to stabilize. This may be true for the calculation done by regulator_set_voltage_time_sel(), however regulators can implement their own set_voltage_time_sel() op which would be skipped if no ramp delay is specified. Remove the check in _regulator_do_set_voltage(), the functions calculating the ramp delay return 0 anyway when the ramp delay is not configured. Signed-off-by: Matthias Kaehlcke Signed-off-by: Mark Brown --- drivers/regulator/core.c | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) (limited to 'drivers/regulator') diff --git a/drivers/regulator/core.c b/drivers/regulator/core.c index b0076ccf896b..df3028b2a8e9 100644 --- a/drivers/regulator/core.c +++ b/drivers/regulator/core.c @@ -2804,9 +2804,7 @@ static int _regulator_do_set_voltage(struct regulator_dev *rdev, goto out; /* Call set_voltage_time_sel if successfully obtained old_selector */ - if (!rdev->constraints->ramp_disable && old_selector >= 0 - && old_selector != selector) { - + if (!old_selector >= 0 && old_selector != selector) { delay = ops->set_voltage_time_sel(rdev, old_selector, selector); if (delay < 0) { @@ -3051,10 +3049,8 @@ int regulator_set_voltage_time_sel(struct regulator_dev *rdev, else if (rdev->desc->ramp_delay) ramp_delay = rdev->desc->ramp_delay; - if (ramp_delay == 0) { - rdev_warn(rdev, "ramp_delay not set\n"); + if (ramp_delay == 0) return 0; - } /* sanity check */ if (!rdev->desc->ops->list_voltage) -- cgit v1.2.1 From 73e705bf81ceb84b39ef9cf6ffb8d12ca0c58a23 Mon Sep 17 00:00:00 2001 From: Matthias Kaehlcke Date: Wed, 14 Sep 2016 09:52:08 -0700 Subject: regulator: core: Add set_voltage_time op The new op is analogous to set_voltage_time_sel. It can be used by regulators which don't have a table of discrete voltages. The function returns the time for the regulator output voltage to stabilize after being set to a new value, in microseconds. If the op is not set a default implementation is used to calculate the delay. This change also removes the ramp_delay calculation in the PWM regulator, since the driver now uses the core code for the calculation of the delay. Signed-off-by: Matthias Kaehlcke Signed-off-by: Mark Brown --- drivers/regulator/core.c | 86 +++++++++++++++++++++++++++------------ drivers/regulator/pwm-regulator.c | 10 ----- 2 files changed, 59 insertions(+), 37 deletions(-) (limited to 'drivers/regulator') diff --git a/drivers/regulator/core.c b/drivers/regulator/core.c index df3028b2a8e9..c52fc0ce2693 100644 --- a/drivers/regulator/core.c +++ b/drivers/regulator/core.c @@ -2743,6 +2743,24 @@ static int _regulator_call_set_voltage_sel(struct regulator_dev *rdev, return ret; } +static int _regulator_set_voltage_time(struct regulator_dev *rdev, + int old_uV, int new_uV) +{ + unsigned int ramp_delay = 0; + + if (rdev->constraints->ramp_delay) + ramp_delay = rdev->constraints->ramp_delay; + else if (rdev->desc->ramp_delay) + ramp_delay = rdev->desc->ramp_delay; + + if (ramp_delay == 0) { + rdev_warn(rdev, "ramp_delay not set\n"); + return 0; + } + + return DIV_ROUND_UP(abs(new_uV - old_uV), ramp_delay); +} + static int _regulator_do_set_voltage(struct regulator_dev *rdev, int min_uV, int max_uV) { @@ -2752,6 +2770,7 @@ static int _regulator_do_set_voltage(struct regulator_dev *rdev, unsigned int selector; int old_selector = -1; const struct regulator_ops *ops = rdev->desc->ops; + int old_uV = _regulator_get_voltage(rdev); trace_regulator_set_voltage(rdev_get_name(rdev), min_uV, max_uV); @@ -2803,23 +2822,37 @@ static int _regulator_do_set_voltage(struct regulator_dev *rdev, if (ret) goto out; - /* Call set_voltage_time_sel if successfully obtained old_selector */ - if (!old_selector >= 0 && old_selector != selector) { - delay = ops->set_voltage_time_sel(rdev, - old_selector, selector); - if (delay < 0) { - rdev_warn(rdev, "set_voltage_time_sel() failed: %d\n", - delay); - delay = 0; + if (ops->set_voltage_time_sel) { + /* + * Call set_voltage_time_sel if successfully obtained + * old_selector + */ + if (old_selector >= 0 && old_selector != selector) + delay = ops->set_voltage_time_sel(rdev, old_selector, + selector); + } else { + if (old_uV != best_val) { + if (ops->set_voltage_time) + delay = ops->set_voltage_time(rdev, old_uV, + best_val); + else + delay = _regulator_set_voltage_time(rdev, + old_uV, + best_val); } + } - /* Insert any necessary delays */ - if (delay >= 1000) { - mdelay(delay / 1000); - udelay(delay % 1000); - } else if (delay) { - udelay(delay); - } + if (delay < 0) { + rdev_warn(rdev, "failed to get delay: %d\n", delay); + delay = 0; + } + + /* Insert any necessary delays */ + if (delay >= 1000) { + mdelay(delay / 1000); + udelay(delay % 1000); + } else if (delay) { + udelay(delay); } if (best_val >= 0) { @@ -3000,9 +3033,13 @@ int regulator_set_voltage_time(struct regulator *regulator, int voltage; int i; + if (ops->set_voltage_time) + return ops->set_voltage_time(rdev, old_uV, new_uV); + else if (!ops->set_voltage_time_sel) + return _regulator_set_voltage_time(rdev, old_uV, new_uV); + /* Currently requires operations to do this */ - if (!ops->list_voltage || !ops->set_voltage_time_sel - || !rdev->desc->n_voltages) + if (!ops->list_voltage || !rdev->desc->n_voltages) return -EINVAL; for (i = 0; i < rdev->desc->n_voltages; i++) { @@ -3041,17 +3078,8 @@ int regulator_set_voltage_time_sel(struct regulator_dev *rdev, unsigned int old_selector, unsigned int new_selector) { - unsigned int ramp_delay = 0; int old_volt, new_volt; - if (rdev->constraints->ramp_delay) - ramp_delay = rdev->constraints->ramp_delay; - else if (rdev->desc->ramp_delay) - ramp_delay = rdev->desc->ramp_delay; - - if (ramp_delay == 0) - return 0; - /* sanity check */ if (!rdev->desc->ops->list_voltage) return -EINVAL; @@ -3059,7 +3087,11 @@ int regulator_set_voltage_time_sel(struct regulator_dev *rdev, old_volt = rdev->desc->ops->list_voltage(rdev, old_selector); new_volt = rdev->desc->ops->list_voltage(rdev, new_selector); - return DIV_ROUND_UP(abs(new_volt - old_volt), ramp_delay); + if (rdev->desc->ops->set_voltage_time) + return rdev->desc->ops->set_voltage_time(rdev, old_volt, + new_volt); + else + return _regulator_set_voltage_time(rdev, old_volt, new_volt); } EXPORT_SYMBOL_GPL(regulator_set_voltage_time_sel); diff --git a/drivers/regulator/pwm-regulator.c b/drivers/regulator/pwm-regulator.c index c24524242da2..1b88e0e15a70 100644 --- a/drivers/regulator/pwm-regulator.c +++ b/drivers/regulator/pwm-regulator.c @@ -10,7 +10,6 @@ * published by the Free Software Foundation. */ -#include #include #include #include @@ -194,12 +193,10 @@ static int pwm_regulator_set_voltage(struct regulator_dev *rdev, unsigned int min_uV_duty = drvdata->continuous.min_uV_dutycycle; unsigned int max_uV_duty = drvdata->continuous.max_uV_dutycycle; unsigned int duty_unit = drvdata->continuous.dutycycle_unit; - unsigned int ramp_delay = rdev->constraints->ramp_delay; int min_uV = rdev->constraints->min_uV; int max_uV = rdev->constraints->max_uV; int diff_uV = max_uV - min_uV; struct pwm_state pstate; - int old_uV = pwm_regulator_get_voltage(rdev); unsigned int diff_duty; unsigned int dutycycle; int ret; @@ -233,13 +230,6 @@ static int pwm_regulator_set_voltage(struct regulator_dev *rdev, return ret; } - if ((ramp_delay == 0) || !pwm_regulator_is_enabled(rdev)) - return 0; - - /* Ramp delay is in uV/uS. Adjust to uS and delay */ - ramp_delay = DIV_ROUND_UP(abs(req_min_uV - old_uV), ramp_delay); - usleep_range(ramp_delay, ramp_delay + DIV_ROUND_UP(ramp_delay, 10)); - return 0; } -- cgit v1.2.1 From 8f9165c981fed187bb483de84caf9adf835aefda Mon Sep 17 00:00:00 2001 From: Jan Remmet Date: Fri, 23 Sep 2016 10:52:00 +0200 Subject: regulator: tps65910: Work around silicon erratum SWCZ010 http://www.ti.com/lit/pdf/SWCZ010: DCDC o/p voltage can go higher than programmed value Impact: VDDI, VDD2, and VIO output programmed voltage level can go higher than expected or crash, when coming out of PFM to PWM mode or using DVFS. Description: When DCDC CLK SYNC bits are 11/01: * VIO 3-MHz oscillator is the source clock of the digital core and input clock of VDD1 and VDD2 * Turn-on of VDD1 and VDD2 HSD PFETis synchronized or at a constant phase shift * Current pulled though VCC1+VCC2 is Iload(VDD1) + Iload(VDD2) * The 3 HSD PFET will be turned-on at the same time, causing the highest possible switching noise on the application. This noise level depends on the layout, the VBAT level, and the load current. The noise level increases with improper layout. When DCDC CLK SYNC bits are 00: * VIO 3-MHz oscillator is the source clock of digital core * VDD1 and VDD2 are running on their own 3-MHz oscillator * Current pulled though VCC1+VCC2 average of Iload(VDD1) + Iload(VDD2) * The switching noise of the 3 SMPS will be randomly spread over time, causing lower overall switching noise. Workaround: Set DCDCCTRL_REG[1:0]= 00. Signed-off-by: Jan Remmet Signed-off-by: Mark Brown Cc: stable@vger.kernel.org --- drivers/regulator/tps65910-regulator.c | 6 ++++++ 1 file changed, 6 insertions(+) (limited to 'drivers/regulator') diff --git a/drivers/regulator/tps65910-regulator.c b/drivers/regulator/tps65910-regulator.c index fb991ec76423..696116ebdf50 100644 --- a/drivers/regulator/tps65910-regulator.c +++ b/drivers/regulator/tps65910-regulator.c @@ -1111,6 +1111,12 @@ static int tps65910_probe(struct platform_device *pdev) pmic->num_regulators = ARRAY_SIZE(tps65910_regs); pmic->ext_sleep_control = tps65910_ext_sleep_control; info = tps65910_regs; + /* Work around silicon erratum SWCZ010: output programmed + * voltage level can go higher than expected or crash + * Workaround: use no synchronization of DCDC clocks + */ + tps65910_reg_clear_bits(pmic->mfd, TPS65910_DCDCCTRL, + DCDCCTRL_DCDCCKSYNC_MASK); break; case TPS65911: pmic->get_ctrl_reg = &tps65911_get_ctrl_register; -- cgit v1.2.1 From 577766175c40d4f425be47b9e70d80238e53f996 Mon Sep 17 00:00:00 2001 From: Joonwoo Park Date: Mon, 19 Sep 2016 14:46:54 -0700 Subject: regulator: core: don't return error with inadequate reason drms_uA_update() always returns failure when it cannot find regulator's input voltage. But if hardware supports load configuration with ops->set_load() and the input regulator isn't specified with valid reason such as the input regulator is battery, not finding input voltage is normal so such case should not return with an error. Avoid such inadequate error return by checking input/output voltages only when drms_uA_update() is about to configure load with enum based ops->set_mode(). Cc: Liam Girdwood Cc: Mark Brown Cc: Bjorn Andersson Cc: linux-kernel@vger.kernel.org Signed-off-by: Joonwoo Park Signed-off-by: Mark Brown --- drivers/regulator/core.c | 36 ++++++++++++++++++------------------ 1 file changed, 18 insertions(+), 18 deletions(-) (limited to 'drivers/regulator') diff --git a/drivers/regulator/core.c b/drivers/regulator/core.c index db320e8fa865..bafcdff42872 100644 --- a/drivers/regulator/core.c +++ b/drivers/regulator/core.c @@ -679,24 +679,6 @@ static int drms_uA_update(struct regulator_dev *rdev) !rdev->desc->ops->set_load) return -EINVAL; - /* get output voltage */ - output_uV = _regulator_get_voltage(rdev); - if (output_uV <= 0) { - rdev_err(rdev, "invalid output voltage found\n"); - return -EINVAL; - } - - /* get input voltage */ - input_uV = 0; - if (rdev->supply) - input_uV = regulator_get_voltage(rdev->supply); - if (input_uV <= 0) - input_uV = rdev->constraints->input_uV; - if (input_uV <= 0) { - rdev_err(rdev, "invalid input voltage found\n"); - return -EINVAL; - } - /* calc total requested load */ list_for_each_entry(sibling, &rdev->consumer_list, list) current_uA += sibling->uA_load; @@ -709,6 +691,24 @@ static int drms_uA_update(struct regulator_dev *rdev) if (err < 0) rdev_err(rdev, "failed to set load %d\n", current_uA); } else { + /* get output voltage */ + output_uV = _regulator_get_voltage(rdev); + if (output_uV <= 0) { + rdev_err(rdev, "invalid output voltage found\n"); + return -EINVAL; + } + + /* get input voltage */ + input_uV = 0; + if (rdev->supply) + input_uV = regulator_get_voltage(rdev->supply); + if (input_uV <= 0) + input_uV = rdev->constraints->input_uV; + if (input_uV <= 0) { + rdev_err(rdev, "invalid input voltage found\n"); + return -EINVAL; + } + /* now get the optimum mode for our new total regulator load */ mode = rdev->desc->ops->get_optimum_mode(rdev, input_uV, output_uV, current_uA); -- cgit v1.2.1 From 5ff00f6aa84b7f4203f525fc6c4a4291e32c314d Mon Sep 17 00:00:00 2001 From: Eric Jeong Date: Mon, 26 Sep 2016 16:33:27 +0900 Subject: regulator: pv88080: Update regulator for PV88080 BB silicon support Three files are modified, the driver, header file and the binding document. Updates for the regulator source file include and .of_match_table entry and node match checking in the probe() function for a compatible pv88080 silicon type. A new "HVBUCK" is added in source file and added regsiter definition in header file for pv88080 bb silicion. The binding documentation changes have been made to reflect these updates. Signed-off-by: Eric Jeong Signed-off-by: Mark Brown --- drivers/regulator/pv88080-regulator.c | 263 ++++++++++++++++++++++++++++++---- drivers/regulator/pv88080-regulator.h | 114 +++++++++------ 2 files changed, 304 insertions(+), 73 deletions(-) (limited to 'drivers/regulator') diff --git a/drivers/regulator/pv88080-regulator.c b/drivers/regulator/pv88080-regulator.c index 81950bdb1cc4..954a20eeb26f 100644 --- a/drivers/regulator/pv88080-regulator.c +++ b/drivers/regulator/pv88080-regulator.c @@ -16,6 +16,7 @@ #include #include #include +#include #include #include #include @@ -26,7 +27,7 @@ #include #include "pv88080-regulator.h" -#define PV88080_MAX_REGULATORS 3 +#define PV88080_MAX_REGULATORS 4 /* PV88080 REGULATOR IDs */ enum { @@ -34,6 +35,12 @@ enum { PV88080_ID_BUCK1, PV88080_ID_BUCK2, PV88080_ID_BUCK3, + PV88080_ID_HVBUCK, +}; + +enum pv88080_types { + TYPE_PV88080_AA, + TYPE_PV88080_BA, }; struct pv88080_regulator { @@ -42,7 +49,8 @@ struct pv88080_regulator { unsigned int n_current_limits; const int *current_limits; unsigned int limit_mask; - unsigned int conf; + unsigned int mode_reg; + unsigned int limit_reg; unsigned int conf2; unsigned int conf5; }; @@ -51,6 +59,8 @@ struct pv88080 { struct device *dev; struct regmap *regmap; struct regulator_dev *rdev[PV88080_MAX_REGULATORS]; + unsigned long type; + const struct pv88080_compatible_regmap *regmap_config; }; struct pv88080_buck_voltage { @@ -59,6 +69,30 @@ struct pv88080_buck_voltage { int uV_step; }; +struct pv88080_buck_regmap { + /* REGS */ + int buck_enable_reg; + int buck_vsel_reg; + int buck_mode_reg; + int buck_limit_reg; + int buck_vdac_range_reg; + int buck_vrange_gain_reg; + /* MASKS */ + int buck_enable_mask; + int buck_vsel_mask; + int buck_limit_mask; +}; + +struct pv88080_compatible_regmap { + /* BUCK1, 2, 3 */ + struct pv88080_buck_regmap buck_regmap[PV88080_MAX_REGULATORS-1]; + /* HVBUCK */ + int hvbuck_enable_reg; + int hvbuck_vsel_reg; + int hvbuck_enable_mask; + int hvbuck_vsel_mask; +}; + static const struct regmap_config pv88080_regmap_config = { .reg_bits = 8, .val_bits = 8, @@ -89,13 +123,111 @@ static const struct pv88080_buck_voltage pv88080_buck_vol[2] = { }, }; +static const struct pv88080_compatible_regmap pv88080_aa_regs = { + /* BUCK1 */ + .buck_regmap[0] = { + .buck_enable_reg = PV88080AA_REG_BUCK1_CONF0, + .buck_vsel_reg = PV88080AA_REG_BUCK1_CONF0, + .buck_mode_reg = PV88080AA_REG_BUCK1_CONF1, + .buck_limit_reg = PV88080AA_REG_BUCK1_CONF1, + .buck_vdac_range_reg = PV88080AA_REG_BUCK1_CONF2, + .buck_vrange_gain_reg = PV88080AA_REG_BUCK1_CONF5, + .buck_enable_mask = PV88080_BUCK1_EN, + .buck_vsel_mask = PV88080_VBUCK1_MASK, + .buck_limit_mask = PV88080_BUCK1_ILIM_MASK, + }, + /* BUCK2 */ + .buck_regmap[1] = { + .buck_enable_reg = PV88080AA_REG_BUCK2_CONF0, + .buck_vsel_reg = PV88080AA_REG_BUCK2_CONF0, + .buck_mode_reg = PV88080AA_REG_BUCK2_CONF1, + .buck_limit_reg = PV88080AA_REG_BUCK2_CONF1, + .buck_vdac_range_reg = PV88080AA_REG_BUCK2_CONF2, + .buck_vrange_gain_reg = PV88080AA_REG_BUCK2_CONF5, + .buck_enable_mask = PV88080_BUCK2_EN, + .buck_vsel_mask = PV88080_VBUCK2_MASK, + .buck_limit_mask = PV88080_BUCK2_ILIM_MASK, + }, + /* BUCK3 */ + .buck_regmap[2] = { + .buck_enable_reg = PV88080AA_REG_BUCK3_CONF0, + .buck_vsel_reg = PV88080AA_REG_BUCK3_CONF0, + .buck_mode_reg = PV88080AA_REG_BUCK3_CONF1, + .buck_limit_reg = PV88080AA_REG_BUCK3_CONF1, + .buck_vdac_range_reg = PV88080AA_REG_BUCK3_CONF2, + .buck_vrange_gain_reg = PV88080AA_REG_BUCK3_CONF5, + .buck_enable_mask = PV88080_BUCK3_EN, + .buck_vsel_mask = PV88080_VBUCK3_MASK, + .buck_limit_mask = PV88080_BUCK3_ILIM_MASK, + }, + /* HVBUCK */ + .hvbuck_enable_reg = PV88080AA_REG_HVBUCK_CONF2, + .hvbuck_vsel_reg = PV88080AA_REG_HVBUCK_CONF1, + .hvbuck_enable_mask = PV88080_HVBUCK_EN, + .hvbuck_vsel_mask = PV88080_VHVBUCK_MASK, +}; + +static const struct pv88080_compatible_regmap pv88080_ba_regs = { + /* BUCK1 */ + .buck_regmap[0] = { + .buck_enable_reg = PV88080BA_REG_BUCK1_CONF0, + .buck_vsel_reg = PV88080BA_REG_BUCK1_CONF0, + .buck_mode_reg = PV88080BA_REG_BUCK1_CONF1, + .buck_limit_reg = PV88080BA_REG_BUCK1_CONF1, + .buck_vdac_range_reg = PV88080BA_REG_BUCK1_CONF2, + .buck_vrange_gain_reg = PV88080BA_REG_BUCK1_CONF5, + .buck_enable_mask = PV88080_BUCK1_EN, + .buck_vsel_mask = PV88080_VBUCK1_MASK, + .buck_limit_mask = PV88080_BUCK1_ILIM_MASK, + }, + /* BUCK2 */ + .buck_regmap[1] = { + .buck_enable_reg = PV88080BA_REG_BUCK2_CONF0, + .buck_vsel_reg = PV88080BA_REG_BUCK2_CONF0, + .buck_mode_reg = PV88080BA_REG_BUCK2_CONF1, + .buck_limit_reg = PV88080BA_REG_BUCK2_CONF1, + .buck_vdac_range_reg = PV88080BA_REG_BUCK2_CONF2, + .buck_vrange_gain_reg = PV88080BA_REG_BUCK2_CONF5, + .buck_enable_mask = PV88080_BUCK2_EN, + .buck_vsel_mask = PV88080_VBUCK2_MASK, + .buck_limit_mask = PV88080_BUCK2_ILIM_MASK, + }, + /* BUCK3 */ + .buck_regmap[2] = { + .buck_enable_reg = PV88080BA_REG_BUCK3_CONF0, + .buck_vsel_reg = PV88080BA_REG_BUCK3_CONF0, + .buck_mode_reg = PV88080BA_REG_BUCK3_CONF1, + .buck_limit_reg = PV88080BA_REG_BUCK3_CONF1, + .buck_vdac_range_reg = PV88080BA_REG_BUCK3_CONF2, + .buck_vrange_gain_reg = PV88080BA_REG_BUCK3_CONF5, + .buck_enable_mask = PV88080_BUCK3_EN, + .buck_vsel_mask = PV88080_VBUCK3_MASK, + .buck_limit_mask = PV88080_BUCK3_ILIM_MASK, + }, + /* HVBUCK */ + .hvbuck_enable_reg = PV88080BA_REG_HVBUCK_CONF2, + .hvbuck_vsel_reg = PV88080BA_REG_HVBUCK_CONF1, + .hvbuck_enable_mask = PV88080_HVBUCK_EN, + .hvbuck_vsel_mask = PV88080_VHVBUCK_MASK, +}; + +#ifdef CONFIG_OF +static const struct of_device_id pv88080_dt_ids[] = { + { .compatible = "pvs,pv88080", .data = (void *)TYPE_PV88080_AA }, + { .compatible = "pvs,pv88080-aa", .data = (void *)TYPE_PV88080_AA }, + { .compatible = "pvs,pv88080-ba", .data = (void *)TYPE_PV88080_BA }, + {}, +}; +MODULE_DEVICE_TABLE(of, pv88080_dt_ids); +#endif + static unsigned int pv88080_buck_get_mode(struct regulator_dev *rdev) { struct pv88080_regulator *info = rdev_get_drvdata(rdev); unsigned int data; int ret, mode = 0; - ret = regmap_read(rdev->regmap, info->conf, &data); + ret = regmap_read(rdev->regmap, info->mode_reg, &data); if (ret < 0) return ret; @@ -136,7 +268,7 @@ static int pv88080_buck_set_mode(struct regulator_dev *rdev, return -EINVAL; } - return regmap_update_bits(rdev->regmap, info->conf, + return regmap_update_bits(rdev->regmap, info->mode_reg, PV88080_BUCK1_MODE_MASK, val); } @@ -151,7 +283,7 @@ static int pv88080_set_current_limit(struct regulator_dev *rdev, int min, if (min <= info->current_limits[i] && max >= info->current_limits[i]) { return regmap_update_bits(rdev->regmap, - info->conf, + info->limit_reg, info->limit_mask, i << PV88080_BUCK1_ILIM_SHIFT); } @@ -166,7 +298,7 @@ static int pv88080_get_current_limit(struct regulator_dev *rdev) unsigned int data; int ret; - ret = regmap_read(rdev->regmap, info->conf, &data); + ret = regmap_read(rdev->regmap, info->limit_reg, &data); if (ret < 0) return ret; @@ -187,6 +319,15 @@ static struct regulator_ops pv88080_buck_ops = { .get_current_limit = pv88080_get_current_limit, }; +static struct regulator_ops pv88080_hvbuck_ops = { + .enable = regulator_enable_regmap, + .disable = regulator_disable_regmap, + .is_enabled = regulator_is_enabled_regmap, + .set_voltage_sel = regulator_set_voltage_sel_regmap, + .get_voltage_sel = regulator_get_voltage_sel_regmap, + .list_voltage = regulator_list_voltage_linear, +}; + #define PV88080_BUCK(chip, regl_name, min, step, max, limits_array) \ {\ .desc = {\ @@ -200,17 +341,25 @@ static struct regulator_ops pv88080_buck_ops = { .min_uV = min, \ .uV_step = step, \ .n_voltages = ((max) - (min))/(step) + 1, \ - .enable_reg = PV88080_REG_##regl_name##_CONF0, \ - .enable_mask = PV88080_##regl_name##_EN, \ - .vsel_reg = PV88080_REG_##regl_name##_CONF0, \ - .vsel_mask = PV88080_V##regl_name##_MASK, \ },\ .current_limits = limits_array, \ .n_current_limits = ARRAY_SIZE(limits_array), \ - .limit_mask = PV88080_##regl_name##_ILIM_MASK, \ - .conf = PV88080_REG_##regl_name##_CONF1, \ - .conf2 = PV88080_REG_##regl_name##_CONF2, \ - .conf5 = PV88080_REG_##regl_name##_CONF5, \ +} + +#define PV88080_HVBUCK(chip, regl_name, min, step, max) \ +{\ + .desc = {\ + .id = chip##_ID_##regl_name,\ + .name = __stringify(chip##_##regl_name),\ + .of_match = of_match_ptr(#regl_name),\ + .regulators_node = of_match_ptr("regulators"),\ + .type = REGULATOR_VOLTAGE,\ + .owner = THIS_MODULE,\ + .ops = &pv88080_hvbuck_ops,\ + .min_uV = min, \ + .uV_step = step, \ + .n_voltages = ((max) - (min))/(step) + 1, \ + },\ } static struct pv88080_regulator pv88080_regulator_info[] = { @@ -220,6 +369,7 @@ static struct pv88080_regulator pv88080_regulator_info[] = { pv88080_buck23_limits), PV88080_BUCK(PV88080, BUCK3, 600000, 6250, 1393750, pv88080_buck23_limits), + PV88080_HVBUCK(PV88080, HVBUCK, 0, 5000, 1275000), }; static irqreturn_t pv88080_irq_handler(int irq, void *data) @@ -280,6 +430,8 @@ static int pv88080_i2c_probe(struct i2c_client *i2c, { struct regulator_init_data *init_data = dev_get_platdata(&i2c->dev); struct pv88080 *chip; + const struct pv88080_compatible_regmap *regmap_config; + const struct of_device_id *match; struct regulator_config config = { }; int i, error, ret; unsigned int conf2, conf5; @@ -297,6 +449,17 @@ static int pv88080_i2c_probe(struct i2c_client *i2c, return error; } + if (i2c->dev.of_node) { + match = of_match_node(pv88080_dt_ids, i2c->dev.of_node); + if (!match) { + dev_err(chip->dev, "Failed to get of_match_node\n"); + return -EINVAL; + } + chip->type = (unsigned long)match->data; + } else { + chip->type = id->driver_data; + } + i2c_set_clientdata(i2c, chip); if (i2c->irq != 0) { @@ -336,31 +499,58 @@ static int pv88080_i2c_probe(struct i2c_client *i2c, "Failed to update mask reg: %d\n", ret); return ret; } - } else { dev_warn(chip->dev, "No IRQ configured\n"); } + switch (chip->type) { + case TYPE_PV88080_AA: + chip->regmap_config = &pv88080_aa_regs; + break; + case TYPE_PV88080_BA: + chip->regmap_config = &pv88080_ba_regs; + break; + } + + regmap_config = chip->regmap_config; config.dev = chip->dev; config.regmap = chip->regmap; - for (i = 0; i < PV88080_MAX_REGULATORS; i++) { + /* Registeration for BUCK1, 2, 3 */ + for (i = 0; i < PV88080_MAX_REGULATORS-1; i++) { if (init_data) config.init_data = &init_data[i]; + pv88080_regulator_info[i].limit_reg + = regmap_config->buck_regmap[i].buck_limit_reg; + pv88080_regulator_info[i].limit_mask + = regmap_config->buck_regmap[i].buck_limit_mask; + pv88080_regulator_info[i].mode_reg + = regmap_config->buck_regmap[i].buck_mode_reg; + pv88080_regulator_info[i].conf2 + = regmap_config->buck_regmap[i].buck_vdac_range_reg; + pv88080_regulator_info[i].conf5 + = regmap_config->buck_regmap[i].buck_vrange_gain_reg; + pv88080_regulator_info[i].desc.enable_reg + = regmap_config->buck_regmap[i].buck_enable_reg; + pv88080_regulator_info[i].desc.enable_mask + = regmap_config->buck_regmap[i].buck_enable_mask; + pv88080_regulator_info[i].desc.vsel_reg + = regmap_config->buck_regmap[i].buck_vsel_reg; + pv88080_regulator_info[i].desc.vsel_mask + = regmap_config->buck_regmap[i].buck_vsel_mask; + ret = regmap_read(chip->regmap, - pv88080_regulator_info[i].conf2, &conf2); + pv88080_regulator_info[i].conf2, &conf2); if (ret < 0) return ret; - conf2 = ((conf2 >> PV88080_BUCK_VDAC_RANGE_SHIFT) & PV88080_BUCK_VDAC_RANGE_MASK); ret = regmap_read(chip->regmap, - pv88080_regulator_info[i].conf5, &conf5); + pv88080_regulator_info[i].conf5, &conf5); if (ret < 0) return ret; - conf5 = ((conf5 >> PV88080_BUCK_VRANGE_GAIN_SHIFT) & PV88080_BUCK_VRANGE_GAIN_MASK); @@ -383,23 +573,38 @@ static int pv88080_i2c_probe(struct i2c_client *i2c, } } + pv88080_regulator_info[PV88080_ID_HVBUCK].desc.enable_reg + = regmap_config->hvbuck_enable_reg; + pv88080_regulator_info[PV88080_ID_HVBUCK].desc.enable_mask + = regmap_config->hvbuck_enable_mask; + pv88080_regulator_info[PV88080_ID_HVBUCK].desc.vsel_reg + = regmap_config->hvbuck_vsel_reg; + pv88080_regulator_info[PV88080_ID_HVBUCK].desc.vsel_mask + = regmap_config->hvbuck_vsel_mask; + + /* Registeration for HVBUCK */ + if (init_data) + config.init_data = &init_data[PV88080_ID_HVBUCK]; + + config.driver_data = (void *)&pv88080_regulator_info[PV88080_ID_HVBUCK]; + chip->rdev[PV88080_ID_HVBUCK] = devm_regulator_register(chip->dev, + &pv88080_regulator_info[PV88080_ID_HVBUCK].desc, &config); + if (IS_ERR(chip->rdev[PV88080_ID_HVBUCK])) { + dev_err(chip->dev, "Failed to register PV88080 regulator\n"); + return PTR_ERR(chip->rdev[PV88080_ID_HVBUCK]); + } + return 0; } static const struct i2c_device_id pv88080_i2c_id[] = { - {"pv88080", 0}, + { "pv88080", TYPE_PV88080_AA }, + { "pv88080-aa", TYPE_PV88080_AA }, + { "pv88080-ba", TYPE_PV88080_BA }, {}, }; MODULE_DEVICE_TABLE(i2c, pv88080_i2c_id); -#ifdef CONFIG_OF -static const struct of_device_id pv88080_dt_ids[] = { - { .compatible = "pvs,pv88080", .data = &pv88080_i2c_id[0] }, - {}, -}; -MODULE_DEVICE_TABLE(of, pv88080_dt_ids); -#endif - static struct i2c_driver pv88080_regulator_driver = { .driver = { .name = "pv88080", diff --git a/drivers/regulator/pv88080-regulator.h b/drivers/regulator/pv88080-regulator.h index 5e9afde606f4..ae25ff360e3d 100644 --- a/drivers/regulator/pv88080-regulator.h +++ b/drivers/regulator/pv88080-regulator.h @@ -17,55 +17,75 @@ #define __PV88080_REGISTERS_H__ /* System Control and Event Registers */ -#define PV88080_REG_EVENT_A 0x04 -#define PV88080_REG_MASK_A 0x09 -#define PV88080_REG_MASK_B 0x0a -#define PV88080_REG_MASK_C 0x0b - -/* Regulator Registers */ -#define PV88080_REG_BUCK1_CONF0 0x27 -#define PV88080_REG_BUCK1_CONF1 0x28 -#define PV88080_REG_BUCK1_CONF2 0x59 -#define PV88080_REG_BUCK1_CONF5 0x5c -#define PV88080_REG_BUCK2_CONF0 0x29 -#define PV88080_REG_BUCK2_CONF1 0x2a -#define PV88080_REG_BUCK2_CONF2 0x61 -#define PV88080_REG_BUCK2_CONF5 0x64 -#define PV88080_REG_BUCK3_CONF0 0x2b -#define PV88080_REG_BUCK3_CONF1 0x2c -#define PV88080_REG_BUCK3_CONF2 0x69 -#define PV88080_REG_BUCK3_CONF5 0x6c +#define PV88080_REG_EVENT_A 0x04 +#define PV88080_REG_MASK_A 0x09 +#define PV88080_REG_MASK_B 0x0A +#define PV88080_REG_MASK_C 0x0B + +/* Regulator Registers - rev. AA */ +#define PV88080AA_REG_HVBUCK_CONF1 0x2D +#define PV88080AA_REG_HVBUCK_CONF2 0x2E +#define PV88080AA_REG_BUCK1_CONF0 0x27 +#define PV88080AA_REG_BUCK1_CONF1 0x28 +#define PV88080AA_REG_BUCK1_CONF2 0x59 +#define PV88080AA_REG_BUCK1_CONF5 0x5C +#define PV88080AA_REG_BUCK2_CONF0 0x29 +#define PV88080AA_REG_BUCK2_CONF1 0x2A +#define PV88080AA_REG_BUCK2_CONF2 0x61 +#define PV88080AA_REG_BUCK2_CONF5 0x64 +#define PV88080AA_REG_BUCK3_CONF0 0x2B +#define PV88080AA_REG_BUCK3_CONF1 0x2C +#define PV88080AA_REG_BUCK3_CONF2 0x69 +#define PV88080AA_REG_BUCK3_CONF5 0x6C + +/* Regulator Registers - rev. BA */ +#define PV88080BA_REG_HVBUCK_CONF1 0x33 +#define PV88080BA_REG_HVBUCK_CONF2 0x34 +#define PV88080BA_REG_BUCK1_CONF0 0x2A +#define PV88080BA_REG_BUCK1_CONF1 0x2C +#define PV88080BA_REG_BUCK1_CONF2 0x5A +#define PV88080BA_REG_BUCK1_CONF5 0x5D +#define PV88080BA_REG_BUCK2_CONF0 0x2D +#define PV88080BA_REG_BUCK2_CONF1 0x2F +#define PV88080BA_REG_BUCK2_CONF2 0x63 +#define PV88080BA_REG_BUCK2_CONF5 0x66 +#define PV88080BA_REG_BUCK3_CONF0 0x30 +#define PV88080BA_REG_BUCK3_CONF1 0x32 +#define PV88080BA_REG_BUCK3_CONF2 0x6C +#define PV88080BA_REG_BUCK3_CONF5 0x6F /* PV88080_REG_EVENT_A (addr=0x04) */ #define PV88080_E_VDD_FLT 0x01 -#define PV88080_E_OVER_TEMP 0x02 +#define PV88080_E_OVER_TEMP 0x02 /* PV88080_REG_MASK_A (addr=0x09) */ #define PV88080_M_VDD_FLT 0x01 -#define PV88080_M_OVER_TEMP 0x02 +#define PV88080_M_OVER_TEMP 0x02 -/* PV88080_REG_BUCK1_CONF0 (addr=0x27) */ +/* PV88080_REG_BUCK1_CONF0 (addr=0x27|0x2A) */ #define PV88080_BUCK1_EN 0x80 -#define PV88080_VBUCK1_MASK 0x7F -/* PV88080_REG_BUCK2_CONF0 (addr=0x29) */ +#define PV88080_VBUCK1_MASK 0x7F + +/* PV88080_REG_BUCK2_CONF0 (addr=0x29|0x2D) */ #define PV88080_BUCK2_EN 0x80 -#define PV88080_VBUCK2_MASK 0x7F -/* PV88080_REG_BUCK3_CONF0 (addr=0x2b) */ +#define PV88080_VBUCK2_MASK 0x7F + +/* PV88080_REG_BUCK3_CONF0 (addr=0x2B|0x30) */ #define PV88080_BUCK3_EN 0x80 -#define PV88080_VBUCK3_MASK 0x7F +#define PV88080_VBUCK3_MASK 0x7F -/* PV88080_REG_BUCK1_CONF1 (addr=0x28) */ -#define PV88080_BUCK1_ILIM_SHIFT 2 +/* PV88080_REG_BUCK1_CONF1 (addr=0x28|0x2C) */ +#define PV88080_BUCK1_ILIM_SHIFT 2 #define PV88080_BUCK1_ILIM_MASK 0x0C #define PV88080_BUCK1_MODE_MASK 0x03 -/* PV88080_REG_BUCK2_CONF1 (addr=0x2a) */ -#define PV88080_BUCK2_ILIM_SHIFT 2 +/* PV88080_REG_BUCK2_CONF1 (addr=0x2A|0x2F) */ +#define PV88080_BUCK2_ILIM_SHIFT 2 #define PV88080_BUCK2_ILIM_MASK 0x0C #define PV88080_BUCK2_MODE_MASK 0x03 -/* PV88080_REG_BUCK3_CONF1 (addr=0x2c) */ -#define PV88080_BUCK3_ILIM_SHIFT 2 +/* PV88080_REG_BUCK3_CONF1 (addr=0x2C|0x32) */ +#define PV88080_BUCK3_ILIM_SHIFT 2 #define PV88080_BUCK3_ILIM_MASK 0x0C #define PV88080_BUCK3_MODE_MASK 0x03 @@ -73,20 +93,26 @@ #define PV88080_BUCK_MODE_AUTO 0x01 #define PV88080_BUCK_MODE_SYNC 0x02 -/* PV88080_REG_BUCK2_CONF2 (addr=0x61) */ -/* PV88080_REG_BUCK3_CONF2 (addr=0x69) */ -#define PV88080_BUCK_VDAC_RANGE_SHIFT 7 -#define PV88080_BUCK_VDAC_RANGE_MASK 0x01 +/* PV88080_REG_HVBUCK_CONF1 (addr=0x2D|0x33) */ +#define PV88080_VHVBUCK_MASK 0xFF + +/* PV88080_REG_HVBUCK_CONF1 (addr=0x2E|0x34) */ +#define PV88080_HVBUCK_EN 0x01 + +/* PV88080_REG_BUCK2_CONF2 (addr=0x61|0x63) */ +/* PV88080_REG_BUCK3_CONF2 (addr=0x69|0x6C) */ +#define PV88080_BUCK_VDAC_RANGE_SHIFT 7 +#define PV88080_BUCK_VDAC_RANGE_MASK 0x01 -#define PV88080_BUCK_VDAC_RANGE_1 0x00 -#define PV88080_BUCK_VDAC_RANGE_2 0x01 +#define PV88080_BUCK_VDAC_RANGE_1 0x00 +#define PV88080_BUCK_VDAC_RANGE_2 0x01 -/* PV88080_REG_BUCK2_CONF5 (addr=0x64) */ -/* PV88080_REG_BUCK3_CONF5 (addr=0x6c) */ -#define PV88080_BUCK_VRANGE_GAIN_SHIFT 0 -#define PV88080_BUCK_VRANGE_GAIN_MASK 0x01 +/* PV88080_REG_BUCK2_CONF5 (addr=0x64|0x66) */ +/* PV88080_REG_BUCK3_CONF5 (addr=0x6C|0x6F) */ +#define PV88080_BUCK_VRANGE_GAIN_SHIFT 0 +#define PV88080_BUCK_VRANGE_GAIN_MASK 0x01 -#define PV88080_BUCK_VRANGE_GAIN_1 0x00 -#define PV88080_BUCK_VRANGE_GAIN_2 0x01 +#define PV88080_BUCK_VRANGE_GAIN_1 0x00 +#define PV88080_BUCK_VRANGE_GAIN_2 0x01 #endif /* __PV88080_REGISTERS_H__ */ -- cgit v1.2.1 From 5258beedc30a72b0c21521aa531ed26ad45cb3f7 Mon Sep 17 00:00:00 2001 From: Baoyou Xie Date: Fri, 23 Sep 2016 20:47:22 +0800 Subject: regulator: dbx500: remove unused functions in dbx500-prcmu.c We get 2 warnings when building kernel with W=1: drivers/regulator/dbx500-prcmu.c:78:6: warning: no previous prototype for 'ux500_regulator_suspend_debug' [-Wmissing-prototypes] drivers/regulator/dbx500-prcmu.c:87:6: warning: no previous prototype for 'ux500_regulator_resume_debug' [-Wmissing-prototypes] In fact, these functions are unused in dbx500-prcmu.c, but should be removed. So this patch removes the unused functions. Signed-off-by: Baoyou Xie Acked-by: Arnd Bergmann Signed-off-by: Mark Brown --- drivers/regulator/dbx500-prcmu.c | 18 ------------------ 1 file changed, 18 deletions(-) (limited to 'drivers/regulator') diff --git a/drivers/regulator/dbx500-prcmu.c b/drivers/regulator/dbx500-prcmu.c index 3963dfad766c..8976141c1438 100644 --- a/drivers/regulator/dbx500-prcmu.c +++ b/drivers/regulator/dbx500-prcmu.c @@ -75,24 +75,6 @@ static struct ux500_regulator_debug { u8 *state_after_suspend; } rdebug; -void ux500_regulator_suspend_debug(void) -{ - int i; - - for (i = 0; i < rdebug.num_regulators; i++) - rdebug.state_before_suspend[i] = - rdebug.regulator_array[i].is_enabled; -} - -void ux500_regulator_resume_debug(void) -{ - int i; - - for (i = 0; i < rdebug.num_regulators; i++) - rdebug.state_after_suspend[i] = - rdebug.regulator_array[i].is_enabled; -} - static int ux500_regulator_power_state_cnt_print(struct seq_file *s, void *p) { /* print power state count */ -- cgit v1.2.1 From 0e70f466fb910ae54c4c71243b99385129e93feb Mon Sep 17 00:00:00 2001 From: Srinivas Pandruvada Date: Fri, 26 Aug 2016 16:21:16 -0700 Subject: thermal: Enhance thermal_zone_device_update for events Added one additional parameter to thermal_zone_device_update() to provide caller with an optional capability to specify reason. Currently this event is used by user space governor to trigger different processing based on event code. Also it saves an additional call to read temperature when the event is received. The following events are cuurently defined: - Unspecified event - New temperature sample - Trip point violated - Trip point changed - thermal device up and down - thermal device power capability changed Signed-off-by: Srinivas Pandruvada Signed-off-by: Zhang Rui --- drivers/regulator/max8973-regulator.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'drivers/regulator') diff --git a/drivers/regulator/max8973-regulator.c b/drivers/regulator/max8973-regulator.c index 3958f50c5975..e0c747aa9f85 100644 --- a/drivers/regulator/max8973-regulator.c +++ b/drivers/regulator/max8973-regulator.c @@ -495,7 +495,8 @@ static irqreturn_t max8973_thermal_irq(int irq, void *data) { struct max8973_chip *mchip = data; - thermal_zone_device_update(mchip->tz_device); + thermal_zone_device_update(mchip->tz_device, + THERMAL_EVENT_UNSPECIFIED); return IRQ_HANDLED; } -- cgit v1.2.1 From 1b5b42216469b05ef4b5916cb40b127dfab1da88 Mon Sep 17 00:00:00 2001 From: Axel Haslam Date: Thu, 3 Nov 2016 12:11:42 +0100 Subject: regulator: core: Add new API to poll for error conditions Regulator consumers can receive event notifications when errors are reported to the driver, but currently, there is no way for a regulator consumer to know when the error is over. To allow a regulator consumer to poll for error conditions add a new API: regulator_get_error_flags. Signed-off-by: Axel Haslam Signed-off-by: Mark Brown --- drivers/regulator/core.c | 33 +++++++++++++++++++++++++++++++++ 1 file changed, 33 insertions(+) (limited to 'drivers/regulator') diff --git a/drivers/regulator/core.c b/drivers/regulator/core.c index 67426c0477d3..08260c215895 100644 --- a/drivers/regulator/core.c +++ b/drivers/regulator/core.c @@ -3359,6 +3359,39 @@ unsigned int regulator_get_mode(struct regulator *regulator) } EXPORT_SYMBOL_GPL(regulator_get_mode); +static int _regulator_get_error_flags(struct regulator_dev *rdev, + unsigned int *flags) +{ + int ret; + + mutex_lock(&rdev->mutex); + + /* sanity check */ + if (!rdev->desc->ops->get_error_flags) { + ret = -EINVAL; + goto out; + } + + ret = rdev->desc->ops->get_error_flags(rdev, flags); +out: + mutex_unlock(&rdev->mutex); + return ret; +} + +/** + * regulator_get_error_flags - get regulator error information + * @regulator: regulator source + * @flags: pointer to store error flags + * + * Get the current regulator error information. + */ +int regulator_get_error_flags(struct regulator *regulator, + unsigned int *flags) +{ + return _regulator_get_error_flags(regulator->rdev, flags); +} +EXPORT_SYMBOL_GPL(regulator_get_error_flags); + /** * regulator_set_load - set regulator load * @regulator: regulator source -- cgit v1.2.1