summaryrefslogtreecommitdiff
path: root/drivers
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2022-05-24 15:09:47 -0700
committerLinus Torvalds <torvalds@linux-foundation.org>2022-05-24 15:09:47 -0700
commit9b18d07ba3ae75fcb7a191fafe4e2954f07271be (patch)
treeb3f3d995a9a8a746fd66fb769154c016dbc8c19e /drivers
parent5d23bb5f25ed9cbf530b99640f4f17f59b79de9e (diff)
parenta5b8e4a5ceec0ab6453176bc7f5eceafa78bf8a9 (diff)
Merge tag 'regulator-v5.19' of git://git.kernel.org/pub/scm/linux/kernel/git/broonie/regulator
Pull regulator updates from Mark Brown: "This is mostly a drivers update including a couple of new drivers but we do have some fixes and improvements to the core as well. - Make sure we don't log spuriously about uncontrollable regulators. - Don't use delays when we should use sleeps for regulators with larger ramp times. - Support for MediaTek MT6358 and MT6366, Richtek RT5759 and Silicon Mitus SM5703" * tag 'regulator-v5.19' of git://git.kernel.org/pub/scm/linux/kernel/git/broonie/regulator: (36 commits) regulator: scmi: Fix refcount leak in scmi_regulator_probe regulator: pfuze100: Fix refcount leak in pfuze_parse_regulators_dt regulator: qcom_smd: Fix up PM8950 regulator configuration regulator: core: Fix enable_count imbalance with EXCLUSIVE_GET regulator: core: Add error flags to sysfs attributes regulator: dt-bindings: qcom,rpmh: document vdd-l7-bob-supply on PMR735A regulator: dt-bindings: qcom,rpmh: document supplies per variant regulator: dt-bindings: qcom,rpmh: update maintainers regulator: mt6315: Enforce regulator-compatible, not name regulator: pca9450: Enable DVS control via PMIC_STBY_REQ regulator: pca9450: Make warm reset on WDOG_B assertion regulator: Add property for WDOG_B warm reset regulator: pca9450: Make I2C Level Translator configurable regulator: Add property for I2C level shifter regulator: sm5703: Correct reference to the common regulator schema regulator: sm5703-regulator: Add regulators support for SM5703 MFD dt-bindings: regulator: Add bindings for Silicon Mitus SM5703 regulators regulator: richtek,rt4801: parse GPIOs per regulator regulator: dt-bindings: richtek,rt4801: use existing ena_gpiod feature regulator: core: Sleep (not delay) in set_voltage() ...
Diffstat (limited to 'drivers')
-rw-r--r--drivers/regulator/Kconfig17
-rw-r--r--drivers/regulator/Makefile2
-rw-r--r--drivers/regulator/core.c93
-rw-r--r--drivers/regulator/da9121-regulator.c2
-rw-r--r--drivers/regulator/fixed.c5
-rw-r--r--drivers/regulator/mt6358-regulator.c213
-rw-r--r--drivers/regulator/pca9450-regulator.c27
-rw-r--r--drivers/regulator/pfuze100-regulator.c2
-rw-r--r--drivers/regulator/qcom_smd-regulator.c35
-rw-r--r--drivers/regulator/rpi-panel-attiny-regulator.c1
-rw-r--r--drivers/regulator/rt4801-regulator.c49
-rw-r--r--drivers/regulator/rt5759-regulator.c369
-rw-r--r--drivers/regulator/scmi-regulator.c2
-rw-r--r--drivers/regulator/sm5703-regulator.c167
-rw-r--r--drivers/regulator/stm32-vrefbuf.c30
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, &regval);
+ 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, &reg_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);