From 7b36ddb208bd1744f4769f11e530bc08c3701964 Mon Sep 17 00:00:00 2001 From: ChiYuan Huang Date: Sat, 26 Mar 2022 19:39:48 +0800 Subject: regulator: rt5759: Add support for Richtek RT5759 DCDC converter Add support for Richtek RT5759 high-performance DCDC converter. Signed-off-by: ChiYuan Huang Link: https://lore.kernel.org/r/1648294788-11758-3-git-send-email-u0084500@gmail.com Signed-off-by: Mark Brown --- drivers/regulator/Kconfig | 10 + drivers/regulator/Makefile | 1 + drivers/regulator/rt5759-regulator.c | 369 +++++++++++++++++++++++++++++++++++ 3 files changed, 380 insertions(+) create mode 100644 drivers/regulator/rt5759-regulator.c (limited to 'drivers') diff --git a/drivers/regulator/Kconfig b/drivers/regulator/Kconfig index 5ef2306fce04..a7effc57bbdb 100644 --- a/drivers/regulator/Kconfig +++ b/drivers/regulator/Kconfig @@ -1057,6 +1057,16 @@ config REGULATOR_RT5190A buck converters, 1 LDO, mute AC OFF depop function, with the general I2C control interface. +config REGULATOR_RT5759 + tristate "Richtek RT5759 Regulator" + depends on I2C + select REGMAP_I2C + help + This adds support for voltage regulator in Richtek RT5759. + The RT5759 is a high-performance, synchronous step-down DC-DC + converter that can deliver up to 9A output current from 3V to 6.5V + input supply. + config REGULATOR_RT6160 tristate "Richtek RT6160 BuckBoost voltage regulator" depends on I2C diff --git a/drivers/regulator/Makefile b/drivers/regulator/Makefile index 1b64ad5767be..69b5a196acd2 100644 --- a/drivers/regulator/Makefile +++ b/drivers/regulator/Makefile @@ -127,6 +127,7 @@ obj-$(CONFIG_REGULATOR_RT4801) += rt4801-regulator.o obj-$(CONFIG_REGULATOR_RT4831) += rt4831-regulator.o obj-$(CONFIG_REGULATOR_RT5033) += rt5033-regulator.o obj-$(CONFIG_REGULATOR_RT5190A) += rt5190a-regulator.o +obj-$(CONFIG_REGULATOR_RT5759) += rt5759-regulator.o obj-$(CONFIG_REGULATOR_RT6160) += rt6160-regulator.o obj-$(CONFIG_REGULATOR_RT6245) += rt6245-regulator.o obj-$(CONFIG_REGULATOR_RTMV20) += rtmv20-regulator.o diff --git a/drivers/regulator/rt5759-regulator.c b/drivers/regulator/rt5759-regulator.c new file mode 100644 index 000000000000..6b96899eb27e --- /dev/null +++ b/drivers/regulator/rt5759-regulator.c @@ -0,0 +1,369 @@ +// SPDX-License-Identifier: GPL-2.0+ + +#include +#include +#include +#include +#include +#include +#include +#include + +#define RT5759_REG_VENDORINFO 0x00 +#define RT5759_REG_FREQ 0x01 +#define RT5759_REG_VSEL 0x02 +#define RT5759_REG_DCDCCTRL 0x03 +#define RT5759_REG_STATUS 0x04 +#define RT5759_REG_DCDCSET 0x05 +#define RT5759A_REG_WDTEN 0x42 + +#define RT5759_TSTEP_MASK GENMASK(3, 2) +#define RT5759_VSEL_MASK GENMASK(6, 0) +#define RT5759_DISCHARGE_MASK BIT(3) +#define RT5759_FPWM_MASK BIT(2) +#define RT5759_ENABLE_MASK BIT(1) +#define RT5759_OT_MASK BIT(1) +#define RT5759_UV_MASK BIT(0) +#define RT5957_OCLVL_MASK GENMASK(7, 6) +#define RT5759_OCLVL_SHIFT 6 +#define RT5957_OTLVL_MASK GENMASK(5, 4) +#define RT5759_OTLVL_SHIFT 4 +#define RT5759A_WDTEN_MASK BIT(1) + +#define RT5759_MANUFACTURER_ID 0x82 +/* vsel range 0x00 ~ 0x5A */ +#define RT5759_NUM_VOLTS 91 +#define RT5759_MIN_UV 600000 +#define RT5759_STEP_UV 10000 +#define RT5759A_STEP_UV 12500 +#define RT5759_MINSS_TIMEUS 1500 + +#define RT5759_PSKIP_MODE 0 +#define RT5759_FPWM_MODE 1 + +enum { + CHIP_TYPE_RT5759 = 0, + CHIP_TYPE_RT5759A, + CHIP_TYPE_MAX +}; + +struct rt5759_priv { + struct device *dev; + struct regmap *regmap; + struct regulator_desc desc; + unsigned long chip_type; +}; + +static int rt5759_set_mode(struct regulator_dev *rdev, unsigned int mode) +{ + struct regmap *regmap = rdev_get_regmap(rdev); + unsigned int mode_val; + + switch (mode) { + case REGULATOR_MODE_NORMAL: + mode_val = 0; + break; + case REGULATOR_MODE_FAST: + mode_val = RT5759_FPWM_MASK; + break; + default: + return -EINVAL; + } + + return regmap_update_bits(regmap, RT5759_REG_STATUS, RT5759_FPWM_MASK, + mode_val); +} + +static unsigned int rt5759_get_mode(struct regulator_dev *rdev) +{ + struct regmap *regmap = rdev_get_regmap(rdev); + unsigned int regval; + int ret; + + ret = regmap_read(regmap, RT5759_REG_DCDCCTRL, ®val); + if (ret) + return REGULATOR_MODE_INVALID; + + if (regval & RT5759_FPWM_MASK) + return REGULATOR_MODE_FAST; + + return REGULATOR_MODE_NORMAL; +} + +static int rt5759_get_error_flags(struct regulator_dev *rdev, + unsigned int *flags) +{ + struct regmap *regmap = rdev_get_regmap(rdev); + unsigned int status, events = 0; + int ret; + + ret = regmap_read(regmap, RT5759_REG_STATUS, &status); + if (ret) + return ret; + + if (status & RT5759_OT_MASK) + events |= REGULATOR_ERROR_OVER_TEMP; + + if (status & RT5759_UV_MASK) + events |= REGULATOR_ERROR_UNDER_VOLTAGE; + + *flags = events; + return 0; +} + +static int rt5759_set_ocp(struct regulator_dev *rdev, int lim_uA, int severity, + bool enable) +{ + struct regmap *regmap = rdev_get_regmap(rdev); + int ocp_lvl[] = { 9800000, 10800000, 11800000 }; + unsigned int ocp_regval; + int i; + + /* Only support over current protection parameter */ + if (severity != REGULATOR_SEVERITY_PROT) + return 0; + + if (enable) { + /* Default ocp level is 10.8A */ + if (lim_uA == 0) + lim_uA = 10800000; + + for (i = 0; i < ARRAY_SIZE(ocp_lvl); i++) { + if (lim_uA <= ocp_lvl[i]) + break; + } + + if (i == ARRAY_SIZE(ocp_lvl)) + i = ARRAY_SIZE(ocp_lvl) - 1; + + ocp_regval = i + 1; + } else + ocp_regval = 0; + + return regmap_update_bits(regmap, RT5759_REG_DCDCSET, RT5957_OCLVL_MASK, + ocp_regval << RT5759_OCLVL_SHIFT); +} + +static int rt5759_set_otp(struct regulator_dev *rdev, int lim, int severity, + bool enable) +{ + struct regmap *regmap = rdev_get_regmap(rdev); + int otp_lvl[] = { 140, 150, 170 }; + unsigned int otp_regval; + int i; + + /* Only support over temperature protection parameter */ + if (severity != REGULATOR_SEVERITY_PROT) + return 0; + + if (enable) { + /* Default otp level is 150'c */ + if (lim == 0) + lim = 150; + + for (i = 0; i < ARRAY_SIZE(otp_lvl); i++) { + if (lim <= otp_lvl[i]) + break; + } + + if (i == ARRAY_SIZE(otp_lvl)) + i = ARRAY_SIZE(otp_lvl) - 1; + + otp_regval = i + 1; + } else + otp_regval = 0; + + return regmap_update_bits(regmap, RT5759_REG_DCDCSET, RT5957_OTLVL_MASK, + otp_regval << RT5759_OTLVL_SHIFT); +} + +static const struct regulator_ops rt5759_regulator_ops = { + .list_voltage = regulator_list_voltage_linear, + .set_voltage_sel = regulator_set_voltage_sel_regmap, + .get_voltage_sel = regulator_get_voltage_sel_regmap, + .enable = regulator_enable_regmap, + .disable = regulator_disable_regmap, + .is_enabled = regulator_is_enabled_regmap, + .set_active_discharge = regulator_set_active_discharge_regmap, + .set_mode = rt5759_set_mode, + .get_mode = rt5759_get_mode, + .set_ramp_delay = regulator_set_ramp_delay_regmap, + .get_error_flags = rt5759_get_error_flags, + .set_over_current_protection = rt5759_set_ocp, + .set_thermal_protection = rt5759_set_otp, +}; + +static unsigned int rt5759_of_map_mode(unsigned int mode) +{ + switch (mode) { + case RT5759_FPWM_MODE: + return REGULATOR_MODE_FAST; + case RT5759_PSKIP_MODE: + return REGULATOR_MODE_NORMAL; + default: + return REGULATOR_MODE_INVALID; + } +} + +static const unsigned int rt5759_ramp_table[] = { 20000, 15000, 10000, 5000 }; + +static int rt5759_regulator_register(struct rt5759_priv *priv) +{ + struct device_node *np = priv->dev->of_node; + struct regulator_desc *reg_desc = &priv->desc; + struct regulator_config reg_cfg; + struct regulator_dev *rdev; + int ret; + + reg_desc->name = "rt5759-buck"; + reg_desc->type = REGULATOR_VOLTAGE; + reg_desc->owner = THIS_MODULE; + reg_desc->ops = &rt5759_regulator_ops; + reg_desc->n_voltages = RT5759_NUM_VOLTS; + reg_desc->min_uV = RT5759_MIN_UV; + reg_desc->uV_step = RT5759_STEP_UV; + reg_desc->vsel_reg = RT5759_REG_VSEL; + reg_desc->vsel_mask = RT5759_VSEL_MASK; + reg_desc->enable_reg = RT5759_REG_DCDCCTRL; + reg_desc->enable_mask = RT5759_ENABLE_MASK; + reg_desc->active_discharge_reg = RT5759_REG_DCDCCTRL; + reg_desc->active_discharge_mask = RT5759_DISCHARGE_MASK; + reg_desc->active_discharge_on = RT5759_DISCHARGE_MASK; + reg_desc->ramp_reg = RT5759_REG_FREQ; + reg_desc->ramp_mask = RT5759_TSTEP_MASK; + reg_desc->ramp_delay_table = rt5759_ramp_table; + reg_desc->n_ramp_values = ARRAY_SIZE(rt5759_ramp_table); + reg_desc->enable_time = RT5759_MINSS_TIMEUS; + reg_desc->of_map_mode = rt5759_of_map_mode; + + /* + * RT5759 step uV = 10000 + * RT5759A step uV = 12500 + */ + if (priv->chip_type == CHIP_TYPE_RT5759A) + reg_desc->uV_step = RT5759A_STEP_UV; + + reg_cfg.dev = priv->dev; + reg_cfg.of_node = np; + reg_cfg.init_data = of_get_regulator_init_data(priv->dev, np, reg_desc); + reg_cfg.regmap = priv->regmap; + + rdev = devm_regulator_register(priv->dev, reg_desc, ®_cfg); + if (IS_ERR(rdev)) { + ret = PTR_ERR(rdev); + dev_err(priv->dev, "Failed to register regulator (%d)\n", ret); + return ret; + } + + return 0; +} + +static int rt5759_init_device_property(struct rt5759_priv *priv) +{ + unsigned int val = 0; + + /* + * Only RT5759A support external watchdog input + */ + if (priv->chip_type != CHIP_TYPE_RT5759A) + return 0; + + if (device_property_read_bool(priv->dev, "richtek,watchdog-enable")) + val = RT5759A_WDTEN_MASK; + + return regmap_update_bits(priv->regmap, RT5759A_REG_WDTEN, + RT5759A_WDTEN_MASK, val); +} + +static int rt5759_manufacturer_check(struct rt5759_priv *priv) +{ + unsigned int vendor; + int ret; + + ret = regmap_read(priv->regmap, RT5759_REG_VENDORINFO, &vendor); + if (ret) + return ret; + + if (vendor != RT5759_MANUFACTURER_ID) { + dev_err(priv->dev, "vendor info not correct (%d)\n", vendor); + return -EINVAL; + } + + return 0; +} + +static bool rt5759_is_accessible_reg(struct device *dev, unsigned int reg) +{ + struct rt5759_priv *priv = dev_get_drvdata(dev); + + if (reg <= RT5759_REG_DCDCSET) + return true; + + if (priv->chip_type == CHIP_TYPE_RT5759A && reg == RT5759A_REG_WDTEN) + return true; + + return false; +} + +static const struct regmap_config rt5759_regmap_config = { + .reg_bits = 8, + .val_bits = 8, + .max_register = RT5759A_REG_WDTEN, + .readable_reg = rt5759_is_accessible_reg, + .writeable_reg = rt5759_is_accessible_reg, +}; + +static int rt5759_probe(struct i2c_client *i2c) +{ + struct rt5759_priv *priv; + int ret; + + priv = devm_kzalloc(&i2c->dev, sizeof(*priv), GFP_KERNEL); + if (!priv) + return -ENOMEM; + + priv->dev = &i2c->dev; + priv->chip_type = (unsigned long)of_device_get_match_data(&i2c->dev); + i2c_set_clientdata(i2c, priv); + + priv->regmap = devm_regmap_init_i2c(i2c, &rt5759_regmap_config); + if (IS_ERR(priv->regmap)) { + ret = PTR_ERR(priv->regmap); + dev_err(&i2c->dev, "Failed to allocate regmap (%d)\n", ret); + return ret; + } + + ret = rt5759_manufacturer_check(priv); + if (ret) { + dev_err(&i2c->dev, "Failed to check device (%d)\n", ret); + return ret; + } + + ret = rt5759_init_device_property(priv); + if (ret) { + dev_err(&i2c->dev, "Failed to init device (%d)\n", ret); + return ret; + } + + return rt5759_regulator_register(priv); +} + +static const struct of_device_id __maybe_unused rt5759_device_table[] = { + { .compatible = "richtek,rt5759", .data = (void *)CHIP_TYPE_RT5759 }, + { .compatible = "richtek,rt5759a", .data = (void *)CHIP_TYPE_RT5759A }, + {} +}; +MODULE_DEVICE_TABLE(of, rt5759_device_table); + +static struct i2c_driver rt5759_driver = { + .driver = { + .name = "rt5759", + .of_match_table = of_match_ptr(rt5759_device_table), + }, + .probe_new = rt5759_probe, +}; +module_i2c_driver(rt5759_driver); + +MODULE_AUTHOR("ChiYuan Huang "); +MODULE_DESCRIPTION("Richtek RT5759 Regulator Driver"); +MODULE_LICENSE("GPL v2"); -- cgit v1.2.3 From 6c315afe65d05dc6eebf2d6b73a191990aada218 Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Thu, 24 Mar 2022 20:18:54 +0000 Subject: regulator: fixed: Remove print on allocation failure OOMs are very verbose, we don't need to print an additional error message when we fail to allocate. Signed-off-by: Mark Brown Link: https://lore.kernel.org/r/20220324201854.3107077-1-broonie@kernel.org Signed-off-by: Mark Brown --- drivers/regulator/fixed.c | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/regulator/fixed.c b/drivers/regulator/fixed.c index 599ad201dca7..2a9867abba20 100644 --- a/drivers/regulator/fixed.c +++ b/drivers/regulator/fixed.c @@ -236,11 +236,8 @@ static int reg_fixed_voltage_probe(struct platform_device *pdev) drvdata->desc.supply_name = devm_kstrdup(&pdev->dev, config->input_supply, GFP_KERNEL); - if (!drvdata->desc.supply_name) { - dev_err(&pdev->dev, - "Failed to allocate input supply\n"); + if (!drvdata->desc.supply_name) return -ENOMEM; - } } if (config->microvolts) -- cgit v1.2.3 From 261f06315cf7c3744731e36bfd8d4434949e3389 Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Fri, 25 Mar 2022 14:46:37 +0000 Subject: regulator: Flag uncontrollable regulators as always_on While we currently assume that regulators with no control available are just uncontionally enabled this isn't always as clearly displayed to users as is desirable, for example the code for disabling unused regulators will log that it is about to disable them. Clean this up a bit by setting always_on during constraint evaluation if we have no available mechanism for controlling the regualtor so things that check the constraint will do the right thing. Signed-off-by: Mark Brown Link: https://lore.kernel.org/r/20220325144637.1543496-1-broonie@kernel.org Signed-off-by: Mark Brown --- drivers/regulator/core.c | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) (limited to 'drivers') diff --git a/drivers/regulator/core.c b/drivers/regulator/core.c index d2553970a67b..a8a95d09ca11 100644 --- a/drivers/regulator/core.c +++ b/drivers/regulator/core.c @@ -1522,6 +1522,24 @@ static int set_machine_constraints(struct regulator_dev *rdev) } } + /* + * If there is no mechanism for controlling the regulator then + * flag it as always_on so we don't end up duplicating checks + * for this so much. Note that we could control the state of + * a supply to control the output on a regulator that has no + * direct control. + */ + if (!rdev->ena_pin && !ops->enable) { + if (rdev->supply_name && !rdev->supply) + return -EPROBE_DEFER; + + if (rdev->supply) + rdev->constraints->always_on = + rdev->supply->rdev->constraints->always_on; + else + rdev->constraints->always_on = true; + } + /* If the constraints say the regulator should be on at this point * and we have control then make sure it is enabled. */ -- cgit v1.2.3 From f0e3c6261af183f0c2246cfe691abec78377622c Mon Sep 17 00:00:00 2001 From: Johnson Wang Date: Fri, 1 Apr 2022 16:02:11 +0800 Subject: regulator: mt6366: Add support for MT6366 regulator The MT6366 is a regulator found on boards based on MediaTek MT8186 and probably other SoCs. It is a so called pmic and connects as a slave to SoC using SPI, wrapped inside the pmic-wrapper. Reviewed-by: AngeloGioacchino Del Regno Signed-off-by: Johnson Wang Link: https://lore.kernel.org/r/20220401080212.27383-2-johnson.wang@mediatek.com Signed-off-by: Mark Brown --- drivers/regulator/mt6358-regulator.c | 213 ++++++++++++++++++++++++++++- include/linux/regulator/mt6358-regulator.h | 45 ++++++ 2 files changed, 253 insertions(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/regulator/mt6358-regulator.c b/drivers/regulator/mt6358-regulator.c index eb8027813b99..8a5ce990f1bf 100644 --- a/drivers/regulator/mt6358-regulator.c +++ b/drivers/regulator/mt6358-regulator.c @@ -130,6 +130,102 @@ struct mt6358_regulator_info { .qi = BIT(15), \ } +#define MT6366_BUCK(match, vreg, min, max, step, \ + volt_ranges, vosel_mask, _da_vsel_reg, _da_vsel_mask, \ + _modeset_reg, _modeset_shift) \ +[MT6366_ID_##vreg] = { \ + .desc = { \ + .name = #vreg, \ + .of_match = of_match_ptr(match), \ + .ops = &mt6358_volt_range_ops, \ + .type = REGULATOR_VOLTAGE, \ + .id = MT6366_ID_##vreg, \ + .owner = THIS_MODULE, \ + .n_voltages = ((max) - (min)) / (step) + 1, \ + .linear_ranges = volt_ranges, \ + .n_linear_ranges = ARRAY_SIZE(volt_ranges), \ + .vsel_reg = MT6358_BUCK_##vreg##_ELR0, \ + .vsel_mask = vosel_mask, \ + .enable_reg = MT6358_BUCK_##vreg##_CON0, \ + .enable_mask = BIT(0), \ + .of_map_mode = mt6358_map_mode, \ + }, \ + .status_reg = MT6358_BUCK_##vreg##_DBG1, \ + .qi = BIT(0), \ + .da_vsel_reg = _da_vsel_reg, \ + .da_vsel_mask = _da_vsel_mask, \ + .modeset_reg = _modeset_reg, \ + .modeset_mask = BIT(_modeset_shift), \ +} + +#define MT6366_LDO(match, vreg, ldo_volt_table, \ + ldo_index_table, enreg, enbit, vosel, \ + vosel_mask) \ +[MT6366_ID_##vreg] = { \ + .desc = { \ + .name = #vreg, \ + .of_match = of_match_ptr(match), \ + .ops = &mt6358_volt_table_ops, \ + .type = REGULATOR_VOLTAGE, \ + .id = MT6366_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), \ + }, \ + .status_reg = MT6358_LDO_##vreg##_CON1, \ + .qi = BIT(15), \ + .index_table = ldo_index_table, \ + .n_table = ARRAY_SIZE(ldo_index_table), \ +} + +#define MT6366_LDO1(match, vreg, min, max, step, \ + volt_ranges, _da_vsel_reg, _da_vsel_mask, \ + vosel, vosel_mask) \ +[MT6366_ID_##vreg] = { \ + .desc = { \ + .name = #vreg, \ + .of_match = of_match_ptr(match), \ + .ops = &mt6358_volt_range_ops, \ + .type = REGULATOR_VOLTAGE, \ + .id = MT6366_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 = MT6358_LDO_##vreg##_CON0, \ + .enable_mask = BIT(0), \ + }, \ + .da_vsel_reg = _da_vsel_reg, \ + .da_vsel_mask = _da_vsel_mask, \ + .status_reg = MT6358_LDO_##vreg##_DBG1, \ + .qi = BIT(0), \ +} + +#define MT6366_REG_FIXED(match, vreg, \ + enreg, enbit, volt) \ +[MT6366_ID_##vreg] = { \ + .desc = { \ + .name = #vreg, \ + .of_match = of_match_ptr(match), \ + .ops = &mt6358_volt_fixed_ops, \ + .type = REGULATOR_VOLTAGE, \ + .id = MT6366_ID_##vreg, \ + .owner = THIS_MODULE, \ + .n_voltages = 1, \ + .enable_reg = enreg, \ + .enable_mask = BIT(enbit), \ + .min_uV = volt, \ + }, \ + .status_reg = MT6358_LDO_##vreg##_CON1, \ + .qi = BIT(15), \ +} + static const struct linear_range buck_volt_range1[] = { REGULATOR_LINEAR_RANGE(500000, 0, 0x7f, 6250), }; @@ -409,6 +505,9 @@ static struct mt6358_regulator_info mt6358_regulators[] = { MT6358_BUCK("buck_vcore", VCORE, 500000, 1293750, 6250, buck_volt_range1, 0x7f, MT6358_BUCK_VCORE_DBG0, 0x7f, MT6358_VCORE_VGPU_ANA_CON0, 1), + MT6358_BUCK("buck_vcore_sshub", VCORE_SSHUB, 500000, 1293750, 6250, + buck_volt_range1, 0x7f, MT6358_BUCK_VCORE_SSHUB_ELR0, 0x7f, + MT6358_VCORE_VGPU_ANA_CON0, 1), MT6358_BUCK("buck_vpa", VPA, 500000, 3650000, 50000, buck_volt_range3, 0x3f, MT6358_BUCK_VPA_DBG0, 0x3f, MT6358_VPA_ANA_CON0, 3), @@ -488,6 +587,10 @@ static struct mt6358_regulator_info mt6358_regulators[] = { MT6358_LDO1("ldo_vsram_others", VSRAM_OTHERS, 500000, 1293750, 6250, buck_volt_range1, MT6358_LDO_VSRAM_OTHERS_DBG0, 0x7f00, MT6358_LDO_VSRAM_CON2, 0x7f), + MT6358_LDO1("ldo_vsram_others_sshub", VSRAM_OTHERS_SSHUB, 500000, + 1293750, 6250, buck_volt_range1, + MT6358_LDO_VSRAM_OTHERS_SSHUB_CON1, 0x7f, + MT6358_LDO_VSRAM_OTHERS_SSHUB_CON1, 0x7f), MT6358_LDO1("ldo_vsram_gpu", VSRAM_GPU, 500000, 1293750, 6250, buck_volt_range1, MT6358_LDO_VSRAM_GPU_DBG0, 0x7f00, MT6358_LDO_VSRAM_CON3, 0x7f), @@ -496,24 +599,124 @@ static struct mt6358_regulator_info mt6358_regulators[] = { MT6358_LDO_VSRAM_CON1, 0x7f), }; +/* The array is indexed by id(MT6366_ID_XXX) */ +static struct mt6358_regulator_info mt6366_regulators[] = { + MT6366_BUCK("buck_vdram1", VDRAM1, 500000, 2087500, 12500, + buck_volt_range2, 0x7f, MT6358_BUCK_VDRAM1_DBG0, 0x7f, + MT6358_VDRAM1_ANA_CON0, 8), + MT6366_BUCK("buck_vcore", VCORE, 500000, 1293750, 6250, + buck_volt_range1, 0x7f, MT6358_BUCK_VCORE_DBG0, 0x7f, + MT6358_VCORE_VGPU_ANA_CON0, 1), + MT6366_BUCK("buck_vcore_sshub", VCORE_SSHUB, 500000, 1293750, 6250, + buck_volt_range1, 0x7f, MT6358_BUCK_VCORE_SSHUB_ELR0, 0x7f, + MT6358_VCORE_VGPU_ANA_CON0, 1), + MT6366_BUCK("buck_vpa", VPA, 500000, 3650000, 50000, + buck_volt_range3, 0x3f, MT6358_BUCK_VPA_DBG0, 0x3f, + MT6358_VPA_ANA_CON0, 3), + MT6366_BUCK("buck_vproc11", VPROC11, 500000, 1293750, 6250, + buck_volt_range1, 0x7f, MT6358_BUCK_VPROC11_DBG0, 0x7f, + MT6358_VPROC_ANA_CON0, 1), + MT6366_BUCK("buck_vproc12", VPROC12, 500000, 1293750, 6250, + buck_volt_range1, 0x7f, MT6358_BUCK_VPROC12_DBG0, 0x7f, + MT6358_VPROC_ANA_CON0, 2), + MT6366_BUCK("buck_vgpu", VGPU, 500000, 1293750, 6250, + buck_volt_range1, 0x7f, MT6358_BUCK_VGPU_ELR0, 0x7f, + MT6358_VCORE_VGPU_ANA_CON0, 2), + MT6366_BUCK("buck_vs2", VS2, 500000, 2087500, 12500, + buck_volt_range2, 0x7f, MT6358_BUCK_VS2_DBG0, 0x7f, + MT6358_VS2_ANA_CON0, 8), + MT6366_BUCK("buck_vmodem", VMODEM, 500000, 1293750, 6250, + buck_volt_range1, 0x7f, MT6358_BUCK_VMODEM_DBG0, 0x7f, + MT6358_VMODEM_ANA_CON0, 8), + MT6366_BUCK("buck_vs1", VS1, 1000000, 2587500, 12500, + buck_volt_range4, 0x7f, MT6358_BUCK_VS1_DBG0, 0x7f, + MT6358_VS1_ANA_CON0, 8), + MT6366_REG_FIXED("ldo_vrf12", VRF12, + MT6358_LDO_VRF12_CON0, 0, 1200000), + MT6366_REG_FIXED("ldo_vio18", VIO18, + MT6358_LDO_VIO18_CON0, 0, 1800000), + MT6366_REG_FIXED("ldo_vcn18", VCN18, MT6358_LDO_VCN18_CON0, 0, 1800000), + MT6366_REG_FIXED("ldo_vfe28", VFE28, MT6358_LDO_VFE28_CON0, 0, 2800000), + MT6366_REG_FIXED("ldo_vcn28", VCN28, MT6358_LDO_VCN28_CON0, 0, 2800000), + MT6366_REG_FIXED("ldo_vxo22", VXO22, MT6358_LDO_VXO22_CON0, 0, 2200000), + MT6366_REG_FIXED("ldo_vaux18", VAUX18, + MT6358_LDO_VAUX18_CON0, 0, 1800000), + MT6366_REG_FIXED("ldo_vbif28", VBIF28, + MT6358_LDO_VBIF28_CON0, 0, 2800000), + MT6366_REG_FIXED("ldo_vio28", VIO28, MT6358_LDO_VIO28_CON0, 0, 2800000), + MT6366_REG_FIXED("ldo_va12", VA12, MT6358_LDO_VA12_CON0, 0, 1200000), + MT6366_REG_FIXED("ldo_vrf18", VRF18, MT6358_LDO_VRF18_CON0, 0, 1800000), + MT6366_REG_FIXED("ldo_vaud28", VAUD28, + MT6358_LDO_VAUD28_CON0, 0, 2800000), + MT6366_LDO("ldo_vdram2", VDRAM2, vdram2_voltages, vdram2_idx, + MT6358_LDO_VDRAM2_CON0, 0, MT6358_LDO_VDRAM2_ELR0, 0x10), + MT6366_LDO("ldo_vsim1", VSIM1, vsim_voltages, vsim_idx, + MT6358_LDO_VSIM1_CON0, 0, MT6358_VSIM1_ANA_CON0, 0xf00), + MT6366_LDO("ldo_vibr", VIBR, vibr_voltages, vibr_idx, + MT6358_LDO_VIBR_CON0, 0, MT6358_VIBR_ANA_CON0, 0xf00), + MT6366_LDO("ldo_vusb", VUSB, vusb_voltages, vusb_idx, + MT6358_LDO_VUSB_CON0_0, 0, MT6358_VUSB_ANA_CON0, 0x700), + MT6366_LDO("ldo_vefuse", VEFUSE, vefuse_voltages, vefuse_idx, + MT6358_LDO_VEFUSE_CON0, 0, MT6358_VEFUSE_ANA_CON0, 0xf00), + MT6366_LDO("ldo_vmch", VMCH, vmch_vemc_voltages, vmch_vemc_idx, + MT6358_LDO_VMCH_CON0, 0, MT6358_VMCH_ANA_CON0, 0x700), + MT6366_LDO("ldo_vemc", VEMC, vmch_vemc_voltages, vmch_vemc_idx, + MT6358_LDO_VEMC_CON0, 0, MT6358_VEMC_ANA_CON0, 0x700), + MT6366_LDO("ldo_vcn33_bt", VCN33_BT, vcn33_bt_wifi_voltages, + vcn33_bt_wifi_idx, MT6358_LDO_VCN33_CON0_0, + 0, MT6358_VCN33_ANA_CON0, 0x300), + MT6366_LDO("ldo_vcn33_wifi", VCN33_WIFI, vcn33_bt_wifi_voltages, + vcn33_bt_wifi_idx, MT6358_LDO_VCN33_CON0_1, + 0, MT6358_VCN33_ANA_CON0, 0x300), + MT6366_LDO("ldo_vmc", VMC, vmc_voltages, vmc_idx, + MT6358_LDO_VMC_CON0, 0, MT6358_VMC_ANA_CON0, 0xf00), + MT6366_LDO("ldo_vsim2", VSIM2, vsim_voltages, vsim_idx, + MT6358_LDO_VSIM2_CON0, 0, MT6358_VSIM2_ANA_CON0, 0xf00), + MT6366_LDO1("ldo_vsram_proc11", VSRAM_PROC11, 500000, 1293750, 6250, + buck_volt_range1, MT6358_LDO_VSRAM_PROC11_DBG0, 0x7f00, + MT6358_LDO_VSRAM_CON0, 0x7f), + MT6366_LDO1("ldo_vsram_others", VSRAM_OTHERS, 500000, 1293750, 6250, + buck_volt_range1, MT6358_LDO_VSRAM_OTHERS_DBG0, 0x7f00, + MT6358_LDO_VSRAM_CON2, 0x7f), + MT6366_LDO1("ldo_vsram_others_sshub", VSRAM_OTHERS_SSHUB, 500000, + 1293750, 6250, buck_volt_range1, + MT6358_LDO_VSRAM_OTHERS_SSHUB_CON1, 0x7f, + MT6358_LDO_VSRAM_OTHERS_SSHUB_CON1, 0x7f), + MT6366_LDO1("ldo_vsram_gpu", VSRAM_GPU, 500000, 1293750, 6250, + buck_volt_range1, MT6358_LDO_VSRAM_GPU_DBG0, 0x7f00, + MT6358_LDO_VSRAM_CON3, 0x7f), + MT6366_LDO1("ldo_vsram_proc12", VSRAM_PROC12, 500000, 1293750, 6250, + buck_volt_range1, MT6358_LDO_VSRAM_PROC12_DBG0, 0x7f00, + MT6358_LDO_VSRAM_CON1, 0x7f), +}; + static int mt6358_regulator_probe(struct platform_device *pdev) { struct mt6397_chip *mt6397 = dev_get_drvdata(pdev->dev.parent); struct regulator_config config = {}; struct regulator_dev *rdev; - int i; + struct mt6358_regulator_info *mt6358_info; + int i, max_regulator; + + if (mt6397->chip_id == MT6366_CHIP_ID) { + max_regulator = MT6366_MAX_REGULATOR; + mt6358_info = mt6366_regulators; + } else { + max_regulator = MT6358_MAX_REGULATOR; + mt6358_info = mt6358_regulators; + } - for (i = 0; i < MT6358_MAX_REGULATOR; i++) { + for (i = 0; i < max_regulator; i++) { config.dev = &pdev->dev; - config.driver_data = &mt6358_regulators[i]; + config.driver_data = &mt6358_info[i]; config.regmap = mt6397->regmap; rdev = devm_regulator_register(&pdev->dev, - &mt6358_regulators[i].desc, + &mt6358_info[i].desc, &config); if (IS_ERR(rdev)) { dev_err(&pdev->dev, "failed to register %s\n", - mt6358_regulators[i].desc.name); + mt6358_info[i].desc.name); return PTR_ERR(rdev); } } diff --git a/include/linux/regulator/mt6358-regulator.h b/include/linux/regulator/mt6358-regulator.h index 1cc304946d09..bdcf83cd719e 100644 --- a/include/linux/regulator/mt6358-regulator.h +++ b/include/linux/regulator/mt6358-regulator.h @@ -48,9 +48,54 @@ enum { MT6358_ID_VLDO28, MT6358_ID_VAUD28, MT6358_ID_VSIM2, + MT6358_ID_VCORE_SSHUB, + MT6358_ID_VSRAM_OTHERS_SSHUB, MT6358_ID_RG_MAX, }; +enum { + MT6366_ID_VDRAM1 = 0, + MT6366_ID_VCORE, + MT6366_ID_VPA, + MT6366_ID_VPROC11, + MT6366_ID_VPROC12, + MT6366_ID_VGPU, + MT6366_ID_VS2, + MT6366_ID_VMODEM, + MT6366_ID_VS1, + MT6366_ID_VDRAM2, + MT6366_ID_VSIM1, + MT6366_ID_VIBR, + MT6366_ID_VRF12, + MT6366_ID_VIO18, + MT6366_ID_VUSB, + MT6366_ID_VCN18, + MT6366_ID_VFE28, + MT6366_ID_VSRAM_PROC11, + MT6366_ID_VCN28, + MT6366_ID_VSRAM_OTHERS, + MT6366_ID_VSRAM_GPU, + MT6366_ID_VXO22, + MT6366_ID_VEFUSE, + MT6366_ID_VAUX18, + MT6366_ID_VMCH, + MT6366_ID_VBIF28, + MT6366_ID_VSRAM_PROC12, + MT6366_ID_VEMC, + MT6366_ID_VIO28, + MT6366_ID_VA12, + MT6366_ID_VRF18, + MT6366_ID_VCN33_BT, + MT6366_ID_VCN33_WIFI, + MT6366_ID_VMC, + MT6366_ID_VAUD28, + MT6366_ID_VSIM2, + MT6366_ID_VCORE_SSHUB, + MT6366_ID_VSRAM_OTHERS_SSHUB, + MT6366_ID_RG_MAX, +}; + #define MT6358_MAX_REGULATOR MT6358_ID_RG_MAX +#define MT6366_MAX_REGULATOR MT6366_ID_RG_MAX #endif /* __LINUX_REGULATOR_MT6358_H */ -- cgit v1.2.3 From 4917e54997b0c5fbf39a3bd574802a16fa705096 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Fri, 25 Mar 2022 20:45:08 +0200 Subject: regulator: rpi-panel-attiny: Get rid of duplicate of_node assignment GPIO library does copy the of_node from the parent device of the GPIO chip, there is no need to repeat this in the individual drivers. Remove these assignment all at once. For the details one may look into the of_gpio_dev_init() implementation. Signed-off-by: Andy Shevchenko Link: https://lore.kernel.org/r/20220325184508.45670-1-andriy.shevchenko@linux.intel.com Signed-off-by: Mark Brown --- drivers/regulator/rpi-panel-attiny-regulator.c | 1 - 1 file changed, 1 deletion(-) (limited to 'drivers') diff --git a/drivers/regulator/rpi-panel-attiny-regulator.c b/drivers/regulator/rpi-panel-attiny-regulator.c index f7df0f4b2f87..fa8706a352ce 100644 --- a/drivers/regulator/rpi-panel-attiny-regulator.c +++ b/drivers/regulator/rpi-panel-attiny-regulator.c @@ -364,7 +364,6 @@ static int attiny_i2c_probe(struct i2c_client *i2c, state->gc.parent = &i2c->dev; state->gc.label = i2c->name; state->gc.owner = THIS_MODULE; - state->gc.of_node = i2c->dev.of_node; state->gc.base = -1; state->gc.ngpio = NUM_GPIO; -- cgit v1.2.3 From bfb5711e2455a239ad64dd5151fb16d195329d46 Mon Sep 17 00:00:00 2001 From: Minghao Chi Date: Tue, 12 Apr 2022 07:10:30 +0000 Subject: regulator: stm32-vrefbuf: using pm_runtime_resume_and_get instead of pm_runtime_get_sync Using pm_runtime_resume_and_get is more appropriate for simplifing code Reported-by: Zeal Robot Signed-off-by: Minghao Chi Link: https://lore.kernel.org/r/20220412071030.2532230-1-chi.minghao@zte.com.cn Signed-off-by: Mark Brown --- drivers/regulator/stm32-vrefbuf.c | 30 ++++++++++-------------------- 1 file changed, 10 insertions(+), 20 deletions(-) (limited to 'drivers') diff --git a/drivers/regulator/stm32-vrefbuf.c b/drivers/regulator/stm32-vrefbuf.c index 161622ea7259..30ea3bc8ca19 100644 --- a/drivers/regulator/stm32-vrefbuf.c +++ b/drivers/regulator/stm32-vrefbuf.c @@ -44,11 +44,9 @@ static int stm32_vrefbuf_enable(struct regulator_dev *rdev) u32 val; int ret; - ret = pm_runtime_get_sync(priv->dev); - if (ret < 0) { - pm_runtime_put_noidle(priv->dev); + ret = pm_runtime_resume_and_get(priv->dev); + if (ret < 0) return ret; - } val = readl_relaxed(priv->base + STM32_VREFBUF_CSR); val = (val & ~STM32_HIZ) | STM32_ENVR; @@ -81,11 +79,9 @@ static int stm32_vrefbuf_disable(struct regulator_dev *rdev) u32 val; int ret; - ret = pm_runtime_get_sync(priv->dev); - if (ret < 0) { - pm_runtime_put_noidle(priv->dev); + ret = pm_runtime_resume_and_get(priv->dev); + if (ret < 0) return ret; - } val = readl_relaxed(priv->base + STM32_VREFBUF_CSR); val &= ~STM32_ENVR; @@ -102,11 +98,9 @@ static int stm32_vrefbuf_is_enabled(struct regulator_dev *rdev) struct stm32_vrefbuf *priv = rdev_get_drvdata(rdev); int ret; - ret = pm_runtime_get_sync(priv->dev); - if (ret < 0) { - pm_runtime_put_noidle(priv->dev); + ret = pm_runtime_resume_and_get(priv->dev); + if (ret < 0) return ret; - } ret = readl_relaxed(priv->base + STM32_VREFBUF_CSR) & STM32_ENVR; @@ -123,11 +117,9 @@ static int stm32_vrefbuf_set_voltage_sel(struct regulator_dev *rdev, u32 val; int ret; - ret = pm_runtime_get_sync(priv->dev); - if (ret < 0) { - pm_runtime_put_noidle(priv->dev); + ret = pm_runtime_resume_and_get(priv->dev); + if (ret < 0) return ret; - } val = readl_relaxed(priv->base + STM32_VREFBUF_CSR); val = (val & ~STM32_VRS) | FIELD_PREP(STM32_VRS, sel); @@ -145,11 +137,9 @@ static int stm32_vrefbuf_get_voltage_sel(struct regulator_dev *rdev) u32 val; int ret; - ret = pm_runtime_get_sync(priv->dev); - if (ret < 0) { - pm_runtime_put_noidle(priv->dev); + ret = pm_runtime_resume_and_get(priv->dev); + if (ret < 0) return ret; - } val = readl_relaxed(priv->base + STM32_VREFBUF_CSR); ret = FIELD_GET(STM32_VRS, val); -- cgit v1.2.3 From bab76514aca36bc513224525d5598da676938218 Mon Sep 17 00:00:00 2001 From: Wei Yongjun Date: Thu, 21 Apr 2022 09:03:35 +0000 Subject: regulator: da9121: Fix uninit-value in da9121_assign_chip_model() KASAN report slab-out-of-bounds in __regmap_init as follows: BUG: KASAN: slab-out-of-bounds in __regmap_init drivers/base/regmap/regmap.c:841 Read of size 1 at addr ffff88803678cdf1 by task xrun/9137 CPU: 0 PID: 9137 Comm: xrun Tainted: G W 5.18.0-rc2 Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS 1.13.0-1ubuntu1.1 04/01/2014 Call Trace: dump_stack_lvl+0xe8/0x15a lib/dump_stack.c:88 print_report.cold+0xcd/0x69b mm/kasan/report.c:313 kasan_report+0x8e/0xc0 mm/kasan/report.c:491 __regmap_init+0x4540/0x4ba0 drivers/base/regmap/regmap.c:841 __devm_regmap_init+0x7a/0x100 drivers/base/regmap/regmap.c:1266 __devm_regmap_init_i2c+0x65/0x80 drivers/base/regmap/regmap-i2c.c:394 da9121_i2c_probe+0x386/0x6d1 drivers/regulator/da9121-regulator.c:1039 i2c_device_probe+0x959/0xac0 drivers/i2c/i2c-core-base.c:563 This happend when da9121 device is probe by da9121_i2c_id, but with invalid dts. Thus, chip->subvariant_id is set to -EINVAL, and later da9121_assign_chip_model() will access 'regmap' without init it. Fix it by return -EINVAL from da9121_assign_chip_model() if 'chip->subvariant_id' is invalid. Fixes: f3fbd5566f6a ("regulator: da9121: Add device variants") Reported-by: Hulk Robot Signed-off-by: Wei Yongjun Reviewed-by: Adam Ward Link: https://lore.kernel.org/r/20220421090335.1876149-1-weiyongjun1@huawei.com Signed-off-by: Mark Brown --- drivers/regulator/da9121-regulator.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'drivers') diff --git a/drivers/regulator/da9121-regulator.c b/drivers/regulator/da9121-regulator.c index eb9df485bd8a..76e0e23bf598 100644 --- a/drivers/regulator/da9121-regulator.c +++ b/drivers/regulator/da9121-regulator.c @@ -1030,6 +1030,8 @@ static int da9121_assign_chip_model(struct i2c_client *i2c, chip->variant_id = DA9121_TYPE_DA9142; regmap = &da9121_2ch_regmap_config; break; + default: + return -EINVAL; } /* Set these up for of_regulator_match call which may want .of_map_modes */ -- cgit v1.2.3 From a38dce4cb1f1bcc4f6ef7f11e54b6507a4043ebe Mon Sep 17 00:00:00 2001 From: Brian Norris Date: Wed, 20 Apr 2022 14:22:12 -0700 Subject: regulator: core: Rename _regulator_enable_delay() I want to use it in other contexts besides _regulator_do_enable(). Signed-off-by: Brian Norris Link: https://lore.kernel.org/r/20220420141511.v2.1.I31ef0014c9597d53722ab513890f839f357fdfb3@changeid Signed-off-by: Mark Brown --- drivers/regulator/core.c | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) (limited to 'drivers') diff --git a/drivers/regulator/core.c b/drivers/regulator/core.c index a8a95d09ca11..d9c7db1665be 100644 --- a/drivers/regulator/core.c +++ b/drivers/regulator/core.c @@ -2529,17 +2529,17 @@ static int regulator_ena_gpio_ctrl(struct regulator_dev *rdev, bool enable) } /** - * _regulator_enable_delay - a delay helper function + * _regulator_delay_helper - a delay helper function * @delay: time to delay in microseconds * * Delay for the requested amount of time as per the guidelines in: * * Documentation/timers/timers-howto.rst * - * The assumption here is that regulators will never be enabled in + * The assumption here is that these regulator operations will never used in * atomic context and therefore sleeping functions can be used. */ -static void _regulator_enable_delay(unsigned int delay) +static void _regulator_delay_helper(unsigned int delay) { unsigned int ms = delay / 1000; unsigned int us = delay % 1000; @@ -2621,7 +2621,7 @@ static int _regulator_do_enable(struct regulator_dev *rdev) s64 remaining = ktime_us_delta(end, ktime_get()); if (remaining > 0) - _regulator_enable_delay(remaining); + _regulator_delay_helper(remaining); } if (rdev->ena_pin) { @@ -2648,14 +2648,14 @@ static int _regulator_do_enable(struct regulator_dev *rdev) /* If poll_enabled_time is set, poll upto the delay calculated * above, delaying poll_enabled_time uS to check if the regulator * actually got enabled. - * If the regulator isn't enabled after enable_delay has - * expired, return -ETIMEDOUT. + * If the regulator isn't enabled after our delay helper has expired, + * return -ETIMEDOUT. */ if (rdev->desc->poll_enabled_time) { unsigned int time_remaining = delay; while (time_remaining > 0) { - _regulator_enable_delay(rdev->desc->poll_enabled_time); + _regulator_delay_helper(rdev->desc->poll_enabled_time); if (rdev->desc->ops->get_status) { ret = _regulator_check_status_enabled(rdev); @@ -2674,7 +2674,7 @@ static int _regulator_do_enable(struct regulator_dev *rdev) return -ETIMEDOUT; } } else { - _regulator_enable_delay(delay); + _regulator_delay_helper(delay); } trace_regulator_enable_complete(rdev_get_name(rdev)); -- cgit v1.2.3 From 062920d2464715ef5cbba52a8573ba12cc882b8f Mon Sep 17 00:00:00 2001 From: Brian Norris Date: Wed, 20 Apr 2022 14:22:13 -0700 Subject: regulator: core: Sleep (not delay) in set_voltage() These delays can be relatively large (e.g., hundreds of microseconds to several milliseconds on RK3399 Gru systems). Per Documentation/timers/timers-howto.rst, that should usually use a sleeping delay. Let's use the existing regulator delay helper to handle both large and small delays appropriately. This avoids burning a bunch of CPU time and hurting scheduling latencies when hitting regulators a lot (e.g., during cpufreq). The sleep vs. delay issue choice has been made differently over time -- early versions of RK3399 Gru PWM-regulator support used usleep_range() in pwm-regulator.c. More of this got moved into the regulator core, in commits like: 73e705bf81ce regulator: core: Add set_voltage_time op At the same time, the sleep turned into a delay. It's OK to sleep in _regulator_do_set_voltage(), as we aren't in an atomic context. (All our callers grab various mutexes already.) I avoid using fsleep() because it uses a usleep_range() of [N to N*2], and usleep_range() very commonly biases to the high end of the range. We don't want to double the expected delay, especially for long delays. Signed-off-by: Brian Norris Reviewed-by: Matthias Kaehlcke Link: https://lore.kernel.org/r/20220420141511.v2.2.If0fc61a894f537b052ca41572aff098cf8e7e673@changeid Signed-off-by: Mark Brown --- drivers/regulator/core.c | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) (limited to 'drivers') diff --git a/drivers/regulator/core.c b/drivers/regulator/core.c index d9c7db1665be..ce3786e966c3 100644 --- a/drivers/regulator/core.c +++ b/drivers/regulator/core.c @@ -3566,12 +3566,7 @@ static int _regulator_do_set_voltage(struct regulator_dev *rdev, } /* Insert any necessary delays */ - if (delay >= 1000) { - mdelay(delay / 1000); - udelay(delay % 1000); - } else if (delay) { - udelay(delay); - } + _regulator_delay_helper(delay); if (best_val >= 0) { unsigned long data = best_val; -- cgit v1.2.3 From 6963569103c02b22076da245b19bd081d8da8f9e Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Mon, 25 Apr 2022 09:24:55 +0200 Subject: regulator: richtek,rt4801: parse GPIOs per regulator Having one enable-gpios property for all regulators is discouraged and instead, similarly to regulator core ena_gpiod feature, each GPIO should be present in each regulator node. Add support for parsing such GPIOs, keeping backwards compatibility. Signed-off-by: Krzysztof Kozlowski Tested-by: ChiYuan Huang Link: https://lore.kernel.org/r/20220425072455.27356-3-krzysztof.kozlowski@linaro.org Signed-off-by: Mark Brown --- drivers/regulator/rt4801-regulator.c | 49 ++++++++++++++++++++++++++++-------- 1 file changed, 38 insertions(+), 11 deletions(-) (limited to 'drivers') diff --git a/drivers/regulator/rt4801-regulator.c b/drivers/regulator/rt4801-regulator.c index 7a87788d3f09..563d79196fdd 100644 --- a/drivers/regulator/rt4801-regulator.c +++ b/drivers/regulator/rt4801-regulator.c @@ -29,11 +29,33 @@ struct rt4801_priv { struct device *dev; - struct gpio_descs *enable_gpios; + struct gpio_desc *enable_gpios[DSV_OUT_MAX]; unsigned int enable_flag; unsigned int volt_sel[DSV_OUT_MAX]; }; +static int rt4801_of_parse_cb(struct device_node *np, + const struct regulator_desc *desc, + struct regulator_config *config) +{ + struct rt4801_priv *priv = config->driver_data; + int id = desc->id; + + if (priv->enable_gpios[id]) { + dev_warn(priv->dev, "duplicated enable-gpios property\n"); + return 0; + } + priv->enable_gpios[id] = devm_fwnode_gpiod_get_index(priv->dev, + of_fwnode_handle(np), + "enable", 0, + GPIOD_OUT_HIGH, + "rt4801"); + if (IS_ERR(priv->enable_gpios[id])) + priv->enable_gpios[id] = NULL; + + return 0; +} + static int rt4801_set_voltage_sel(struct regulator_dev *rdev, unsigned int selector) { struct rt4801_priv *priv = rdev_get_drvdata(rdev); @@ -63,15 +85,14 @@ static int rt4801_get_voltage_sel(struct regulator_dev *rdev) static int rt4801_enable(struct regulator_dev *rdev) { struct rt4801_priv *priv = rdev_get_drvdata(rdev); - struct gpio_descs *gpios = priv->enable_gpios; int id = rdev_get_id(rdev), ret; - if (!gpios || gpios->ndescs <= id) { + if (!priv->enable_gpios[id]) { dev_warn(&rdev->dev, "no dedicated gpio can control\n"); goto bypass_gpio; } - gpiod_set_value(gpios->desc[id], 1); + gpiod_set_value(priv->enable_gpios[id], 1); bypass_gpio: ret = regmap_write(rdev->regmap, rdev->desc->vsel_reg, priv->volt_sel[id]); @@ -85,15 +106,14 @@ bypass_gpio: static int rt4801_disable(struct regulator_dev *rdev) { struct rt4801_priv *priv = rdev_get_drvdata(rdev); - struct gpio_descs *gpios = priv->enable_gpios; int id = rdev_get_id(rdev); - if (!gpios || gpios->ndescs <= id) { + if (!priv->enable_gpios[id]) { dev_warn(&rdev->dev, "no dedicated gpio can control\n"); goto bypass_gpio; } - gpiod_set_value(gpios->desc[id], 0); + gpiod_set_value(priv->enable_gpios[id], 0); bypass_gpio: priv->enable_flag &= ~BIT(id); @@ -122,6 +142,7 @@ static const struct regulator_desc rt4801_regulator_descs[] = { .name = "DSVP", .ops = &rt4801_regulator_ops, .of_match = of_match_ptr("DSVP"), + .of_parse_cb = rt4801_of_parse_cb, .type = REGULATOR_VOLTAGE, .id = DSV_OUT_POS, .min_uV = MIN_UV, @@ -135,6 +156,7 @@ static const struct regulator_desc rt4801_regulator_descs[] = { .name = "DSVN", .ops = &rt4801_regulator_ops, .of_match = of_match_ptr("DSVN"), + .of_parse_cb = rt4801_of_parse_cb, .type = REGULATOR_VOLTAGE, .id = DSV_OUT_NEG, .min_uV = MIN_UV, @@ -172,10 +194,15 @@ static int rt4801_probe(struct i2c_client *i2c) return PTR_ERR(regmap); } - priv->enable_gpios = devm_gpiod_get_array_optional(&i2c->dev, "enable", GPIOD_OUT_HIGH); - if (IS_ERR(priv->enable_gpios)) { - dev_err(&i2c->dev, "Failed to get gpios\n"); - return PTR_ERR(priv->enable_gpios); + for (i = 0; i < DSV_OUT_MAX; i++) { + priv->enable_gpios[i] = devm_gpiod_get_index_optional(&i2c->dev, + "enable", + i, + GPIOD_OUT_HIGH); + if (IS_ERR(priv->enable_gpios[i])) { + dev_err(&i2c->dev, "Failed to get gpios\n"); + return PTR_ERR(priv->enable_gpios[i]); + } } for (i = 0; i < DSV_OUT_MAX; i++) { -- cgit v1.2.3 From e8858ba89ca377064da130d09648c99683f8bd90 Mon Sep 17 00:00:00 2001 From: Markuss Broks Date: Sat, 23 Apr 2022 11:53:18 +0300 Subject: regulator: sm5703-regulator: Add regulators support for SM5703 MFD Regulators block of SM5703 controls several voltage regulators which are used to power various components. There are 3 LDO outputs ranging from 1.5 to 3.3V, a buck regulator ranging from 1V to 3V, two fixed voltage LDO regulators for powering the USB devices and one high-power fixed voltage LDO line (actually two lines) meant to power high-power USB devices. Signed-off-by: Markuss Broks Link: https://lore.kernel.org/r/20220423085319.483524-6-markuss.broks@gmail.com Signed-off-by: Mark Brown --- drivers/regulator/Kconfig | 7 ++ drivers/regulator/Makefile | 1 + drivers/regulator/sm5703-regulator.c | 167 +++++++++++++++++++++++++++++++++++ 3 files changed, 175 insertions(+) create mode 100644 drivers/regulator/sm5703-regulator.c (limited to 'drivers') diff --git a/drivers/regulator/Kconfig b/drivers/regulator/Kconfig index a7effc57bbdb..cbe0f96ca342 100644 --- a/drivers/regulator/Kconfig +++ b/drivers/regulator/Kconfig @@ -1167,6 +1167,13 @@ config REGULATOR_SLG51000 The SLG51000 is seven compact and customizable low dropout regulators. +config REGULATOR_SM5703 + tristate "Silicon Mitus SM5703 regulators" + depends on MFD_SM5703 + help + This driver provides support for voltage regulators of SM5703 + multi-function device. + config REGULATOR_STM32_BOOSTER tristate "STMicroelectronics STM32 BOOSTER" depends on ARCH_STM32 || COMPILE_TEST diff --git a/drivers/regulator/Makefile b/drivers/regulator/Makefile index 69b5a196acd2..8d3ee8b6d41d 100644 --- a/drivers/regulator/Makefile +++ b/drivers/regulator/Makefile @@ -139,6 +139,7 @@ obj-$(CONFIG_REGULATOR_S5M8767) += s5m8767.o obj-$(CONFIG_REGULATOR_SC2731) += sc2731-regulator.o obj-$(CONFIG_REGULATOR_SKY81452) += sky81452-regulator.o obj-$(CONFIG_REGULATOR_SLG51000) += slg51000-regulator.o +obj-$(CONFIG_REGULATOR_SM5703) += sm5703-regulator.o obj-$(CONFIG_REGULATOR_STM32_BOOSTER) += stm32-booster.o obj-$(CONFIG_REGULATOR_STM32_VREFBUF) += stm32-vrefbuf.o obj-$(CONFIG_REGULATOR_STM32_PWR) += stm32-pwr.o diff --git a/drivers/regulator/sm5703-regulator.c b/drivers/regulator/sm5703-regulator.c new file mode 100644 index 000000000000..05ad28fc4da8 --- /dev/null +++ b/drivers/regulator/sm5703-regulator.c @@ -0,0 +1,167 @@ +// SPDX-License-Identifier: GPL-2.0-only + +#include +#include +#include +#include +#include +#include +#include + +enum sm5703_regulators { + SM5703_BUCK, + SM5703_LDO1, + SM5703_LDO2, + SM5703_LDO3, + SM5703_USBLDO1, + SM5703_USBLDO2, + SM5703_VBUS, + SM5703_MAX_REGULATORS, +}; + +static const int sm5703_ldo_voltagemap[] = { + 1500000, 1800000, 2600000, 2800000, 3000000, 3300000, +}; + +static const int sm5703_buck_voltagemap[] = { + 1000000, 1000000, 1000000, 1000000, + 1000000, 1000000, 1000000, 1000000, + 1000000, 1000000, 1000000, 1100000, + 1200000, 1300000, 1400000, 1500000, + 1600000, 1700000, 1800000, 1900000, + 2000000, 2100000, 2200000, 2300000, + 2400000, 2500000, 2600000, 2700000, + 2800000, 2900000, 3000000, 3000000, +}; + +#define SM5703USBLDO(_name, _id) \ + [SM5703_USBLDO ## _id] = { \ + .name = _name, \ + .of_match = _name, \ + .regulators_node = "regulators", \ + .type = REGULATOR_VOLTAGE, \ + .id = SM5703_USBLDO ## _id, \ + .ops = &sm5703_regulator_ops_fixed, \ + .fixed_uV = SM5703_USBLDO_MICROVOLT, \ + .enable_reg = SM5703_REG_USBLDO12, \ + .enable_mask = SM5703_REG_EN_USBLDO ##_id, \ + .owner = THIS_MODULE, \ + } + +#define SM5703VBUS(_name) \ + [SM5703_VBUS] = { \ + .name = _name, \ + .of_match = _name, \ + .regulators_node = "regulators", \ + .type = REGULATOR_VOLTAGE, \ + .id = SM5703_VBUS, \ + .ops = &sm5703_regulator_ops_fixed, \ + .fixed_uV = SM5703_VBUS_MICROVOLT, \ + .enable_reg = SM5703_REG_CNTL, \ + .enable_mask = SM5703_OPERATION_MODE_MASK, \ + .enable_val = SM5703_OPERATION_MODE_USB_OTG_MODE, \ + .disable_val = SM5703_OPERATION_MODE_CHARGING_ON, \ + .owner = THIS_MODULE, \ + } + +#define SM5703BUCK(_name) \ + [SM5703_BUCK] = { \ + .name = _name, \ + .of_match = _name, \ + .regulators_node = "regulators", \ + .type = REGULATOR_VOLTAGE, \ + .id = SM5703_BUCK, \ + .ops = &sm5703_regulator_ops, \ + .n_voltages = ARRAY_SIZE(sm5703_buck_voltagemap), \ + .volt_table = sm5703_buck_voltagemap, \ + .vsel_reg = SM5703_REG_BUCK, \ + .vsel_mask = SM5703_BUCK_VOLT_MASK, \ + .enable_reg = SM5703_REG_BUCK, \ + .enable_mask = SM5703_REG_EN_BUCK, \ + .owner = THIS_MODULE, \ + } + +#define SM5703LDO(_name, _id) \ + [SM5703_LDO ## _id] = { \ + .name = _name, \ + .of_match = _name, \ + .regulators_node = "regulators", \ + .type = REGULATOR_VOLTAGE, \ + .id = SM5703_LDO ## _id, \ + .ops = &sm5703_regulator_ops, \ + .n_voltages = ARRAY_SIZE(sm5703_ldo_voltagemap), \ + .volt_table = sm5703_ldo_voltagemap, \ + .vsel_reg = SM5703_REG_LDO ##_id, \ + .vsel_mask = SM5703_LDO_VOLT_MASK, \ + .enable_reg = SM5703_REG_LDO ##_id, \ + .enable_mask = SM5703_LDO_EN, \ + .owner = THIS_MODULE, \ + } + +static const struct regulator_ops sm5703_regulator_ops = { + .enable = regulator_enable_regmap, + .disable = regulator_disable_regmap, + .is_enabled = regulator_is_enabled_regmap, + .list_voltage = regulator_list_voltage_table, + .get_voltage_sel = regulator_get_voltage_sel_regmap, + .set_voltage_sel = regulator_set_voltage_sel_regmap, +}; + +static const struct regulator_ops sm5703_regulator_ops_fixed = { + .enable = regulator_enable_regmap, + .disable = regulator_disable_regmap, + .is_enabled = regulator_is_enabled_regmap, +}; + +static struct regulator_desc sm5703_regulators_desc[SM5703_MAX_REGULATORS] = { + SM5703BUCK("buck"), + SM5703LDO("ldo1", 1), + SM5703LDO("ldo2", 2), + SM5703LDO("ldo3", 3), + SM5703USBLDO("usbldo1", 1), + SM5703USBLDO("usbldo2", 2), + SM5703VBUS("vbus"), +}; + +static int sm5703_regulator_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct regulator_config config = { NULL, }; + struct regulator_dev *rdev; + struct sm5703_dev *sm5703 = dev_get_drvdata(pdev->dev.parent); + int i; + + config.dev = dev->parent; + config.regmap = sm5703->regmap; + + for (i = 0; i < SM5703_MAX_REGULATORS; i++) { + rdev = devm_regulator_register(dev, + &sm5703_regulators_desc[i], + &config); + if (IS_ERR(rdev)) + return dev_err_probe(dev, PTR_ERR(rdev), + "Failed to register a regulator\n"); + } + + return 0; +} + +static const struct platform_device_id sm5703_regulator_id[] = { + { "sm5703-regulator", 0 }, + {} +}; +MODULE_DEVICE_TABLE(platform, sm5703_regulator_id); + +static struct platform_driver sm5703_regulator_driver = { + .driver = { + .name = "sm5703-regulator", + }, + .probe = sm5703_regulator_probe, + .id_table = sm5703_regulator_id, +}; + +module_platform_driver(sm5703_regulator_driver); + +MODULE_DESCRIPTION("Silicon Mitus SM5703 LDO/Buck/USB regulator driver"); +MODULE_AUTHOR("Markuss Broks "); +MODULE_LICENSE("GPL"); -- cgit v1.2.3 From 62139f52b7e588d565aa9df81ea0a0548a68b823 Mon Sep 17 00:00:00 2001 From: Per-Daniel Olsson Date: Fri, 29 Apr 2022 09:22:08 +0200 Subject: regulator: pca9450: Make I2C Level Translator configurable Make the I2C Level Translator included in PCA9450 configurable from devicetree. The reset state is off. By setting nxp,i2c-lt-enable, the I2C Level Translator will be enabled while in STANDBY or RUN state. Signed-off-by: Per-Daniel Olsson Signed-off-by: Rickard x Andersson Link: https://lore.kernel.org/r/20220429072211.24957-2-rickaran@axis.com Signed-off-by: Mark Brown --- drivers/regulator/pca9450-regulator.c | 11 +++++++++++ include/linux/regulator/pca9450.h | 7 +++++++ 2 files changed, 18 insertions(+) (limited to 'drivers') diff --git a/drivers/regulator/pca9450-regulator.c b/drivers/regulator/pca9450-regulator.c index 64e5f5f0cc84..87b4e6e29ba1 100644 --- a/drivers/regulator/pca9450-regulator.c +++ b/drivers/regulator/pca9450-regulator.c @@ -810,6 +810,17 @@ static int pca9450_i2c_probe(struct i2c_client *i2c, return ret; } + if (of_property_read_bool(i2c->dev.of_node, "nxp,i2c-lt-enable")) { + /* Enable I2C Level Translator */ + ret = regmap_update_bits(pca9450->regmap, PCA9450_REG_CONFIG2, + I2C_LT_MASK, I2C_LT_ON_STANDBY_RUN); + if (ret) { + dev_err(&i2c->dev, + "Failed to enable I2C level translator\n"); + return ret; + } + } + /* * The driver uses the LDO5CTRL_H register to control the LDO5 regulator. * This is only valid if the SD_VSEL input of the PMIC is high. Let's diff --git a/include/linux/regulator/pca9450.h b/include/linux/regulator/pca9450.h index 71902f41c919..3c01c2bf84f5 100644 --- a/include/linux/regulator/pca9450.h +++ b/include/linux/regulator/pca9450.h @@ -226,4 +226,11 @@ enum { #define WDOG_B_CFG_COLD_LDO12 0x80 #define WDOG_B_CFG_COLD 0xC0 +/* PCA9450_REG_CONFIG2 bits */ +#define I2C_LT_MASK 0x03 +#define I2C_LT_FORCE_DISABLE 0x00 +#define I2C_LT_ON_STANDBY_RUN 0x01 +#define I2C_LT_ON_RUN 0x02 +#define I2C_LT_FORCE_ENABLE 0x03 + #endif /* __LINUX_REG_PCA9450_H__ */ -- cgit v1.2.3 From 2364a64d0673f5044e6a52cb17d6d60c6f1f8329 Mon Sep 17 00:00:00 2001 From: Rickard x Andersson Date: Fri, 29 Apr 2022 09:22:10 +0200 Subject: regulator: pca9450: Make warm reset on WDOG_B assertion The default configuration of the PMIC behavior makes the PMIC power cycle most regulators on WDOG_B assertion. This power cycling causes the memory contents of OCRAM to be lost. Some systems neeeds some memory that survives reset and reboot, therefore this patch is created. Signed-off-by: Rickard x Andersson Link: https://lore.kernel.org/r/20220429072211.24957-4-rickaran@axis.com Signed-off-by: Mark Brown --- drivers/regulator/pca9450-regulator.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/regulator/pca9450-regulator.c b/drivers/regulator/pca9450-regulator.c index 87b4e6e29ba1..4a3ae73c600c 100644 --- a/drivers/regulator/pca9450-regulator.c +++ b/drivers/regulator/pca9450-regulator.c @@ -702,6 +702,7 @@ static int pca9450_i2c_probe(struct i2c_client *i2c, struct regulator_config config = { }; struct pca9450 *pca9450; unsigned int device_id, i; + unsigned int reset_ctrl; int ret; if (!i2c->irq) { @@ -802,9 +803,14 @@ static int pca9450_i2c_probe(struct i2c_client *i2c, return ret; } + if (of_property_read_bool(i2c->dev.of_node, "nxp,wdog_b-warm-reset")) + reset_ctrl = WDOG_B_CFG_WARM; + else + reset_ctrl = WDOG_B_CFG_COLD_LDO12; + /* Set reset behavior on assertion of WDOG_B signal */ ret = regmap_update_bits(pca9450->regmap, PCA9450_REG_RESET_CTRL, - WDOG_B_CFG_MASK, WDOG_B_CFG_COLD_LDO12); + WDOG_B_CFG_MASK, reset_ctrl); if (ret) { dev_err(&i2c->dev, "Failed to set WDOG_B reset behavior\n"); return ret; -- cgit v1.2.3 From 20078e3bbe6e5adb1a88f03f9609d532d99c690c Mon Sep 17 00:00:00 2001 From: Rickard x Andersson Date: Fri, 29 Apr 2022 09:22:11 +0200 Subject: regulator: pca9450: Enable DVS control via PMIC_STBY_REQ When DVS is enabled via the devicetree properties "nxp,dvs-run-voltage" and "nxp,dvs-standby-voltage" then also the bit that enables DVS control via PMIC_STBY_REQ pin should be set. Signed-off-by: Rickard x Andersson Link: https://lore.kernel.org/r/20220429072211.24957-5-rickaran@axis.com Signed-off-by: Mark Brown --- drivers/regulator/pca9450-regulator.c | 8 ++++++++ 1 file changed, 8 insertions(+) (limited to 'drivers') diff --git a/drivers/regulator/pca9450-regulator.c b/drivers/regulator/pca9450-regulator.c index 4a3ae73c600c..14b7d3376516 100644 --- a/drivers/regulator/pca9450-regulator.c +++ b/drivers/regulator/pca9450-regulator.c @@ -174,6 +174,14 @@ static int buck_set_dvs(const struct regulator_desc *desc, } } + if (ret == 0) { + struct pca9450_regulator_desc *regulator = container_of(desc, + struct pca9450_regulator_desc, desc); + + /* Enable DVS control through PMIC_STBY_REQ for this BUCK */ + ret = regmap_update_bits(regmap, regulator->desc.enable_reg, + BUCK1_DVS_CTRL, BUCK1_DVS_CTRL); + } return ret; } -- cgit v1.2.3 From 0f2d636e7d1fd76f704dd3ea5089ce29a8aee049 Mon Sep 17 00:00:00 2001 From: Zev Weiss Date: Tue, 3 May 2022 23:52:49 -0700 Subject: regulator: core: Add error flags to sysfs attributes If a regulator provides a get_error_flags() operation, its sysfs attributes will now include an entry for each defined REGULATOR_ERROR_* flag. Signed-off-by: Zev Weiss Link: https://lore.kernel.org/r/20220504065252.6955-3-zev@bewilderbeest.net Signed-off-by: Mark Brown --- Documentation/ABI/testing/sysfs-class-regulator | 81 +++++++++++++++++++++++++ drivers/regulator/core.c | 45 ++++++++++++++ 2 files changed, 126 insertions(+) (limited to 'drivers') diff --git a/Documentation/ABI/testing/sysfs-class-regulator b/Documentation/ABI/testing/sysfs-class-regulator index 8516f08806dd..475b9a372657 100644 --- a/Documentation/ABI/testing/sysfs-class-regulator +++ b/Documentation/ABI/testing/sysfs-class-regulator @@ -370,3 +370,84 @@ Description: 'unknown' means software cannot determine the state, or the reported state is invalid. + +What: /sys/class/regulator/.../under_voltage +Date: April 2022 +KernelVersion: 5.18 +Contact: Zev Weiss +Description: + Some regulator directories will contain a field called + under_voltage. This indicates if the device reports an + under-voltage fault (1) or not (0). + +What: /sys/class/regulator/.../over_current +Date: April 2022 +KernelVersion: 5.18 +Contact: Zev Weiss +Description: + Some regulator directories will contain a field called + over_current. This indicates if the device reports an + over-current fault (1) or not (0). + +What: /sys/class/regulator/.../regulation_out +Date: April 2022 +KernelVersion: 5.18 +Contact: Zev Weiss +Description: + Some regulator directories will contain a field called + regulation_out. This indicates if the device reports an + out-of-regulation fault (1) or not (0). + +What: /sys/class/regulator/.../fail +Date: April 2022 +KernelVersion: 5.18 +Contact: Zev Weiss +Description: + Some regulator directories will contain a field called + fail. This indicates if the device reports an output failure + (1) or not (0). + +What: /sys/class/regulator/.../over_temp +Date: April 2022 +KernelVersion: 5.18 +Contact: Zev Weiss +Description: + Some regulator directories will contain a field called + over_temp. This indicates if the device reports an + over-temperature fault (1) or not (0). + +What: /sys/class/regulator/.../under_voltage_warn +Date: April 2022 +KernelVersion: 5.18 +Contact: Zev Weiss +Description: + Some regulator directories will contain a field called + under_voltage_warn. This indicates if the device reports an + under-voltage warning (1) or not (0). + +What: /sys/class/regulator/.../over_current_warn +Date: April 2022 +KernelVersion: 5.18 +Contact: Zev Weiss +Description: + Some regulator directories will contain a field called + over_current_warn. This indicates if the device reports an + over-current warning (1) or not (0). + +What: /sys/class/regulator/.../over_voltage_warn +Date: April 2022 +KernelVersion: 5.18 +Contact: Zev Weiss +Description: + Some regulator directories will contain a field called + over_voltage_warn. This indicates if the device reports an + over-voltage warning (1) or not (0). + +What: /sys/class/regulator/.../over_temp_warn +Date: April 2022 +KernelVersion: 5.18 +Contact: Zev Weiss +Description: + Some regulator directories will contain a field called + over_temp_warn. This indicates if the device reports an + over-temperature warning (1) or not (0). diff --git a/drivers/regulator/core.c b/drivers/regulator/core.c index ce3786e966c3..d790f7b648b1 100644 --- a/drivers/regulator/core.c +++ b/drivers/regulator/core.c @@ -83,6 +83,7 @@ struct regulator_supply_alias { static int _regulator_is_enabled(struct regulator_dev *rdev); static int _regulator_disable(struct regulator *regulator); +static int _regulator_get_error_flags(struct regulator_dev *rdev, unsigned int *flags); static int _regulator_get_current_limit(struct regulator_dev *rdev); static unsigned int _regulator_get_mode(struct regulator_dev *rdev); static int _notifier_call_chain(struct regulator_dev *rdev, @@ -911,6 +912,30 @@ static ssize_t bypass_show(struct device *dev, } static DEVICE_ATTR_RO(bypass); +#define REGULATOR_ERROR_ATTR(name, bit) \ + static ssize_t name##_show(struct device *dev, struct device_attribute *attr, \ + char *buf) \ + { \ + int ret; \ + unsigned int flags; \ + struct regulator_dev *rdev = dev_get_drvdata(dev); \ + ret = _regulator_get_error_flags(rdev, &flags); \ + if (ret) \ + return ret; \ + return sysfs_emit(buf, "%d\n", !!(flags & (bit))); \ + } \ + static DEVICE_ATTR_RO(name) + +REGULATOR_ERROR_ATTR(under_voltage, REGULATOR_ERROR_UNDER_VOLTAGE); +REGULATOR_ERROR_ATTR(over_current, REGULATOR_ERROR_OVER_CURRENT); +REGULATOR_ERROR_ATTR(regulation_out, REGULATOR_ERROR_REGULATION_OUT); +REGULATOR_ERROR_ATTR(fail, REGULATOR_ERROR_FAIL); +REGULATOR_ERROR_ATTR(over_temp, REGULATOR_ERROR_OVER_TEMP); +REGULATOR_ERROR_ATTR(under_voltage_warn, REGULATOR_ERROR_UNDER_VOLTAGE_WARN); +REGULATOR_ERROR_ATTR(over_current_warn, REGULATOR_ERROR_OVER_CURRENT_WARN); +REGULATOR_ERROR_ATTR(over_voltage_warn, REGULATOR_ERROR_OVER_VOLTAGE_WARN); +REGULATOR_ERROR_ATTR(over_temp_warn, REGULATOR_ERROR_OVER_TEMP_WARN); + /* Calculate the new optimum regulator operating mode based on the new total * consumer load. All locks held by caller */ @@ -4984,6 +5009,15 @@ static struct attribute *regulator_dev_attrs[] = { &dev_attr_max_microvolts.attr, &dev_attr_min_microamps.attr, &dev_attr_max_microamps.attr, + &dev_attr_under_voltage.attr, + &dev_attr_over_current.attr, + &dev_attr_regulation_out.attr, + &dev_attr_fail.attr, + &dev_attr_over_temp.attr, + &dev_attr_under_voltage_warn.attr, + &dev_attr_over_current_warn.attr, + &dev_attr_over_voltage_warn.attr, + &dev_attr_over_temp_warn.attr, &dev_attr_suspend_standby_state.attr, &dev_attr_suspend_mem_state.attr, &dev_attr_suspend_disk_state.attr, @@ -5039,6 +5073,17 @@ static umode_t regulator_attr_is_visible(struct kobject *kobj, if (attr == &dev_attr_bypass.attr) return ops->get_bypass ? mode : 0; + if (attr == &dev_attr_under_voltage.attr || + attr == &dev_attr_over_current.attr || + attr == &dev_attr_regulation_out.attr || + attr == &dev_attr_fail.attr || + attr == &dev_attr_over_temp.attr || + attr == &dev_attr_under_voltage_warn.attr || + attr == &dev_attr_over_current_warn.attr || + attr == &dev_attr_over_voltage_warn.attr || + attr == &dev_attr_over_temp_warn.attr) + return ops->get_error_flags ? mode : 0; + /* constraints need specific supporting methods */ if (attr == &dev_attr_min_microvolts.attr || attr == &dev_attr_max_microvolts.attr) -- cgit v1.2.3 From c3e3ca05dae37f8f74bb80358efd540911cbc2c8 Mon Sep 17 00:00:00 2001 From: Zev Weiss Date: Wed, 4 May 2022 21:31:52 -0700 Subject: regulator: core: Fix enable_count imbalance with EXCLUSIVE_GET Since the introduction of regulator->enable_count, a driver that did an exclusive get on an already-enabled regulator would end up with enable_count initialized to 0 but rdev->use_count initialized to 1. With that starting point the regulator is effectively stuck enabled, because if the driver attempted to disable it it would fail the enable_count underflow check in _regulator_handle_consumer_disable(). The EXCLUSIVE_GET path in _regulator_get() now initializes enable_count along with rdev->use_count so that the regulator can be disabled without underflowing the former. Signed-off-by: Zev Weiss Fixes: 5451781dadf85 ("regulator: core: Only count load for enabled consumers") Link: https://lore.kernel.org/r/20220505043152.12933-1-zev@bewilderbeest.net Signed-off-by: Mark Brown --- drivers/regulator/core.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/regulator/core.c b/drivers/regulator/core.c index d2553970a67b..c4d844ffad7a 100644 --- a/drivers/regulator/core.c +++ b/drivers/regulator/core.c @@ -2133,10 +2133,13 @@ struct regulator *_regulator_get(struct device *dev, const char *id, rdev->exclusive = 1; ret = _regulator_is_enabled(rdev); - if (ret > 0) + if (ret > 0) { rdev->use_count = 1; - else + regulator->enable_count = 1; + } else { rdev->use_count = 0; + regulator->enable_count = 0; + } } link = device_link_add(dev, &rdev->dev, DL_FLAG_STATELESS); -- cgit v1.2.3 From b11b3d21a94d66bc05d1142e0b210bfa316c62be Mon Sep 17 00:00:00 2001 From: Konrad Dybcio Date: Sat, 30 Apr 2022 18:37:52 +0200 Subject: regulator: qcom_smd: Fix up PM8950 regulator configuration Following changes have been made: - S5, L4, L18, L20 and L21 were removed (S5 is managed by SPMI, whereas the rest seems not to exist [or at least it's blocked by Sony Loire /MSM8956/ RPM firmware]) - Supply maps have were adjusted to reflect regulator changes. Fixes: e44adca5fa25 ("regulator: qcom_smd: Add PM8950 regulators") Signed-off-by: Konrad Dybcio Link: https://lore.kernel.org/r/20220430163753.609909-1-konrad.dybcio@somainline.org Signed-off-by: Mark Brown --- drivers/regulator/qcom_smd-regulator.c | 35 +++++++++++++++++----------------- 1 file changed, 17 insertions(+), 18 deletions(-) (limited to 'drivers') diff --git a/drivers/regulator/qcom_smd-regulator.c b/drivers/regulator/qcom_smd-regulator.c index 8490aa8eecb1..7dff94a2eb7e 100644 --- a/drivers/regulator/qcom_smd-regulator.c +++ b/drivers/regulator/qcom_smd-regulator.c @@ -944,32 +944,31 @@ static const struct rpm_regulator_data rpm_pm8950_regulators[] = { { "s2", QCOM_SMD_RPM_SMPA, 2, &pm8950_hfsmps, "vdd_s2" }, { "s3", QCOM_SMD_RPM_SMPA, 3, &pm8950_hfsmps, "vdd_s3" }, { "s4", QCOM_SMD_RPM_SMPA, 4, &pm8950_hfsmps, "vdd_s4" }, - { "s5", QCOM_SMD_RPM_SMPA, 5, &pm8950_ftsmps2p5, "vdd_s5" }, + /* S5 is managed via SPMI. */ { "s6", QCOM_SMD_RPM_SMPA, 6, &pm8950_hfsmps, "vdd_s6" }, { "l1", QCOM_SMD_RPM_LDOA, 1, &pm8950_ult_nldo, "vdd_l1_l19" }, { "l2", QCOM_SMD_RPM_LDOA, 2, &pm8950_ult_nldo, "vdd_l2_l23" }, { "l3", QCOM_SMD_RPM_LDOA, 3, &pm8950_ult_nldo, "vdd_l3" }, - { "l4", QCOM_SMD_RPM_LDOA, 4, &pm8950_ult_pldo, "vdd_l4_l5_l6_l7_l16" }, - { "l5", QCOM_SMD_RPM_LDOA, 5, &pm8950_pldo_lv, "vdd_l4_l5_l6_l7_l16" }, - { "l6", QCOM_SMD_RPM_LDOA, 6, &pm8950_pldo_lv, "vdd_l4_l5_l6_l7_l16" }, - { "l7", QCOM_SMD_RPM_LDOA, 7, &pm8950_pldo_lv, "vdd_l4_l5_l6_l7_l16" }, + /* L4 seems not to exist. */ + { "l5", QCOM_SMD_RPM_LDOA, 5, &pm8950_pldo_lv, "vdd_l5_l6_l7_l16" }, + { "l6", QCOM_SMD_RPM_LDOA, 6, &pm8950_pldo_lv, "vdd_l5_l6_l7_l16" }, + { "l7", QCOM_SMD_RPM_LDOA, 7, &pm8950_pldo_lv, "vdd_l5_l6_l7_l16" }, { "l8", QCOM_SMD_RPM_LDOA, 8, &pm8950_ult_pldo, "vdd_l8_l11_l12_l17_l22" }, { "l9", QCOM_SMD_RPM_LDOA, 9, &pm8950_ult_pldo, "vdd_l9_l10_l13_l14_l15_l18" }, { "l10", QCOM_SMD_RPM_LDOA, 10, &pm8950_ult_nldo, "vdd_l9_l10_l13_l14_l15_l18"}, - { "l11", QCOM_SMD_RPM_LDOA, 11, &pm8950_ult_pldo, "vdd_l8_l11_l12_l17_l22"}, - { "l12", QCOM_SMD_RPM_LDOA, 12, &pm8950_ult_pldo, "vdd_l8_l11_l12_l17_l22"}, - { "l13", QCOM_SMD_RPM_LDOA, 13, &pm8950_ult_pldo, "vdd_l9_l10_l13_l14_l15_l18"}, - { "l14", QCOM_SMD_RPM_LDOA, 14, &pm8950_ult_pldo, "vdd_l9_l10_l13_l14_l15_l18"}, - { "l15", QCOM_SMD_RPM_LDOA, 15, &pm8950_ult_pldo, "vdd_l9_l10_l13_l14_l15_l18"}, - { "l16", QCOM_SMD_RPM_LDOA, 16, &pm8950_ult_pldo, "vdd_l4_l5_l6_l7_l16"}, - { "l17", QCOM_SMD_RPM_LDOA, 17, &pm8950_ult_pldo, "vdd_l8_l11_l12_l17_l22"}, - { "l18", QCOM_SMD_RPM_LDOA, 18, &pm8950_ult_pldo, "vdd_l9_l10_l13_l14_l15_l18"}, - { "l19", QCOM_SMD_RPM_LDOA, 18, &pm8950_pldo, "vdd_l1_l19"}, - { "l20", QCOM_SMD_RPM_LDOA, 18, &pm8950_pldo, "vdd_l20"}, - { "l21", QCOM_SMD_RPM_LDOA, 18, &pm8950_pldo, "vdd_l21"}, - { "l22", QCOM_SMD_RPM_LDOA, 18, &pm8950_pldo, "vdd_l8_l11_l12_l17_l22"}, - { "l23", QCOM_SMD_RPM_LDOA, 18, &pm8950_pldo, "vdd_l2_l23"}, + { "l11", QCOM_SMD_RPM_LDOA, 11, &pm8950_ult_pldo, "vdd_l8_l11_l12_l17_l22" }, + { "l12", QCOM_SMD_RPM_LDOA, 12, &pm8950_ult_pldo, "vdd_l8_l11_l12_l17_l22" }, + { "l13", QCOM_SMD_RPM_LDOA, 13, &pm8950_ult_pldo, "vdd_l9_l10_l13_l14_l15_l18" }, + { "l14", QCOM_SMD_RPM_LDOA, 14, &pm8950_ult_pldo, "vdd_l9_l10_l13_l14_l15_l18" }, + { "l15", QCOM_SMD_RPM_LDOA, 15, &pm8950_ult_pldo, "vdd_l9_l10_l13_l14_l15_l18" }, + { "l16", QCOM_SMD_RPM_LDOA, 16, &pm8950_ult_pldo, "vdd_l5_l6_l7_l16" }, + { "l17", QCOM_SMD_RPM_LDOA, 17, &pm8950_ult_pldo, "vdd_l8_l11_l12_l17_l22" }, + /* L18 seems not to exist. */ + { "l19", QCOM_SMD_RPM_LDOA, 19, &pm8950_pldo, "vdd_l1_l19" }, + /* L20 & L21 seem not to exist. */ + { "l22", QCOM_SMD_RPM_LDOA, 22, &pm8950_pldo, "vdd_l8_l11_l12_l17_l22" }, + { "l23", QCOM_SMD_RPM_LDOA, 23, &pm8950_pldo, "vdd_l2_l23" }, {} }; -- cgit v1.2.3 From afaa7b933ef00a2d3262f4d1252087613fb5c06d Mon Sep 17 00:00:00 2001 From: Miaoqian Lin Date: Wed, 11 May 2022 15:35:05 +0400 Subject: regulator: pfuze100: Fix refcount leak in pfuze_parse_regulators_dt of_node_get() returns a node with refcount incremented. Calling of_node_put() to drop the reference when not needed anymore. Fixes: 3784b6d64dc5 ("regulator: pfuze100: add pfuze100 regulator driver") Signed-off-by: Miaoqian Lin Link: https://lore.kernel.org/r/20220511113506.45185-1-linmq006@gmail.com Signed-off-by: Mark Brown --- drivers/regulator/pfuze100-regulator.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'drivers') diff --git a/drivers/regulator/pfuze100-regulator.c b/drivers/regulator/pfuze100-regulator.c index d60d7d1b7fa2..aa55cfca9e40 100644 --- a/drivers/regulator/pfuze100-regulator.c +++ b/drivers/regulator/pfuze100-regulator.c @@ -521,6 +521,7 @@ static int pfuze_parse_regulators_dt(struct pfuze_chip *chip) parent = of_get_child_by_name(np, "regulators"); if (!parent) { dev_err(dev, "regulators node not found\n"); + of_node_put(np); return -EINVAL; } @@ -550,6 +551,7 @@ static int pfuze_parse_regulators_dt(struct pfuze_chip *chip) } of_node_put(parent); + of_node_put(np); if (ret < 0) { dev_err(dev, "Error parsing regulator init data: %d\n", ret); -- cgit v1.2.3 From 68d6c8476fd4f448e70e0ab31ff972838ac41dae Mon Sep 17 00:00:00 2001 From: Miaoqian Lin Date: Mon, 16 May 2022 11:44:33 +0400 Subject: regulator: scmi: Fix refcount leak in scmi_regulator_probe of_find_node_by_name() returns a node pointer with refcount incremented, we should use of_node_put() on it when done. Add missing of_node_put() to avoid refcount leak. Fixes: 0fbeae70ee7c ("regulator: add SCMI driver") Signed-off-by: Miaoqian Lin Link: https://lore.kernel.org/r/20220516074433.32433-1-linmq006@gmail.com Signed-off-by: Mark Brown --- drivers/regulator/scmi-regulator.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/regulator/scmi-regulator.c b/drivers/regulator/scmi-regulator.c index 1f02f60ad136..41ae7ac27ff6 100644 --- a/drivers/regulator/scmi-regulator.c +++ b/drivers/regulator/scmi-regulator.c @@ -352,7 +352,7 @@ static int scmi_regulator_probe(struct scmi_device *sdev) return ret; } } - + of_node_put(np); /* * Register a regulator for each valid regulator-DT-entry that we * can successfully reach via SCMI and has a valid associated voltage -- cgit v1.2.3