diff options
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/regulator/Kconfig | 17 | ||||
-rw-r--r-- | drivers/regulator/Makefile | 2 | ||||
-rw-r--r-- | drivers/regulator/core.c | 93 | ||||
-rw-r--r-- | drivers/regulator/da9121-regulator.c | 2 | ||||
-rw-r--r-- | drivers/regulator/fixed.c | 5 | ||||
-rw-r--r-- | drivers/regulator/mt6358-regulator.c | 213 | ||||
-rw-r--r-- | drivers/regulator/pca9450-regulator.c | 27 | ||||
-rw-r--r-- | drivers/regulator/pfuze100-regulator.c | 2 | ||||
-rw-r--r-- | drivers/regulator/qcom_smd-regulator.c | 35 | ||||
-rw-r--r-- | drivers/regulator/rpi-panel-attiny-regulator.c | 1 | ||||
-rw-r--r-- | drivers/regulator/rt4801-regulator.c | 49 | ||||
-rw-r--r-- | drivers/regulator/rt5759-regulator.c | 369 | ||||
-rw-r--r-- | drivers/regulator/scmi-regulator.c | 2 | ||||
-rw-r--r-- | drivers/regulator/sm5703-regulator.c | 167 | ||||
-rw-r--r-- | drivers/regulator/stm32-vrefbuf.c | 30 |
15 files changed, 937 insertions, 77 deletions
diff --git a/drivers/regulator/Kconfig b/drivers/regulator/Kconfig index 5ef2306fce04..cbe0f96ca342 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 @@ -1157,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 1b64ad5767be..8d3ee8b6d41d 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 @@ -138,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/core.c b/drivers/regulator/core.c index d2553970a67b..1e54a833f2cf 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 */ @@ -1522,6 +1547,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. */ @@ -2133,10 +2176,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); @@ -2511,17 +2557,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; @@ -2603,7 +2649,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) { @@ -2630,14 +2676,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); @@ -2656,7 +2702,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)); @@ -3548,12 +3594,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; @@ -4971,6 +5012,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, @@ -5026,6 +5076,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) 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 */ 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) 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/drivers/regulator/pca9450-regulator.c b/drivers/regulator/pca9450-regulator.c index 64e5f5f0cc84..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; } @@ -702,6 +710,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,14 +811,30 @@ 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; } + 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/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); 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" }, {} }; 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; 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++) { 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 <linux/bits.h> +#include <linux/i2c.h> +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/of_device.h> +#include <linux/regmap.h> +#include <linux/regulator/driver.h> +#include <linux/regulator/of_regulator.h> + +#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 <cy_huang@richtek.com>"); +MODULE_DESCRIPTION("Richtek RT5759 Regulator Driver"); +MODULE_LICENSE("GPL v2"); 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 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 <linux/mfd/sm5703.h> +#include <linux/module.h> +#include <linux/mod_devicetable.h> +#include <linux/platform_device.h> +#include <linux/regmap.h> +#include <linux/regulator/driver.h> +#include <linux/regulator/of_regulator.h> + +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 <markuss.broks@gmail.com>"); +MODULE_LICENSE("GPL"); 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); |