From 7a89ec1b4fcc89420b3473705da33097edf6aea6 Mon Sep 17 00:00:00 2001 From: Eduard Bostina Date: Sat, 15 Aug 2026 08:29:13 +0000 Subject: regulator: dt-bindings: Convert TPS65023 to DT schema Convert the Texas Instruments TPS65023 family of PMICs bindings to DT schema. Signed-off-by: Eduard Bostina Reviewed-by: Krzysztof Kozlowski Link: https://patch.msgid.link/20260815082913.2144978-1-egbostina@gmail.com Signed-off-by: Mark Brown --- .../devicetree/bindings/regulator/ti,tps65023.yaml | 90 ++++++++++++++++++++++ .../devicetree/bindings/regulator/tps65023.txt | 60 --------------- 2 files changed, 90 insertions(+), 60 deletions(-) create mode 100644 Documentation/devicetree/bindings/regulator/ti,tps65023.yaml delete mode 100644 Documentation/devicetree/bindings/regulator/tps65023.txt diff --git a/Documentation/devicetree/bindings/regulator/ti,tps65023.yaml b/Documentation/devicetree/bindings/regulator/ti,tps65023.yaml new file mode 100644 index 000000000000..928698595f52 --- /dev/null +++ b/Documentation/devicetree/bindings/regulator/ti,tps65023.yaml @@ -0,0 +1,90 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/regulator/ti,tps65023.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Texas Instruments TPS65023 Regulator + +maintainers: + - Eduard Bostina + +properties: + compatible: + enum: + - ti,tps65020 + - ti,tps65021 + - ti,tps65023 + + reg: + maxItems: 1 + + regulators: + type: object + description: > + List of child nodes that specify the regulator initialization data. + Must be named after their hardware counterparts: VDCDC[1-3] and LDO[1-2]. + + patternProperties: + "^(VDCDC[1-3]|LDO[1-2])$": + type: object + $ref: regulator.yaml# + unevaluatedProperties: false + + additionalProperties: false + +required: + - compatible + - reg + - regulators + +additionalProperties: false + +examples: + - | + i2c { + #address-cells = <1>; + #size-cells = <0>; + + tps65023@48 { + compatible = "ti,tps65023"; + reg = <0x48>; + + regulators { + VDCDC1 { + regulator-name = "vdd_mpu"; + regulator-always-on; + regulator-min-microvolt = <1200000>; + regulator-max-microvolt = <1200000>; + }; + + VDCDC2 { + regulator-name = "vdd_core"; + regulator-always-on; + regulator-min-microvolt = <3300000>; + regulator-max-microvolt = <3300000>; + }; + + VDCDC3 { + regulator-name = "vdd_io"; + regulator-always-on; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + }; + + LDO1 { + regulator-name = "vdd_usb18"; + regulator-always-on; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + }; + + LDO2 { + regulator-name = "vdd_usb33"; + regulator-always-on; + regulator-min-microvolt = <3300000>; + regulator-max-microvolt = <3300000>; + }; + }; + }; + }; diff --git a/Documentation/devicetree/bindings/regulator/tps65023.txt b/Documentation/devicetree/bindings/regulator/tps65023.txt deleted file mode 100644 index a4714e4da370..000000000000 --- a/Documentation/devicetree/bindings/regulator/tps65023.txt +++ /dev/null @@ -1,60 +0,0 @@ -TPS65023 family of regulators - -Required properties: -- compatible: Must be one of the following. - "ti,tps65020", - "ti,tps65021", - "ti,tps65023", -- reg: I2C slave address -- regulators: list of regulators provided by this controller, must be named - after their hardware counterparts: VDCDC[1-3] and LDO[1-2] -- regulators: This is the list of child nodes that specify the regulator - initialization data for defined regulators. The definition for each of - these nodes is defined using the standard binding for regulators found at - Documentation/devicetree/bindings/regulator/regulator.txt. - -Each regulator is defined using the standard binding for regulators. - -Example: - - tps65023@48 { - compatible = "ti,tps65023"; - reg = <0x48>; - - regulators { - VDCDC1 { - regulator-name = "vdd_mpu"; - regulator-always-on; - regulator-min-microvolt = <1200000>; - regulator-max-microvolt = <1200000>; - }; - - VDCDC2 { - regulator-name = "vdd_core"; - regulator-always-on; - regulator-min-microvolt = <3300000>; - regulator-max-microvolt = <3300000>; - }; - - VDCDC3 { - regulator-name = "vdd_io"; - regulator-always-on; - regulator-min-microvolt = <1800000>; - regulator-max-microvolt = <1800000>; - }; - - LDO1 { - regulator-name = "vdd_usb18"; - regulator-always-on; - regulator-min-microvolt = <1800000>; - regulator-max-microvolt = <1800000>; - }; - - LDO2 { - regulator-name = "vdd_usb33"; - regulator-always-on; - regulator-min-microvolt = <3300000>; - regulator-max-microvolt = <3300000>; - }; - }; - }; -- cgit v1.2.3 From 97350c1541d0182195f022f459840a8bd3747b2b Mon Sep 17 00:00:00 2001 From: Fabio Estevam Date: Mon, 17 Aug 2026 22:40:58 -0300 Subject: regulator: pca9450: Use LDO5 low-control enable mask LDO5 has voltage-selection fields in both LDO5CTRL_L and LDO5CTRL_H, selected by the SD_VSEL pin. Its ENMODE field, however, is only in LDO5CTRL_L. The regulator descriptors correctly use LDO5CTRL_L as enable_reg, but use the misleading LDO5H_EN_MASK name for enable_mask. Both mask definitions have the same value, so this causes no functional problem. Use LDO5L_EN_MASK in all LDO5 descriptors and remove the unused LDO5H_EN_MASK definition. Signed-off-by: Fabio Estevam Link: https://patch.msgid.link/20260818014059.351152-1-festevam@gmail.com Signed-off-by: Mark Brown --- drivers/regulator/pca9450-regulator.c | 6 +++--- include/linux/regulator/pca9450.h | 1 - 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/drivers/regulator/pca9450-regulator.c b/drivers/regulator/pca9450-regulator.c index c41db70fa052..93d0af7f7eda 100644 --- a/drivers/regulator/pca9450-regulator.c +++ b/drivers/regulator/pca9450-regulator.c @@ -621,7 +621,7 @@ static struct pca9450_regulator_desc pca9450a_regulators[] = { .vsel_reg = PCA9450_REG_LDO5CTRL_H, .vsel_mask = LDO5HOUT_MASK, .enable_reg = PCA9450_REG_LDO5CTRL_L, - .enable_mask = LDO5H_EN_MASK, + .enable_mask = LDO5L_EN_MASK, .owner = THIS_MODULE, }, }, @@ -866,7 +866,7 @@ static struct pca9450_regulator_desc pca9450bc_regulators[] = { .vsel_reg = PCA9450_REG_LDO5CTRL_H, .vsel_mask = LDO5HOUT_MASK, .enable_reg = PCA9450_REG_LDO5CTRL_L, - .enable_mask = LDO5H_EN_MASK, + .enable_mask = LDO5L_EN_MASK, .owner = THIS_MODULE, }, }, @@ -1086,7 +1086,7 @@ static struct pca9450_regulator_desc pca9451a_regulators[] = { .vsel_reg = PCA9450_REG_LDO5CTRL_H, .vsel_mask = LDO5HOUT_MASK, .enable_reg = PCA9450_REG_LDO5CTRL_L, - .enable_mask = LDO5H_EN_MASK, + .enable_mask = LDO5L_EN_MASK, .owner = THIS_MODULE, }, }, diff --git a/include/linux/regulator/pca9450.h b/include/linux/regulator/pca9450.h index 0df8b3c48082..2aa73624d0b8 100644 --- a/include/linux/regulator/pca9450.h +++ b/include/linux/regulator/pca9450.h @@ -210,7 +210,6 @@ enum { #define LDO5L_EN_MASK 0xC0 #define LDO5LOUT_MASK 0x0F -#define LDO5H_EN_MASK 0xC0 #define LDO5HOUT_MASK 0x0F /* PCA9450_REG_IRQ bits */ -- cgit v1.2.3 From 0c47038219a048b12c7e095d6f4b0cdd146e878a Mon Sep 17 00:00:00 2001 From: Fabio Estevam Date: Mon, 17 Aug 2026 22:40:59 -0300 Subject: regulator: pca9450: Support regulator-off-in-suspend The PCA9450 uses each regulator's ENMODE field to control whether the regulator remains enabled when the PMIC transitions from RUN to STANDBY mode. The driver does not currently implement set_suspend_disable(), so a regulator configured with regulator-off-in-suspend remains enabled during system suspend. Implement set_suspend_disable() for the buck regulators and LDO3-LDO5. The suspend and runtime controls share ENMODE, so first read the field and leave it unchanged when it is 00b. This preserves the state of a regulator that was already disabled at runtime. For an enabled regulator, program 10b to keep it on in RUN and turn it off while PMIC_STBY_REQ is asserted. Most buck descriptors set enable_val to 01b, while BUCK2 uses 10b. When enable_val is nonzero, regulator_is_enabled_regmap() checks for an exact match. It would therefore report most bucks as disabled after their ENMODE is changed from 01b to 10b, even though all valid nonzero ENMODE values enable the regulator in RUN. Use a custom is_enabled() helper for the buck operation tables that considers a nonzero ENMODE enabled. The LDO descriptors leave enable_val at zero, for which the generic helper already performs this nonzero check, so keep using it for the LDOs. Runtime enable and disable operations remain unchanged: disable writes 00b and enable writes the regulator's default mode. The suspend callback reapplies 10b on each suspend after any intervening runtime operation. Keep LDO1 and LDO2 on regulator operations without set_suspend_disable(), because these regulators supply the SNVS domain and must remain enabled in STANDBY mode. Measured on a custom i.MX8MP board, turning off NVCC_SD2 (LDO5) during system suspend reduced power consumption by approximately 64 mW. Signed-off-by: Fabio Estevam Link: https://patch.msgid.link/20260818014059.351152-2-festevam@gmail.com Signed-off-by: Mark Brown --- drivers/regulator/pca9450-regulator.c | 75 +++++++++++++++++++++++++++++++---- include/linux/regulator/pca9450.h | 3 ++ 2 files changed, 70 insertions(+), 8 deletions(-) diff --git a/drivers/regulator/pca9450-regulator.c b/drivers/regulator/pca9450-regulator.c index 93d0af7f7eda..613bce411f31 100644 --- a/drivers/regulator/pca9450-regulator.c +++ b/drivers/regulator/pca9450-regulator.c @@ -77,10 +77,56 @@ static const unsigned int pca9450_dvs_buck_ramp_table[] = { 25000, 12500, 6250, 3125 }; +static int pca9450_regulator_is_enabled(struct regulator_dev *rdev) +{ + unsigned int val; + int ret; + + ret = regmap_read(rdev->regmap, rdev->desc->enable_reg, &val); + if (ret) + return ret; + + /* All valid nonzero ENMODE values enable the regulator in RUN mode. */ + return !!(val & rdev->desc->enable_mask); +} + +static int pca9450_set_suspend_disable(struct regulator_dev *rdev, + unsigned int suspend_val) +{ + int ret; + + /* Do not enable a runtime-disabled regulator when returning to RUN. */ + ret = pca9450_regulator_is_enabled(rdev); + if (ret < 0) + return ret; + if (!ret) + return 0; + + return regmap_update_bits(rdev->regmap, rdev->desc->enable_reg, + rdev->desc->enable_mask, + suspend_val); +} + +/* + * ENMODE = 10b keeps the regulator enabled in RUN mode and disables it + * while PMIC_STBY_REQ is asserted. + */ +static int pca9450_buck_set_suspend_disable(struct regulator_dev *rdev) +{ + return pca9450_set_suspend_disable(rdev, + BUCK_ENMODE_ONREQ_STBYREQ); +} + +static int pca9450_ldo_set_suspend_disable(struct regulator_dev *rdev) +{ + return pca9450_set_suspend_disable(rdev, + LDO_ENMODE_ONREQ_STBYREQ); +} + static const struct regulator_ops pca9450_dvs_buck_regulator_ops = { .enable = regulator_enable_regmap, .disable = regulator_disable_regmap, - .is_enabled = regulator_is_enabled_regmap, + .is_enabled = pca9450_regulator_is_enabled, .list_voltage = regulator_list_voltage_linear_range, .set_voltage_sel = regulator_set_voltage_sel_regmap, .get_voltage_sel = regulator_get_voltage_sel_regmap, @@ -88,18 +134,20 @@ static const struct regulator_ops pca9450_dvs_buck_regulator_ops = { .set_ramp_delay = regulator_set_ramp_delay_regmap, .set_mode = pca9450_buck_set_mode, .get_mode = pca9450_buck_get_mode, + .set_suspend_disable = pca9450_buck_set_suspend_disable, }; static const struct regulator_ops pca9450_buck_regulator_ops = { .enable = regulator_enable_regmap, .disable = regulator_disable_regmap, - .is_enabled = regulator_is_enabled_regmap, + .is_enabled = pca9450_regulator_is_enabled, .list_voltage = regulator_list_voltage_linear_range, .set_voltage_sel = regulator_set_voltage_sel_regmap, .get_voltage_sel = regulator_get_voltage_sel_regmap, .set_voltage_time_sel = regulator_set_voltage_time_sel, .set_mode = pca9450_buck_set_mode, .get_mode = pca9450_buck_get_mode, + .set_suspend_disable = pca9450_buck_set_suspend_disable, }; static const struct regulator_ops pca9450_ldo_regulator_ops = { @@ -111,6 +159,16 @@ static const struct regulator_ops pca9450_ldo_regulator_ops = { .get_voltage_sel = regulator_get_voltage_sel_regmap, }; +static const struct regulator_ops pca9450_ldo_suspend_regulator_ops = { + .enable = regulator_enable_regmap, + .disable = regulator_disable_regmap, + .is_enabled = regulator_is_enabled_regmap, + .list_voltage = regulator_list_voltage_linear_range, + .set_voltage_sel = regulator_set_voltage_sel_regmap, + .get_voltage_sel = regulator_get_voltage_sel_regmap, + .set_suspend_disable = pca9450_ldo_set_suspend_disable, +}; + static unsigned int pca9450_ldo5_get_reg_voltage_sel(struct regulator_dev *rdev) { struct pca9450 *pca9450 = rdev_get_drvdata(rdev); @@ -164,6 +222,7 @@ static const struct regulator_ops pca9450_ldo5_regulator_ops = { .list_voltage = regulator_list_voltage_linear_range, .set_voltage_sel = pca9450_ldo5_set_voltage_sel_regmap, .get_voltage_sel = pca9450_ldo5_get_voltage_sel_regmap, + .set_suspend_disable = pca9450_ldo_set_suspend_disable, }; /* @@ -575,7 +634,7 @@ static struct pca9450_regulator_desc pca9450a_regulators[] = { .of_match = of_match_ptr("LDO3"), .regulators_node = of_match_ptr("regulators"), .id = PCA9450_LDO3, - .ops = &pca9450_ldo_regulator_ops, + .ops = &pca9450_ldo_suspend_regulator_ops, .type = REGULATOR_VOLTAGE, .n_voltages = PCA9450_LDO3_VOLTAGE_NUM, .linear_ranges = pca9450_ldo34_volts, @@ -594,7 +653,7 @@ static struct pca9450_regulator_desc pca9450a_regulators[] = { .of_match = of_match_ptr("LDO4"), .regulators_node = of_match_ptr("regulators"), .id = PCA9450_LDO4, - .ops = &pca9450_ldo_regulator_ops, + .ops = &pca9450_ldo_suspend_regulator_ops, .type = REGULATOR_VOLTAGE, .n_voltages = PCA9450_LDO4_VOLTAGE_NUM, .linear_ranges = pca9450_ldo34_volts, @@ -820,7 +879,7 @@ static struct pca9450_regulator_desc pca9450bc_regulators[] = { .of_match = of_match_ptr("LDO3"), .regulators_node = of_match_ptr("regulators"), .id = PCA9450_LDO3, - .ops = &pca9450_ldo_regulator_ops, + .ops = &pca9450_ldo_suspend_regulator_ops, .type = REGULATOR_VOLTAGE, .n_voltages = PCA9450_LDO3_VOLTAGE_NUM, .linear_ranges = pca9450_ldo34_volts, @@ -839,7 +898,7 @@ static struct pca9450_regulator_desc pca9450bc_regulators[] = { .of_match = of_match_ptr("LDO4"), .regulators_node = of_match_ptr("regulators"), .id = PCA9450_LDO4, - .ops = &pca9450_ldo_regulator_ops, + .ops = &pca9450_ldo_suspend_regulator_ops, .type = REGULATOR_VOLTAGE, .n_voltages = PCA9450_LDO4_VOLTAGE_NUM, .linear_ranges = pca9450_ldo34_volts, @@ -1040,7 +1099,7 @@ static struct pca9450_regulator_desc pca9451a_regulators[] = { .of_match = of_match_ptr("LDO3"), .regulators_node = of_match_ptr("regulators"), .id = PCA9450_LDO3, - .ops = &pca9450_ldo_regulator_ops, + .ops = &pca9450_ldo_suspend_regulator_ops, .type = REGULATOR_VOLTAGE, .n_voltages = PCA9450_LDO3_VOLTAGE_NUM, .linear_ranges = pca9450_ldo34_volts, @@ -1059,7 +1118,7 @@ static struct pca9450_regulator_desc pca9451a_regulators[] = { .of_match = of_match_ptr("LDO4"), .regulators_node = of_match_ptr("regulators"), .id = PCA9450_LDO4, - .ops = &pca9450_ldo_regulator_ops, + .ops = &pca9450_ldo_suspend_regulator_ops, .type = REGULATOR_VOLTAGE, .n_voltages = PCA9450_LDO4_VOLTAGE_NUM, .linear_ranges = pca9450_ldo34_volts, diff --git a/include/linux/regulator/pca9450.h b/include/linux/regulator/pca9450.h index 2aa73624d0b8..bf94df5fafe3 100644 --- a/include/linux/regulator/pca9450.h +++ b/include/linux/regulator/pca9450.h @@ -212,6 +212,9 @@ enum { #define LDO5HOUT_MASK 0x0F +/* LDO ENMODE value: ON in RUN, OFF while PMIC_STBY_REQ is asserted */ +#define LDO_ENMODE_ONREQ_STBYREQ 0x80 + /* PCA9450_REG_IRQ bits */ #define IRQ_PWRON 0x80 #define IRQ_WDOGB 0x40 -- cgit v1.2.3 From f7396c2dbbc1bed6c2c554d1ddf80d16e4780a7d Mon Sep 17 00:00:00 2001 From: Chandradhar Kumar Date: Sat, 22 Aug 2026 12:25:19 +0530 Subject: regulator: fixed: reject incompatible platform devices The fixed regulator driver expects non-DT platform devices to provide their configuration through platform_data as a struct fixed_voltage_config. An explicitly bound driver can bypass the normal platform device/driver matching and attach the fixed regulator driver to an unrelated platform device. This causes the driver's platform_data to be interpreted as a struct fixed_voltage_config even though it contains data for a different device. Reject non-DT platform devices whose name does not match the fixed regulator driver before accessing their platform data. Fixes: 4b74ff651249 ("regulator: add support for fixed regulators.") Reported-by: syzbot+bfc9e55cf4f98183c636@syzkaller.appspotmail.com Closes: https://syzbot.org/bug?extid=bfc9e55cf4f98183c636 Signed-off-by: Chandradhar Kumar Link: https://patch.msgid.link/20260822065519.112441-1-chandradhar.2003@gmail.com Signed-off-by: Mark Brown --- drivers/regulator/fixed.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/drivers/regulator/fixed.c b/drivers/regulator/fixed.c index 417d282dd4ed..faa82f30eb1f 100644 --- a/drivers/regulator/fixed.c +++ b/drivers/regulator/fixed.c @@ -28,6 +28,7 @@ #include #include #include +#include struct fixed_voltage_data { struct regulator_desc desc; @@ -225,6 +226,9 @@ static int reg_fixed_voltage_probe(struct platform_device *pdev) enum gpiod_flags gflags; int ret; + if (!pdev->dev.of_node && strcmp(pdev->name, "reg-fixed-voltage")) + return -ENODEV; + drvdata = devm_kzalloc(&pdev->dev, sizeof(struct fixed_voltage_data), GFP_KERNEL); if (!drvdata) -- cgit v1.2.3 From f0c54cc56a9a21047b1afa209baea8ea931f2e92 Mon Sep 17 00:00:00 2001 From: Donggeun Yoo Date: Thu, 3 Sep 2026 17:20:09 +0900 Subject: regulator: pf1550: fix division by zero in the ramp rate selection set_machine_constraints() calls the set_ramp_delay() op when either constraints->ramp_delay or constraints->ramp_disable is set. The regulator binding documents regulator-ramp-delay = <0> as the way to disable ramp control, and of_get_regulation_constraints() turns that into ramp_disable = true while leaving ramp_delay at 0, so the op is called with a ramp_delay of 0. The range check rejects negative values and values above 6250 but not zero, and the value is then used as a divisor. The mapping is also wrong for the values that do pass the check. The hardware offers two rates, 6250 uV/us and 3125 uV/us, selected by SWx_DVSSPEED in SWx_CTRL1. Dividing 6250 by the requested rate and taking bit 1 of the quotient does not map monotonically onto them: a request for 1500 uV/us selects 6250 uV/us, while a request for the faster 2000 uV/us selects 3125 uV/us. Replace the division with a direct mapping onto the two supported rates. Requests at or below 3125 uV/us get the slower rate and anything above it gets the faster one. A ramp_delay of 0 asks for ramp control to be disabled, which this hardware cannot do, so it gets the fastest rate; pfuze100 handles the disabled case the same way. Fixes: 7320d41c29bb ("regulator: pf1550: Add support for regulator") Signed-off-by: Donggeun Yoo Link: https://patch.msgid.link/20260903082010.4024603-1-donggeunyoo.kernel@gmail.com Signed-off-by: Mark Brown --- drivers/regulator/pf1550-regulator.c | 19 ++++++++++++++----- 1 file changed, 14 insertions(+), 5 deletions(-) diff --git a/drivers/regulator/pf1550-regulator.c b/drivers/regulator/pf1550-regulator.c index 610eac9bb9cb..5394bc784e1d 100644 --- a/drivers/regulator/pf1550-regulator.c +++ b/drivers/regulator/pf1550-regulator.c @@ -49,17 +49,26 @@ static const int pf1550_ldo13_volts[] = { static int pf1550_set_ramp_delay(struct regulator_dev *rdev, int ramp_delay) { int id = rdev_get_id(rdev); - unsigned int ramp_bits = 0; + unsigned int ramp_bits; int ret; if (id > PF1550_VREFDDR) return -EACCES; - if (ramp_delay < 0 || ramp_delay > 6250) + switch (ramp_delay) { + case 0: + /* Ramp control is disabled, so use the fastest rate. */ + ramp_bits = 0; + break; + case 1 ... 3125: + ramp_bits = 1; + break; + case 3126 ... 6250: + ramp_bits = 0; + break; + default: return -EINVAL; - - ramp_delay = 6250 / ramp_delay; - ramp_bits = ramp_delay >> 1; + } ret = regmap_update_bits(rdev->regmap, rdev->desc->vsel_reg + 4, 0x10, ramp_bits << 4); -- cgit v1.2.3 From 94235414a0568f260b60b89ec584ff4829d5e8c9 Mon Sep 17 00:00:00 2001 From: Lukas Beckmann Date: Sat, 22 Aug 2026 18:05:00 +0200 Subject: genirq: Discard cpumask of irqaffinity= boot parameter if parsing fails irq_affinity_setup() ignores the return value of cpulist_parse(). This can result in using a "half parsed" cpulist. E.g. on a system with 8 cores, the parameter "irqaffinity=0,1,6-10,4" would result in using only CPU 0 and 1, since the parsing fails at 6-10. Other boot parameters which take a cpulist (e.g. isolcpus=, workqueue.unbound_cpus=) already handle this by falling back to a default. Check the return value of cpulist_parse() and let init_irq_default_affinity() set the default in early_irq_init() later, if parsing fails. Signed-off-by: Lukas Beckmann Signed-off-by: Thomas Gleixner Reviewed-by: Radu Rendec Link: https://patch.msgid.link/20260822160502.4665-1-lbckmnn@mailbox.org --- kernel/irq/irqdesc.c | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/kernel/irq/irqdesc.c b/kernel/irq/irqdesc.c index 3a818f07a101..7cbcc3fb9e6d 100644 --- a/kernel/irq/irqdesc.c +++ b/kernel/irq/irqdesc.c @@ -28,7 +28,15 @@ static struct lock_class_key irq_desc_lock_class; static int __init irq_affinity_setup(char *str) { alloc_bootmem_cpumask_var(&irq_default_affinity); - cpulist_parse(str, irq_default_affinity); + if (cpulist_parse(str, irq_default_affinity) < 0) { + /* + * Clear the mask so that init_irq_default_affinity() + * defaults it later. + */ + cpumask_clear(irq_default_affinity); + pr_warn("irqaffinity: incorrect CPU range, using default\n"); + return 1; + } /* * Set at least the boot cpu. We don't want to end up with * bugreports caused by random commandline masks -- cgit v1.2.3 From 67f399a9ac7f3001cafc0cb1b645e3e5760779d2 Mon Sep 17 00:00:00 2001 From: Enlin Mu Date: Tue, 25 Aug 2026 09:15:09 +0800 Subject: softirq: Remove redundant h->action from preempt_count mismatch error When a preempt_count mismatch is detected in handle_softirqs(), the error message currently prints the softirq action handler (h->action). However, as Thomas Gleixner pointed out, the action handler for a given softirq vector is always a known, fixed function (e.g., run_timer_softirq for TIMER_SOFTIRQ). Printing it provides zero diagnostic value. The real issue typically lies in the functions invoked *within* that handler, not the handler entry point itself. Therefore, as suggested by Sebastian Andrzej Siewior, remove h->action from the print statement entirely to clean up the error message. Suggested-by: Thomas Gleixner Suggested-by: Sebastian Andrzej Siewior Signed-off-by: Enlin Mu Signed-off-by: Enlin Mu Signed-off-by: Thomas Gleixner Reviewed-by: Sebastian Andrzej Siewior Link: https://patch.msgid.link/20260825011509.8505-1-enlin.mu@linux.dev --- kernel/softirq.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/kernel/softirq.c b/kernel/softirq.c index 7980a4a232f9..800d81c57302 100644 --- a/kernel/softirq.c +++ b/kernel/softirq.c @@ -645,8 +645,8 @@ restart: h->action(); trace_softirq_exit(vec_nr); if (unlikely(prev_count != preempt_count())) { - pr_err("huh, entered softirq %u %s %p with preempt_count %08x, exited with %08x?\n", - vec_nr, softirq_to_name[vec_nr], h->action, + pr_err("huh, entered softirq %u %s with preempt_count %08x, exited with %08x?\n", + vec_nr, softirq_to_name[vec_nr], prev_count, preempt_count()); preempt_count_set(prev_count); } -- cgit v1.2.3 From 761f34e333ace119eacc3af70fec87fceeb76dc0 Mon Sep 17 00:00:00 2001 From: Diederik de Haas Date: Fri, 4 Sep 2026 16:46:31 +0200 Subject: regulator: tps65185: Remove redundant dev_err_probe() The devm_request_threaded_irq() function now automatically logs detailed error messages on failure. This eliminates the need for driver-specific dev_err_probe() calls that print generic messages. Signed-off-by: Diederik de Haas Link: https://patch.msgid.link/20260904144728.1629471-1-diederik@cknow-tech.com Signed-off-by: Mark Brown --- drivers/regulator/tps65185.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/drivers/regulator/tps65185.c b/drivers/regulator/tps65185.c index 6a3130177e7a..4865227e444a 100644 --- a/drivers/regulator/tps65185.c +++ b/drivers/regulator/tps65185.c @@ -392,8 +392,7 @@ static int tps65185_probe(struct i2c_client *client) IRQF_TRIGGER_RISING | IRQF_ONESHOT, "PGOOD", data); if (ret) - return dev_err_probe(&client->dev, ret, - "failed to request power good irq\n"); + return ret; if (client->irq) { ret = devm_request_threaded_irq(&client->dev, client->irq, @@ -401,8 +400,7 @@ static int tps65185_probe(struct i2c_client *client) IRQF_TRIGGER_LOW | IRQF_ONESHOT, "tps65185", data); if (ret) - return dev_err_probe(&client->dev, ret, - "failed to request irq\n"); + return ret; } ret = regmap_update_bits(data->regmap, TPS65185_REG_INT_EN2, BIT(0), BIT(0)); -- cgit v1.2.3 From 24fa0eadc2e3c7e9397924197dca7777ec08b8d7 Mon Sep 17 00:00:00 2001 From: Jisheng Zhang Date: Tue, 1 Sep 2026 12:31:21 +0800 Subject: regulator: mp886x: fix vsel_mask The MP886X vsel is 7bits, fix the vsel_mask. Fixes: 97be82880b61 ("regulator: add support for MP8869 regulator") Signed-off-by: Jisheng Zhang Link: https://patch.msgid.link/20260901043123.5401-2-jszhang@kernel.org Signed-off-by: Mark Brown --- drivers/regulator/mp886x.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/regulator/mp886x.c b/drivers/regulator/mp886x.c index e0b62bc02a1e..a10f3a20d413 100644 --- a/drivers/regulator/mp886x.c +++ b/drivers/regulator/mp886x.c @@ -267,7 +267,7 @@ static int mp886x_regulator_register(struct mp886x_device_info *di, rdesc->min_uV = 600000; rdesc->uV_step = 10000; rdesc->vsel_reg = MP886X_VSEL; - rdesc->vsel_mask = 0x3f; + rdesc->vsel_mask = 0x7f; rdesc->ramp_reg = MP886X_SYSCNTLREG1; rdesc->ramp_mask = MP886X_SLEW_MASK; rdesc->ramp_delay_table = di->ci->slew_rates; -- cgit v1.2.3 From c75d4f104f81197c1c405fba28025241b7419346 Mon Sep 17 00:00:00 2001 From: Jisheng Zhang Date: Tue, 1 Sep 2026 12:31:22 +0800 Subject: regulator: dt-bindings: mp886x: support mp8864 The MP8864 is a 4 A, 21 V synchronous step-down converter. Its register layout and voltage transition handling are compatible with the MP8867, but its selectable switching frequencies are 600 kHz, 850 kHz, 1.1 MHz and 1.6 MHz. Add the compatible and chip-specific switching-frequency table. Signed-off-by: Jisheng Zhang Assisted-by: Codex:gpt-5 Acked-by: Conor Dooley Link: https://patch.msgid.link/20260901043123.5401-3-jszhang@kernel.org Signed-off-by: Mark Brown --- .../devicetree/bindings/regulator/mps,mp886x.yaml | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/Documentation/devicetree/bindings/regulator/mps,mp886x.yaml b/Documentation/devicetree/bindings/regulator/mps,mp886x.yaml index 374a4f6b1e23..6cf7c1c3c0c3 100644 --- a/Documentation/devicetree/bindings/regulator/mps,mp886x.yaml +++ b/Documentation/devicetree/bindings/regulator/mps,mp886x.yaml @@ -4,17 +4,30 @@ $id: http://devicetree.org/schemas/regulator/mps,mp886x.yaml# $schema: http://devicetree.org/meta-schemas/core.yaml# -title: Monolithic Power Systems MP8867/MP8869 voltage regulator +title: Monolithic Power Systems MP8864/MP8867/MP8869 voltage regulator maintainers: - Jisheng Zhang allOf: - $ref: regulator.yaml# + - if: + properties: + compatible: + const: mps,mp8864 + then: + properties: + mps,switch-frequency-hz: + enum: [600000, 850000, 1100000, 1600000] + else: + properties: + mps,switch-frequency-hz: + enum: [500000, 750000, 1000000, 1250000, 1500000] properties: compatible: enum: + - mps,mp8864 - mps,mp8867 - mps,mp8869 @@ -33,7 +46,6 @@ properties: mps,switch-frequency-hz: description: The valid switch frequency in Hertz. - enum: [500000, 750000, 1000000, 1250000, 1500000] required: - compatible -- cgit v1.2.3 From 6c45fd3e18548ebb30a7a4bc5b2bfc1f875f4614 Mon Sep 17 00:00:00 2001 From: Jisheng Zhang Date: Tue, 1 Sep 2026 12:31:23 +0800 Subject: regulator: mp886x: add MP8864 support The MP8864 is a 4 A, 21 V synchronous step-down converter. Its register layout and voltage transition handling are compatible with the MP8867, but its selectable switching frequencies are 600 kHz, 850 kHz, 1.1 MHz and 1.6 MHz. Add the compatible and chip-specific switching-frequency table. Signed-off-by: Jisheng Zhang Assisted-by: Codex:gpt-5 Link: https://patch.msgid.link/20260901043123.5401-4-jszhang@kernel.org Signed-off-by: Mark Brown --- drivers/regulator/Kconfig | 2 +- drivers/regulator/mp886x.c | 21 ++++++++++++++++++++- 2 files changed, 21 insertions(+), 2 deletions(-) diff --git a/drivers/regulator/Kconfig b/drivers/regulator/Kconfig index 89789ac7a786..c8940e2c7e04 100644 --- a/drivers/regulator/Kconfig +++ b/drivers/regulator/Kconfig @@ -864,7 +864,7 @@ config REGULATOR_MP8859 module. The module will be named "mp8859". config REGULATOR_MP886X - tristate "MPS MP8869 regulator driver" + tristate "MPS MP8864/MP8867/MP8869 regulator driver" depends on I2C && OF select REGMAP_I2C help diff --git a/drivers/regulator/mp886x.c b/drivers/regulator/mp886x.c index a10f3a20d413..14f60cdcbbd6 100644 --- a/drivers/regulator/mp886x.c +++ b/drivers/regulator/mp886x.c @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0 // -// MP8867/MP8869 regulator driver +// MP8864/MP8867/MP8869 regulator driver // // Copyright (C) 2020 Synaptics Incorporated // @@ -229,6 +229,23 @@ static const struct regulator_ops mp8867_regulator_ops = { .set_ramp_delay = regulator_set_ramp_delay_regmap, }; +static const struct mp886x_cfg_info mp8864_ci = { + .rops = &mp8867_regulator_ops, + .slew_rates = { + 64000, + 32000, + 16000, + 8000, + 4000, + 2000, + 1000, + 500, + }, + .switch_freq = { 600000, 850000, 1100000, 1600000 }, + .fs_reg = MP886X_SYSCNTLREG1, + .fs_shift = 1, +}; + static const struct mp886x_cfg_info mp8867_ci = { .rops = &mp8867_regulator_ops, .slew_rates = { @@ -341,6 +358,7 @@ static int mp886x_i2c_probe(struct i2c_client *client) } static const struct of_device_id mp886x_dt_ids[] = { + { .compatible = "mps,mp8864", .data = &mp8864_ci }, { .compatible = "mps,mp8867", .data = &mp8867_ci }, { .compatible = "mps,mp8869", .data = &mp8869_ci }, { } @@ -348,6 +366,7 @@ static const struct of_device_id mp886x_dt_ids[] = { MODULE_DEVICE_TABLE(of, mp886x_dt_ids); static const struct i2c_device_id mp886x_id[] = { + { .name = "mp8864", .driver_data = (kernel_ulong_t)&mp8864_ci }, { .name = "mp8867", .driver_data = (kernel_ulong_t)&mp8867_ci }, { .name = "mp8869", .driver_data = (kernel_ulong_t)&mp8869_ci }, { } -- cgit v1.2.3 From f0944054a0e0ad8cc23003a98e3fede5b1c1354b Mon Sep 17 00:00:00 2001 From: Luca Weiss Date: Tue, 1 Sep 2026 10:58:56 +0200 Subject: regulator: dt-bindings: qcom,rpmh: Add supply names for PM6350 The supply names for the PM6350 regulators were skipped during initial bringup. Document them now. Signed-off-by: Luca Weiss Link: https://patch.msgid.link/20260901-fp4-regulator-supply-v1-1-68288ab70aee@fairphone.com Signed-off-by: Mark Brown --- .../bindings/regulator/qcom,rpmh-regulator.yaml | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/Documentation/devicetree/bindings/regulator/qcom,rpmh-regulator.yaml b/Documentation/devicetree/bindings/regulator/qcom,rpmh-regulator.yaml index eed2ce7fa861..9115885e7985 100644 --- a/Documentation/devicetree/bindings/regulator/qcom,rpmh-regulator.yaml +++ b/Documentation/devicetree/bindings/regulator/qcom,rpmh-regulator.yaml @@ -187,6 +187,22 @@ allOf: patternProperties: "^vdd-s[1-8]-supply$": true + - if: + properties: + compatible: + enum: + - qcom,pm6350-rpmh-regulators + then: + properties: + vdd-l2-l5-l7-supply: true + vdd-l3-l6-l8-l9-l10-supply: true + vdd-l12-l14-supply: true + vdd-l15-l19-l22-supply: true + vdd-l18-l20-l21-supply: true + patternProperties: + "^vdd-l([14]|1[1367])-supply$": true + "^vdd-s[1-6]-supply$": true + - if: properties: compatible: -- cgit v1.2.3 From 05e0f510e299ce8836f8776bccd8d3197e9c57fd Mon Sep 17 00:00:00 2001 From: Luca Weiss Date: Tue, 1 Sep 2026 10:58:57 +0200 Subject: regulator: qcom-rpmh: Add supply names for PM6350 The supply names for the PM6350 regulators were skipped during initial bringup. Add them. Signed-off-by: Luca Weiss Reviewed-by: Abel Vesa Link: https://patch.msgid.link/20260901-fp4-regulator-supply-v1-2-68288ab70aee@fairphone.com Signed-off-by: Mark Brown --- drivers/regulator/qcom-rpmh-regulator.c | 46 ++++++++++++++++----------------- 1 file changed, 23 insertions(+), 23 deletions(-) diff --git a/drivers/regulator/qcom-rpmh-regulator.c b/drivers/regulator/qcom-rpmh-regulator.c index 25c14de3cd8b..dd2265961151 100644 --- a/drivers/regulator/qcom-rpmh-regulator.c +++ b/drivers/regulator/qcom-rpmh-regulator.c @@ -1589,31 +1589,31 @@ static const struct rpmh_vreg_init_data pm6150l_vreg_data[] = { }; static const struct rpmh_vreg_init_data pm6350_vreg_data[] = { - RPMH_VREG("smps1", SMPS, 1, &pmic5_ftsmps510, NULL), - RPMH_VREG("smps2", SMPS, 2, &pmic5_hfsmps510, NULL), + RPMH_VREG("smps1", SMPS, 1, &pmic5_ftsmps510, "vdd-s1"), + RPMH_VREG("smps2", SMPS, 2, &pmic5_hfsmps510, "vdd-s2"), /* smps3 - smps5 not configured */ - RPMH_VREG("ldo1", LDO, 1, &pmic5_nldo, NULL), - RPMH_VREG("ldo2", LDO, 2, &pmic5_pldo, NULL), - RPMH_VREG("ldo3", LDO, 3, &pmic5_pldo, NULL), - RPMH_VREG("ldo4", LDO, 4, &pmic5_nldo, NULL), - RPMH_VREG("ldo5", LDO, 5, &pmic5_pldo, NULL), - RPMH_VREG("ldo6", LDO, 6, &pmic5_pldo, NULL), - RPMH_VREG("ldo7", LDO, 7, &pmic5_pldo, NULL), - RPMH_VREG("ldo8", LDO, 8, &pmic5_pldo, NULL), - RPMH_VREG("ldo9", LDO, 9, &pmic5_pldo, NULL), - RPMH_VREG("ldo10", LDO, 10, &pmic5_pldo, NULL), - RPMH_VREG("ldo11", LDO, 11, &pmic5_pldo, NULL), - RPMH_VREG("ldo12", LDO, 12, &pmic5_pldo, NULL), - RPMH_VREG("ldo13", LDO, 13, &pmic5_nldo, NULL), - RPMH_VREG("ldo14", LDO, 14, &pmic5_pldo, NULL), - RPMH_VREG("ldo15", LDO, 15, &pmic5_nldo, NULL), - RPMH_VREG("ldo16", LDO, 16, &pmic5_nldo, NULL), + RPMH_VREG("ldo1", LDO, 1, &pmic5_nldo, "vdd-l1"), + RPMH_VREG("ldo2", LDO, 2, &pmic5_pldo, "vdd-l2-l5-l7"), + RPMH_VREG("ldo3", LDO, 3, &pmic5_pldo, "vdd-l3-l6-l8-l9-l10"), + RPMH_VREG("ldo4", LDO, 4, &pmic5_nldo, "vdd-l4"), + RPMH_VREG("ldo5", LDO, 5, &pmic5_pldo, "vdd-l2-l5-l7"), + RPMH_VREG("ldo6", LDO, 6, &pmic5_pldo, "vdd-l3-l6-l8-l9-l10"), + RPMH_VREG("ldo7", LDO, 7, &pmic5_pldo, "vdd-l2-l5-l7"), + RPMH_VREG("ldo8", LDO, 8, &pmic5_pldo, "vdd-l3-l6-l8-l9-l10"), + RPMH_VREG("ldo9", LDO, 9, &pmic5_pldo, "vdd-l3-l6-l8-l9-l10"), + RPMH_VREG("ldo10", LDO, 10, &pmic5_pldo, "vdd-l3-l6-l8-l9-l10"), + RPMH_VREG("ldo11", LDO, 11, &pmic5_pldo, "vdd-l11"), + RPMH_VREG("ldo12", LDO, 12, &pmic5_pldo, "vdd-l12-l14"), + RPMH_VREG("ldo13", LDO, 13, &pmic5_nldo, "vdd-l13"), + RPMH_VREG("ldo14", LDO, 14, &pmic5_pldo, "vdd-l12-l14"), + RPMH_VREG("ldo15", LDO, 15, &pmic5_nldo, "vdd-l15-l19-l22"), + RPMH_VREG("ldo16", LDO, 16, &pmic5_nldo, "vdd-l16"), /* ldo17 not configured */ - RPMH_VREG("ldo18", LDO, 18, &pmic5_nldo, NULL), - RPMH_VREG("ldo19", LDO, 19, &pmic5_nldo, NULL), - RPMH_VREG("ldo20", LDO, 20, &pmic5_nldo, NULL), - RPMH_VREG("ldo21", LDO, 21, &pmic5_nldo, NULL), - RPMH_VREG("ldo22", LDO, 22, &pmic5_nldo, NULL), + RPMH_VREG("ldo18", LDO, 18, &pmic5_nldo, "vdd-l18-l20-l21"), + RPMH_VREG("ldo19", LDO, 19, &pmic5_nldo, "vdd-l15-l19-l22"), + RPMH_VREG("ldo20", LDO, 20, &pmic5_nldo, "vdd-l18-l20-l21"), + RPMH_VREG("ldo21", LDO, 21, &pmic5_nldo, "vdd-l18-l20-l21"), + RPMH_VREG("ldo22", LDO, 22, &pmic5_nldo, "vdd-l15-l19-l22"), }; static const struct rpmh_vreg_init_data pmcx0102_vreg_data[] = { -- cgit v1.2.3 From fd744eb396a332d1f26280b15ac9de55f4b283d4 Mon Sep 17 00:00:00 2001 From: Luca Weiss Date: Tue, 1 Sep 2026 10:58:58 +0200 Subject: regulator: qcom-rpmh: Add missing regulators in PM6350 Add the missing smps3-6 and ldo17 definitions. While smps3/5 and ldo17 are not used from the rpmh regulator driver on SM6350, the regulators do exist, so add them with the types based on the datasheet. Signed-off-by: Luca Weiss Reviewed-by: Konrad Dybcio Reviewed-by: Abel Vesa Link: https://patch.msgid.link/20260901-fp4-regulator-supply-v1-3-68288ab70aee@fairphone.com Signed-off-by: Mark Brown --- drivers/regulator/qcom-rpmh-regulator.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/drivers/regulator/qcom-rpmh-regulator.c b/drivers/regulator/qcom-rpmh-regulator.c index dd2265961151..7d20f3e47760 100644 --- a/drivers/regulator/qcom-rpmh-regulator.c +++ b/drivers/regulator/qcom-rpmh-regulator.c @@ -1591,7 +1591,10 @@ static const struct rpmh_vreg_init_data pm6150l_vreg_data[] = { static const struct rpmh_vreg_init_data pm6350_vreg_data[] = { RPMH_VREG("smps1", SMPS, 1, &pmic5_ftsmps510, "vdd-s1"), RPMH_VREG("smps2", SMPS, 2, &pmic5_hfsmps510, "vdd-s2"), - /* smps3 - smps5 not configured */ + RPMH_VREG("smps3", SMPS, 3, &pmic5_ftsmps510, "vdd-s3"), + RPMH_VREG("smps4", SMPS, 4, &pmic5_ftsmps510, "vdd-s4"), + RPMH_VREG("smps5", SMPS, 5, &pmic5_ftsmps510, "vdd-s5"), + RPMH_VREG("smps6", SMPS, 6, &pmic5_hfsmps510, "vdd-s6"), RPMH_VREG("ldo1", LDO, 1, &pmic5_nldo, "vdd-l1"), RPMH_VREG("ldo2", LDO, 2, &pmic5_pldo, "vdd-l2-l5-l7"), RPMH_VREG("ldo3", LDO, 3, &pmic5_pldo, "vdd-l3-l6-l8-l9-l10"), @@ -1608,7 +1611,7 @@ static const struct rpmh_vreg_init_data pm6350_vreg_data[] = { RPMH_VREG("ldo14", LDO, 14, &pmic5_pldo, "vdd-l12-l14"), RPMH_VREG("ldo15", LDO, 15, &pmic5_nldo, "vdd-l15-l19-l22"), RPMH_VREG("ldo16", LDO, 16, &pmic5_nldo, "vdd-l16"), - /* ldo17 not configured */ + RPMH_VREG("ldo17", LDO, 17, &pmic5_nldo, "vdd-l17"), RPMH_VREG("ldo18", LDO, 18, &pmic5_nldo, "vdd-l18-l20-l21"), RPMH_VREG("ldo19", LDO, 19, &pmic5_nldo, "vdd-l15-l19-l22"), RPMH_VREG("ldo20", LDO, 20, &pmic5_nldo, "vdd-l18-l20-l21"), -- cgit v1.2.3 From f267ad84f59c9170629babb2ca928a26a9adcb0a Mon Sep 17 00:00:00 2001 From: Hemanth Selam Date: Fri, 4 Sep 2026 16:32:00 +0530 Subject: regulator: fix typos in comments Fix typos in comments, reported by scripts/checkpatch.pl using the misspelling list in scripts/spelling.txt. Only touches comments, no code changes. Assisted-by: Cursor:claude-opus-5 Signed-off-by: Hemanth Selam Link: https://patch.msgid.link/20260904110203.10113-2-hemanth.selam@gmail.com Signed-off-by: Mark Brown --- drivers/regulator/ab8500-ext.c | 2 +- drivers/regulator/core.c | 2 +- drivers/regulator/pv88080-regulator.c | 4 ++-- include/linux/regulator/driver.h | 2 +- 4 files changed, 5 insertions(+), 5 deletions(-) diff --git a/drivers/regulator/ab8500-ext.c b/drivers/regulator/ab8500-ext.c index b9955aa4e0d1..c0657362a102 100644 --- a/drivers/regulator/ab8500-ext.c +++ b/drivers/regulator/ab8500-ext.c @@ -88,7 +88,7 @@ static struct regulator_init_data ab8500_ext_regulators[] = { * @update_reg: register to control on/off * @update_mask: mask to enable/disable and set mode of regulator * @update_val: bits holding the regulator current mode - * @update_val_hp: bits to set EN pin active (LPn pin deactive) + * @update_val_hp: bits to set EN pin active (LPn pin deactivate) * normally this means high power mode * @update_val_lp: bits to set EN pin active and LPn pin active * normally this means low power mode diff --git a/drivers/regulator/core.c b/drivers/regulator/core.c index 6a4008f387b5..1e950260f441 100644 --- a/drivers/regulator/core.c +++ b/drivers/regulator/core.c @@ -3029,7 +3029,7 @@ static int _regulator_do_enable(struct regulator_dev *rdev) */ trace_regulator_enable_delay(rdev_get_name(rdev)); - /* If poll_enabled_time is set, poll upto the delay calculated + /* If poll_enabled_time is set, poll up to the delay calculated * above, delaying poll_enabled_time uS to check if the regulator * actually got enabled. * If the regulator isn't enabled after our delay helper has expired, diff --git a/drivers/regulator/pv88080-regulator.c b/drivers/regulator/pv88080-regulator.c index b96afbf11ff3..1f2c405fd2bd 100644 --- a/drivers/regulator/pv88080-regulator.c +++ b/drivers/regulator/pv88080-regulator.c @@ -432,7 +432,7 @@ static int pv88080_i2c_probe(struct i2c_client *i2c) config.dev = chip->dev; config.regmap = chip->regmap; - /* Registeration for BUCK1, 2, 3 */ + /* Registration for BUCK1, 2, 3 */ for (i = 0; i < PV88080_MAX_REGULATORS-1; i++) { if (init_data) config.init_data = &init_data[i]; @@ -498,7 +498,7 @@ static int pv88080_i2c_probe(struct i2c_client *i2c) pv88080_regulator_info[PV88080_ID_HVBUCK].desc.vsel_mask = regmap_config->hvbuck_vsel_mask; - /* Registeration for HVBUCK */ + /* Registration for HVBUCK */ if (init_data) config.init_data = &init_data[PV88080_ID_HVBUCK]; diff --git a/include/linux/regulator/driver.h b/include/linux/regulator/driver.h index cc6ce709ec86..55cc519103ed 100644 --- a/include/linux/regulator/driver.h +++ b/include/linux/regulator/driver.h @@ -362,7 +362,7 @@ enum regulator_type { * @off_on_delay: guard time (in uS), before re-enabling a regulator * * @poll_enabled_time: The polling interval (in uS) to use while checking that - * the regulator was actually enabled. Max upto enable_time. + * the regulator was actually enabled. Max up to enable_time. * * @of_map_mode: Maps a hardware mode defined in a DeviceTree to a standard mode */ -- cgit v1.2.3 From 63ab1abd01a14a564ac23c7032ea81944f6af642 Mon Sep 17 00:00:00 2001 From: Hemanth Selam Date: Fri, 4 Sep 2026 16:32:01 +0530 Subject: regulator: fix repeated word in log message Drop the word written twice, reported by checkpatch.pl as a possible repeated word. Only the message text changes, no code changes. Assisted-by: Cursor:claude-opus-5 Signed-off-by: Hemanth Selam Link: https://patch.msgid.link/20260904110203.10113-3-hemanth.selam@gmail.com Signed-off-by: Mark Brown --- drivers/regulator/tps6105x-regulator.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/regulator/tps6105x-regulator.c b/drivers/regulator/tps6105x-regulator.c index a09c6ae6a0ce..7f99f3e90bec 100644 --- a/drivers/regulator/tps6105x-regulator.c +++ b/drivers/regulator/tps6105x-regulator.c @@ -65,7 +65,7 @@ static int tps6105x_regulator_probe(struct platform_device *pdev) /* This instance is not set for regulator mode so bail out */ if (pdata->mode != TPS6105X_MODE_VOLTAGE) { dev_info(&pdev->dev, - "chip not in voltage mode mode, exit probe\n"); + "chip not in voltage mode, exit probe\n"); return 0; } -- cgit v1.2.3 From e3c05a881fc9f0d47e373998bef5b4cb7426c565 Mon Sep 17 00:00:00 2001 From: Tapio Reijonen Date: Thu, 10 Sep 2026 08:51:41 +0000 Subject: regulator: dt-bindings: Add MPS MPQ4210 The MPQ4210 is a 40V synchronous four-switch buck-boost controller with an I2C interface. Its output voltage is programmed through an 11-bit feedback reference DAC covering 0 to 2.047V in 1mV steps, and is then scaled by an external feedback resistor divider, so the divider ratio has to be described in the device tree for the driver to translate reference voltages into output voltages. The divider is given in ohms rather than the kilo ohms used by mps,mp886x.yaml because the bottom resistor is not necessarily a whole number of kilo ohms. The same divider scales the reference ramp rate, so unlike the other bindings that scale by a feedback divider there is no portable value a board can copy into regulator-ramp-delay. Describe how the selectable rates are derived from the four reference slew rates, and show the calculation in the example. Signed-off-by: Tapio Reijonen Link: https://patch.msgid.link/20260910-mpq4210-regulator-v1-1-d37e208dfc8d@vaisala.com Signed-off-by: Mark Brown --- .../devicetree/bindings/regulator/mps,mpq4210.yaml | 69 ++++++++++++++++++++++ MAINTAINERS | 5 ++ 2 files changed, 74 insertions(+) create mode 100644 Documentation/devicetree/bindings/regulator/mps,mpq4210.yaml diff --git a/Documentation/devicetree/bindings/regulator/mps,mpq4210.yaml b/Documentation/devicetree/bindings/regulator/mps,mpq4210.yaml new file mode 100644 index 000000000000..e9e7a87e7533 --- /dev/null +++ b/Documentation/devicetree/bindings/regulator/mps,mpq4210.yaml @@ -0,0 +1,69 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/regulator/mps,mpq4210.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Monolithic Power Systems MPQ4210 buck-boost regulator + +maintainers: + - Tapio Reijonen + +description: + The MPQ4210 is a synchronous four-switch buck-boost controller with an I2C + interface. The output voltage is programmed through an 11-bit feedback + reference DAC and scaled by an external feedback resistor divider. + + The controller ramps the feedback reference at 38, 50, 75 or 150 mV/ms. + The divider scales the ramp rate along with the voltage, so the output + ramp rates that regulator-ramp-delay can select are those values + multiplied by (R1 + R2) / R2. + +allOf: + - $ref: regulator.yaml# + +properties: + compatible: + const: mps,mpq4210 + + reg: + maxItems: 1 + + enable-gpios: + description: GPIO connected to the EN pin. If absent, EN is assumed to + be permanently asserted. + maxItems: 1 + + mps,fb-voltage-divider: + description: An array of two integers containing the resistor values R1 + and R2 of the output feedback voltage divider in ohms. + $ref: /schemas/types.yaml#/definitions/uint32-array + maxItems: 2 + +required: + - compatible + - reg + - mps,fb-voltage-divider + +unevaluatedProperties: false + +examples: + - | + #include + i2c { + #address-cells = <1>; + #size-cells = <0>; + + regulator@64 { + compatible = "mps,mpq4210"; + reg = <0x64>; + regulator-name = "vout"; + regulator-min-microvolt = <4000000>; + regulator-max-microvolt = <20000000>; + enable-gpios = <&gpio0 2 GPIO_ACTIVE_LOW>; + /* R1 = 82 kOhm, R2 = 9.1 kOhm */ + mps,fb-voltage-divider = <82000 9100>; + /* 50 mV/ms reference ramp x (82000 + 9100) / 9100 */ + regulator-ramp-delay = <500>; + }; + }; diff --git a/MAINTAINERS b/MAINTAINERS index 3a19da74d00c..eb552bff791b 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -18372,6 +18372,11 @@ F: scripts/module* F: tools/testing/selftests/kmod/ F: tools/testing/selftests/module/ +MONOLITHIC POWER SYSTEM MPQ4210 REGULATOR DRIVER +M: Tapio Reijonen +S: Maintained +F: Documentation/devicetree/bindings/regulator/mps,mpq4210.yaml + MONOLITHIC POWER SYSTEM PMIC DRIVER M: Saravanan Sekar S: Maintained -- cgit v1.2.3 From 61879d561e91c71502fef9f28f26b31e9a5b9fa2 Mon Sep 17 00:00:00 2001 From: Tapio Reijonen Date: Thu, 10 Sep 2026 08:51:42 +0000 Subject: regulator: Add MPS MPQ4210 buck-boost regulator driver The MPQ4210 is a 40V synchronous four-switch buck-boost controller with an I2C interface. Add a driver exposing voltage control and enable control through the regulator interface. The output voltage is programmed by an 11-bit feedback reference DAC with a 1mV step, split across REF_LSB[2:0] and REF_MSB[7:0], and is then scaled by the external feedback divider described in the device tree. Only 0.3V to 2.047V of that range is specified, so linear_min_sel holds the driver to it and the lower selectors are not offered. Scaled by the divider, that floor is not zero: 4.2V on a board with a gain of 14, and the core narrows regulator-min-microvolt to it. The same divider ratio applies to the slew rate, so the four reference slew rates that the Control 1 SR field selects are scaled into a per-device ramp_delay_table and the field is exposed through regulator_set_ramp_delay_regmap(). ramp_delay is initialised from the rate SR is currently programmed for, so the core waits in proportion to the size of each change; a board that sets regulator-ramp-delay reprograms SR and the core uses that value instead. Enabling follows the start-up sequence in the datasheet: commit the reference with the GO bit, wait 200ms, then set ENPWR. Control 1 bit 2 is documented as reserved but has to be set before the controller starts up, so probe sets it. The controller does not respond on the bus while EN is deasserted, so the enable GPIO is claimed before the first register access. Link: https://www.monolithicpower.com/en/mpq4210.html Signed-off-by: Tapio Reijonen Link: https://patch.msgid.link/20260910-mpq4210-regulator-v1-2-d37e208dfc8d@vaisala.com Signed-off-by: Mark Brown --- MAINTAINERS | 1 + drivers/regulator/Kconfig | 11 ++ drivers/regulator/Makefile | 1 + drivers/regulator/mpq4210.c | 243 ++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 256 insertions(+) create mode 100644 drivers/regulator/mpq4210.c diff --git a/MAINTAINERS b/MAINTAINERS index eb552bff791b..78d28c103eb1 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -18376,6 +18376,7 @@ MONOLITHIC POWER SYSTEM MPQ4210 REGULATOR DRIVER M: Tapio Reijonen S: Maintained F: Documentation/devicetree/bindings/regulator/mps,mpq4210.yaml +F: drivers/regulator/mpq4210.c MONOLITHIC POWER SYSTEM PMIC DRIVER M: Saravanan Sekar diff --git a/drivers/regulator/Kconfig b/drivers/regulator/Kconfig index 89789ac7a786..df7742533f22 100644 --- a/drivers/regulator/Kconfig +++ b/drivers/regulator/Kconfig @@ -870,6 +870,17 @@ config REGULATOR_MP886X help This driver supports the MP8869 voltage regulator. +config REGULATOR_MPQ4210 + tristate "MPS MPQ4210 regulator driver" + depends on I2C && OF + select REGMAP_I2C + help + This driver supports the MPQ4210 synchronous buck-boost controller. + It supports get/set voltage, enable/disable and ramp rate selection + through the regulator interface. + Say M here if you want to include support for the regulator as a + module. The module will be named "mpq4210". + config REGULATOR_MPQ7920 tristate "Monolithic MPQ7920 PMIC" depends on I2C && OF diff --git a/drivers/regulator/Makefile b/drivers/regulator/Makefile index 5a764cec8df8..af69a0ee877d 100644 --- a/drivers/regulator/Makefile +++ b/drivers/regulator/Makefile @@ -104,6 +104,7 @@ obj-$(CONFIG_REGULATOR_MCP16502) += mcp16502.o obj-$(CONFIG_REGULATOR_MP5416) += mp5416.o obj-$(CONFIG_REGULATOR_MP8859) += mp8859.o obj-$(CONFIG_REGULATOR_MP886X) += mp886x.o +obj-$(CONFIG_REGULATOR_MPQ4210) += mpq4210.o obj-$(CONFIG_REGULATOR_MPQ7920) += mpq7920.o obj-$(CONFIG_REGULATOR_MT6311) += mt6311-regulator.o obj-$(CONFIG_REGULATOR_MT6315) += mt6315-regulator.o diff --git a/drivers/regulator/mpq4210.c b/drivers/regulator/mpq4210.c new file mode 100644 index 000000000000..227136d82258 --- /dev/null +++ b/drivers/regulator/mpq4210.c @@ -0,0 +1,243 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Monolithic Power Systems MPQ4210 buck-boost regulator + * + * Copyright (c) 2026 Vaisala Oyj + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define MPQ4210_REF_LSB 0x00 +#define MPQ4210_REF_LSB_MASK GENMASK(2, 0) +#define MPQ4210_REF_LSB_BITS 3 +#define MPQ4210_REF_MSB 0x01 +#define MPQ4210_CONTROL1 0x02 +#define MPQ4210_CONTROL1_SR GENMASK(7, 6) +#define MPQ4210_CONTROL1_RESERVED BIT(2) +#define MPQ4210_CONTROL1_GO BIT(1) +#define MPQ4210_CONTROL1_ENPWR BIT(0) +#define MPQ4210_INT_MASK 0x06 + +/* + * The feedback reference is an 11 bit value with a 1mV step. The datasheet + * specifies no reference below 0.3V, so those selectors are not offered. + */ +#define MPQ4210_REF_MIN 0x12c +#define MPQ4210_REF_MAX 0x7ff +#define MPQ4210_REF_STEP_UV 1000 + +#define MPQ4210_ENPWR_DELAY_MS 200 + +/* Feedback reference slew rate per MPQ4210_CONTROL1_SR value, in uV/us. */ +static const unsigned int mpq4210_ref_slew_rate[] = { 38, 50, 75, 150 }; + +static const struct regmap_config mpq4210_regmap_config = { + .reg_bits = 8, + .val_bits = 8, + .max_register = MPQ4210_INT_MASK, +}; + +/* Scale a feedback reference value by the output voltage divider ratio. */ +static unsigned int mpq4210_scale(unsigned int val, u32 r1, u32 r2) +{ + u64 tmp = (u64)val * (r1 + r2); + + do_div(tmp, r2); + + return tmp; +} + +static int mpq4210_set_voltage_sel(struct regulator_dev *rdev, unsigned int sel) +{ + int ret; + + ret = regmap_write(rdev->regmap, MPQ4210_REF_LSB, + sel & MPQ4210_REF_LSB_MASK); + if (ret) + return ret; + + ret = regmap_write(rdev->regmap, MPQ4210_REF_MSB, + sel >> MPQ4210_REF_LSB_BITS); + if (ret) + return ret; + + return regmap_set_bits(rdev->regmap, MPQ4210_CONTROL1, + MPQ4210_CONTROL1_GO); +} + +static int mpq4210_get_voltage_sel(struct regulator_dev *rdev) +{ + unsigned int lsb, msb; + int ret; + + ret = regmap_read(rdev->regmap, MPQ4210_REF_MSB, &msb); + if (ret) + return ret; + + ret = regmap_read(rdev->regmap, MPQ4210_REF_LSB, &lsb); + if (ret) + return ret; + + return (msb << MPQ4210_REF_LSB_BITS) | (lsb & MPQ4210_REF_LSB_MASK); +} + +static int mpq4210_enable(struct regulator_dev *rdev) +{ + int ret; + + ret = regmap_set_bits(rdev->regmap, MPQ4210_CONTROL1, + MPQ4210_CONTROL1_GO); + if (ret) + return ret; + + /* The reference has to settle before power switching may start. */ + msleep(MPQ4210_ENPWR_DELAY_MS); + + return regmap_set_bits(rdev->regmap, MPQ4210_CONTROL1, + MPQ4210_CONTROL1_ENPWR); +} + +static const struct regulator_ops mpq4210_regulator_ops = { + .set_voltage_sel = mpq4210_set_voltage_sel, + .get_voltage_sel = mpq4210_get_voltage_sel, + .list_voltage = regulator_list_voltage_linear, + .set_ramp_delay = regulator_set_ramp_delay_regmap, + .enable = mpq4210_enable, + .disable = regulator_disable_regmap, + .is_enabled = regulator_is_enabled_regmap, +}; + +static const struct regulator_desc mpq4210_regulator = { + .name = "mpq4210", + .type = REGULATOR_VOLTAGE, + .owner = THIS_MODULE, + .ops = &mpq4210_regulator_ops, + .n_voltages = MPQ4210_REF_MAX + 1, + .linear_min_sel = MPQ4210_REF_MIN, + .enable_reg = MPQ4210_CONTROL1, + .enable_mask = MPQ4210_CONTROL1_ENPWR, + .ramp_reg = MPQ4210_CONTROL1, + .ramp_mask = MPQ4210_CONTROL1_SR, + .n_ramp_values = ARRAY_SIZE(mpq4210_ref_slew_rate), +}; + +static int mpq4210_i2c_probe(struct i2c_client *client) +{ + struct device *dev = &client->dev; + struct regulator_config config = { }; + struct regulator_desc *desc; + struct regulator_dev *rdev; + struct gpio_desc *enable; + struct regmap *regmap; + unsigned int *slew; + unsigned int i, val; + u32 r[2]; + int ret; + + ret = of_property_read_u32_array(dev->of_node, "mps,fb-voltage-divider", + r, ARRAY_SIZE(r)); + if (ret) + return dev_err_probe(dev, ret, + "failed to read mps,fb-voltage-divider\n"); + + if (!r[1]) + return dev_err_probe(dev, -EINVAL, + "feedback divider R2 must not be zero\n"); + + /* The controller does not answer on the bus while EN is deasserted. */ + enable = devm_gpiod_get_optional(dev, "enable", GPIOD_OUT_HIGH); + if (IS_ERR(enable)) + return dev_err_probe(dev, PTR_ERR(enable), + "failed to get enable GPIO\n"); + + regmap = devm_regmap_init_i2c(client, &mpq4210_regmap_config); + if (IS_ERR(regmap)) + return dev_err_probe(dev, PTR_ERR(regmap), + "failed to init regmap\n"); + + desc = devm_kmemdup(dev, &mpq4210_regulator, sizeof(*desc), GFP_KERNEL); + if (!desc) + return -ENOMEM; + + desc->min_uV = mpq4210_scale(MPQ4210_REF_MIN * MPQ4210_REF_STEP_UV, + r[0], r[1]); + desc->uV_step = mpq4210_scale(MPQ4210_REF_STEP_UV, r[0], r[1]); + + slew = devm_kcalloc(dev, ARRAY_SIZE(mpq4210_ref_slew_rate), + sizeof(*slew), GFP_KERNEL); + if (!slew) + return -ENOMEM; + + for (i = 0; i < ARRAY_SIZE(mpq4210_ref_slew_rate); i++) + slew[i] = mpq4210_scale(mpq4210_ref_slew_rate[i], r[0], r[1]); + + desc->ramp_delay_table = slew; + + ret = regmap_read(regmap, MPQ4210_CONTROL1, &val); + if (ret) + return dev_err_probe(dev, ret, "failed to read control 1\n"); + + /* The core overrides this if the board sets regulator-ramp-delay. */ + desc->ramp_delay = slew[FIELD_GET(MPQ4210_CONTROL1_SR, val)]; + + /* + * Documented as reserved, but the datasheet requires it to be set + * before the controller starts up. + */ + ret = regmap_set_bits(regmap, MPQ4210_CONTROL1, + MPQ4210_CONTROL1_RESERVED); + if (ret) + return dev_err_probe(dev, ret, "failed to write control 1\n"); + + config.dev = dev; + config.regmap = regmap; + config.of_node = dev->of_node; + config.init_data = of_get_regulator_init_data(dev, dev->of_node, desc); + if (!config.init_data) + return -ENOMEM; + + rdev = devm_regulator_register(dev, desc, &config); + if (IS_ERR(rdev)) + return dev_err_probe(dev, PTR_ERR(rdev), + "failed to register regulator\n"); + + return 0; +} + +static const struct of_device_id mpq4210_of_match[] = { + { .compatible = "mps,mpq4210" }, + { } +}; +MODULE_DEVICE_TABLE(of, mpq4210_of_match); + +static const struct i2c_device_id mpq4210_i2c_id[] = { + { .name = "mpq4210" }, + { } +}; +MODULE_DEVICE_TABLE(i2c, mpq4210_i2c_id); + +static struct i2c_driver mpq4210_regulator_driver = { + .driver = { + .name = "mpq4210", + .probe_type = PROBE_PREFER_ASYNCHRONOUS, + .of_match_table = mpq4210_of_match, + }, + .probe = mpq4210_i2c_probe, + .id_table = mpq4210_i2c_id, +}; + +module_i2c_driver(mpq4210_regulator_driver); + +MODULE_DESCRIPTION("Monolithic Power Systems MPQ4210 voltage regulator driver"); +MODULE_AUTHOR("Tapio Reijonen "); +MODULE_LICENSE("GPL"); -- cgit v1.2.3 From dfdfda2a95843706428a9d95ab546cb10983e684 Mon Sep 17 00:00:00 2001 From: Linus Walleij Date: Tue, 1 Sep 2026 22:02:06 +0200 Subject: regulator: ab8500: Fix AB8505 VANA voltage selectors The AB8505 VANA voltage table assumes selector 0 represents 1.05 V and all eight selectors increase linearly. Selector 0 actually represents 1.2 V. Selectors 1 through 6 cover 1.05 V through 1.175 V, and selector 7 represents 1.225 V. Correct the table so each selector reports and programs the documented voltage. Reference: AB8505 User Manual, DM00046744 Rev 3, p. 257 Fixes: 8a3b1b8703fe ("regulator: ab8500: Add voltage selection for AUDIO and ANA on AB8505") Assisted-by: LLM Signed-off-by: Linus Walleij Link: https://patch.msgid.link/20260901-ux500-dts-snowball-regulator-v2-1-fe88b01829bf@kernel.org Signed-off-by: Mark Brown --- drivers/regulator/ab8500.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/regulator/ab8500.c b/drivers/regulator/ab8500.c index 3705c98b0713..ca59406d42a8 100644 --- a/drivers/regulator/ab8500.c +++ b/drivers/regulator/ab8500.c @@ -264,13 +264,13 @@ static const unsigned int fixed_2050000_voltage[] = { }; static const unsigned int ldo_vana_voltages[] = { + 1200000, 1050000, 1075000, 1100000, 1125000, 1150000, 1175000, - 1200000, 1225000, }; -- cgit v1.2.3 From ac72c091a9810493ccd9209414d4f859276727ab Mon Sep 17 00:00:00 2001 From: Linus Walleij Date: Tue, 1 Sep 2026 22:02:07 +0200 Subject: regulator: ab8500: Add AB8505 VAUX3 3.05 V setting AB8505 has an additional VAUX3 voltage setting which is not encoded in the normal three-bit selector. ArmRegu2.Vaux3Sel3 overrides that selector and selects 3.05 V. Add the missing voltage and use the override bit as an extended selector. Program the ordinary selector before clearing the override so VAUX3 does not briefly switch to a stale voltage. Reference: AB8505 User Manual, DM00046744 Rev 3, pp. 229 and 254 Fixes: 547f384f33db ("regulator: ab8500: add support for ab8505") Assisted-by: LLM Signed-off-by: Linus Walleij Link: https://patch.msgid.link/20260901-ux500-dts-snowball-regulator-v2-2-fe88b01829bf@kernel.org Signed-off-by: Mark Brown --- drivers/regulator/ab8500.c | 101 +++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 98 insertions(+), 3 deletions(-) diff --git a/drivers/regulator/ab8500.c b/drivers/regulator/ab8500.c index ca59406d42a8..07d96f8ff944 100644 --- a/drivers/regulator/ab8500.c +++ b/drivers/regulator/ab8500.c @@ -173,6 +173,7 @@ struct ab8500_shared_mode { * @voltage_bank: bank to control regulator voltage * @voltage_reg: register to control regulator voltage * @voltage_mask: mask to control regulator voltage + * @expand_register: additional register used to select an extra voltage */ struct ab8500_regulator_info { struct device *dev; @@ -193,6 +194,12 @@ struct ab8500_regulator_info { u8 voltage_bank; u8 voltage_reg; u8 voltage_mask; + struct { + u8 voltage_limit; + u8 voltage_bank; + u8 voltage_reg; + u8 voltage_mask; + } expand_register; }; /* voltage tables for the vauxn/vintcore supplies */ @@ -226,6 +233,18 @@ static const unsigned int ldo_vaux3_voltages[] = { 2910000, }; +static const unsigned int ldo_vaux3_ab8505_voltages[] = { + 1200000, + 1500000, + 1800000, + 2100000, + 2500000, + 2750000, + 2790000, + 2910000, + 3050000, +}; + static const unsigned int ldo_vaux56_voltages[] = { 1800000, 1050000, @@ -593,6 +612,64 @@ static int ab8500_regulator_set_voltage_sel(struct regulator_dev *rdev, return ret; } +static int ab8500_regulator_get_voltage_sel_expand(struct regulator_dev *rdev) +{ + struct ab8500_regulator_info *info = rdev_get_drvdata(rdev); + u8 regval; + int ret; + + if (!info) + return -EINVAL; + + ret = abx500_get_register_interruptible(info->dev, + info->expand_register.voltage_bank, + info->expand_register.voltage_reg, ®val); + if (ret < 0) { + dev_err(rdev_get_dev(rdev), + "couldn't read voltage expand reg for regulator\n"); + return ret; + } + + if (regval & info->expand_register.voltage_mask) + return info->expand_register.voltage_limit; + + return ab8500_regulator_get_voltage_sel(rdev); +} + +static int ab8500_regulator_set_voltage_sel_expand(struct regulator_dev *rdev, + unsigned int selector) +{ + struct ab8500_regulator_info *info = rdev_get_drvdata(rdev); + u8 regval; + int ret; + + if (!info) + return -EINVAL; + + if (selector > info->expand_register.voltage_limit) + return -EINVAL; + + if (selector < info->expand_register.voltage_limit) { + ret = ab8500_regulator_set_voltage_sel(rdev, selector); + if (ret < 0) + return ret; + + regval = 0; + } else { + regval = info->expand_register.voltage_mask; + } + + ret = abx500_mask_and_set_register_interruptible(info->dev, + info->expand_register.voltage_bank, + info->expand_register.voltage_reg, + info->expand_register.voltage_mask, regval); + if (ret < 0) + dev_err(rdev_get_dev(rdev), + "couldn't set voltage expand reg for regulator\n"); + + return ret; +} + static const struct regulator_ops ab8500_regulator_volt_mode_ops = { .enable = ab8500_regulator_enable, .disable = ab8500_regulator_disable, @@ -605,6 +682,18 @@ static const struct regulator_ops ab8500_regulator_volt_mode_ops = { .list_voltage = regulator_list_voltage_table, }; +static const struct regulator_ops ab8500_regulator_volt_mode_expand_ops = { + .enable = ab8500_regulator_enable, + .disable = ab8500_regulator_disable, + .is_enabled = ab8500_regulator_is_enabled, + .get_optimum_mode = ab8500_regulator_get_optimum_mode, + .set_mode = ab8500_regulator_set_mode, + .get_mode = ab8500_regulator_get_mode, + .get_voltage_sel = ab8500_regulator_get_voltage_sel_expand, + .set_voltage_sel = ab8500_regulator_set_voltage_sel_expand, + .list_voltage = regulator_list_voltage_table, +}; + static const struct regulator_ops ab8500_regulator_volt_ops = { .enable = ab8500_regulator_enable, .disable = ab8500_regulator_disable, @@ -908,12 +997,12 @@ static struct ab8500_regulator_info [AB8505_LDO_AUX3] = { .desc = { .name = "LDO-AUX3", - .ops = &ab8500_regulator_volt_mode_ops, + .ops = &ab8500_regulator_volt_mode_expand_ops, .type = REGULATOR_VOLTAGE, .id = AB8505_LDO_AUX3, .owner = THIS_MODULE, - .n_voltages = ARRAY_SIZE(ldo_vaux3_voltages), - .volt_table = ldo_vaux3_voltages, + .n_voltages = ARRAY_SIZE(ldo_vaux3_ab8505_voltages), + .volt_table = ldo_vaux3_ab8505_voltages, }, .load_lp_uA = 5000, .update_bank = 0x04, @@ -925,6 +1014,12 @@ static struct ab8500_regulator_info .voltage_bank = 0x04, .voltage_reg = 0x21, .voltage_mask = 0x07, + .expand_register = { + .voltage_limit = 8, + .voltage_bank = 0x04, + .voltage_reg = 0x01, + .voltage_mask = 0x10, + }, }, [AB8505_LDO_AUX4] = { .desc = { -- cgit v1.2.3 From 4ec4df7e54182edb6955caace37684e535e462dc Mon Sep 17 00:00:00 2001 From: Linus Walleij Date: Tue, 1 Sep 2026 22:02:08 +0200 Subject: regulator: ab8500: Handle AB8505 VINTCORE selector 7 The AB8505 VINTCORE table exposes only selectors 0 through 6. The hardware also accepts selector 7 and maps it to 1.35 V, just like selector 6. Omitting it can make an OTP-programmed selector 7 appear invalid to the regulator core. Give AB8505 its own eight-entry selector table while leaving the AB8500 table unchanged. Reference: AB8505 User Manual, DM00046744 Rev 3, p. 223 Fixes: 547f384f33db ("regulator: ab8500: add support for ab8505") Assisted-by: LLM Signed-off-by: Linus Walleij Link: https://patch.msgid.link/20260901-ux500-dts-snowball-regulator-v2-3-fe88b01829bf@kernel.org Signed-off-by: Mark Brown --- drivers/regulator/ab8500.c | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/drivers/regulator/ab8500.c b/drivers/regulator/ab8500.c index 07d96f8ff944..5e24e6cdc773 100644 --- a/drivers/regulator/ab8500.c +++ b/drivers/regulator/ab8500.c @@ -266,6 +266,17 @@ static const unsigned int ldo_vintcore_voltages[] = { 1350000, }; +static const unsigned int ldo_vintcore_ab8505_voltages[] = { + 1200000, + 1225000, + 1250000, + 1275000, + 1300000, + 1325000, + 1350000, + 1350000, +}; + static const unsigned int fixed_1200000_voltage[] = { 1200000, }; @@ -1095,8 +1106,8 @@ static struct ab8500_regulator_info .type = REGULATOR_VOLTAGE, .id = AB8505_LDO_INTCORE, .owner = THIS_MODULE, - .n_voltages = ARRAY_SIZE(ldo_vintcore_voltages), - .volt_table = ldo_vintcore_voltages, + .n_voltages = ARRAY_SIZE(ldo_vintcore_ab8505_voltages), + .volt_table = ldo_vintcore_ab8505_voltages, }, .load_lp_uA = 5000, .update_bank = 0x03, -- cgit v1.2.3 From b9fc8a8d31b914b09329240f532ff0e9c00cd727 Mon Sep 17 00:00:00 2001 From: Linus Walleij Date: Tue, 1 Sep 2026 22:02:09 +0200 Subject: regulator: ab8500: Treat cut 1.0 VAUX3 as fixed The early-cut workaround currently gives AB8500 cut 1.0 the 16 programmable VAUX3 settings introduced with cut 1.1. On cut 1.0 the selector is not programmable and VAUX3 is fixed at 1.2 V. Register VAUX3 as a fixed-voltage regulator on cut 1.0 and retain the 16-value workaround only for cut 1.1. Reference: AB8500 User Manual, UM0836 Rev 3, p. 240 Fixes: 2b75151a1041 ("regulators: Added ab8500 v2 support") Assisted-by: LLM Signed-off-by: Linus Walleij Link: https://patch.msgid.link/20260901-ux500-dts-snowball-regulator-v2-4-fe88b01829bf@kernel.org Signed-off-by: Mark Brown --- drivers/regulator/ab8500.c | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/drivers/regulator/ab8500.c b/drivers/regulator/ab8500.c index 5e24e6cdc773..42cb8dfdc7c9 100644 --- a/drivers/regulator/ab8500.c +++ b/drivers/regulator/ab8500.c @@ -1783,9 +1783,14 @@ static int ab8500_regulator_register(struct platform_device *pdev, config.driver_data = info; config.of_node = np; - /* fix for hardware before ab8500v2.0 */ - if (is_ab8500_1p1_or_earlier(ab8500)) { - if (info->desc.id == AB8500_LDO_AUX3) { + /* Handle the different VAUX3 implementations in early AB8500 cuts. */ + if (info->desc.id == AB8500_LDO_AUX3) { + if (is_ab8500_1p0_or_earlier(ab8500)) { + info->desc.ops = &ab8500_regulator_mode_ops; + info->desc.n_voltages = 1; + info->desc.volt_table = fixed_1200000_voltage; + info->voltage_mask = 0; + } else if (is_ab8500_1p1_or_earlier(ab8500)) { info->desc.n_voltages = ARRAY_SIZE(ldo_vauxn_voltages); info->desc.volt_table = ldo_vauxn_voltages; -- cgit v1.2.3 From a5ee78846015512b4d3d32f8aa463024a23234ce Mon Sep 17 00:00:00 2001 From: Linus Walleij Date: Tue, 1 Sep 2026 22:02:10 +0200 Subject: regulator: ab8500: Test dedicated enable bits only Some regulator control registers have independent enable and low-power bits. is_enabled() currently tests their combined update mask, so an off regulator with its low-power bit set is incorrectly reported as enabled. Add an optional enable mask and use it for VINTCORE, AB8500 TVOUT, AB8505 ADC, and AB8505 VAUX5/6. Regulators whose two-bit field encodes the complete operating state continue to test the full update mask. References: AB8500 User Manual, UM0836 Rev 3, p. 214; AB8505 User Manual, DM00046744 Rev 3, pp. 171-172 and 223 Fixes: 65e03ed2d0cd ("regulators: Fixed errors in ab8500 register mapping") Assisted-by: LLM Signed-off-by: Linus Walleij Link: https://patch.msgid.link/20260901-ux500-dts-snowball-regulator-v2-5-fe88b01829bf@kernel.org Signed-off-by: Mark Brown --- drivers/regulator/ab8500.c | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/drivers/regulator/ab8500.c b/drivers/regulator/ab8500.c index 42cb8dfdc7c9..05c6b9c7af0c 100644 --- a/drivers/regulator/ab8500.c +++ b/drivers/regulator/ab8500.c @@ -162,6 +162,7 @@ struct ab8500_shared_mode { * @update_bank: bank to control on/off * @update_reg: register to control on/off * @update_mask: mask to enable/disable and set mode of regulator + * @enable_mask: optional mask for an enable bit separate from the mode bit * @update_val: bits holding the regulator current mode * @update_val_idle: bits to enable the regulator in idle (low power) mode * @update_val_normal: bits to enable the regulator in normal (high power) mode @@ -183,6 +184,7 @@ struct ab8500_regulator_info { u8 update_bank; u8 update_reg; u8 update_mask; + u8 enable_mask; u8 update_val; u8 update_val_idle; u8 update_val_normal; @@ -377,6 +379,7 @@ static int ab8500_regulator_is_enabled(struct regulator_dev *rdev) { int ret; struct ab8500_regulator_info *info = rdev_get_drvdata(rdev); + u8 enable_mask; u8 regval; if (info == NULL) { @@ -392,13 +395,15 @@ static int ab8500_regulator_is_enabled(struct regulator_dev *rdev) return ret; } + enable_mask = info->enable_mask ? info->enable_mask : info->update_mask; + dev_vdbg(rdev_get_dev(rdev), "%s-is_enabled (bank, reg, mask, value): 0x%x, 0x%x, 0x%x," " 0x%x\n", info->desc.name, info->update_bank, info->update_reg, - info->update_mask, regval); + enable_mask, regval); - if (regval & info->update_mask) + if (regval & enable_mask) return 1; else return 0; @@ -833,6 +838,7 @@ static struct ab8500_regulator_info .update_bank = 0x03, .update_reg = 0x80, .update_mask = 0x44, + .enable_mask = 0x04, .update_val = 0x44, .update_val_idle = 0x44, .update_val_normal = 0x04, @@ -861,6 +867,7 @@ static struct ab8500_regulator_info .update_bank = 0x03, .update_reg = 0x80, .update_mask = 0x82, + .enable_mask = 0x02, .update_val = 0x02, .update_val_idle = 0x82, .update_val_normal = 0x02, @@ -1070,6 +1077,7 @@ static struct ab8500_regulator_info .update_bank = 0x01, .update_reg = 0x55, .update_mask = 0x18, + .enable_mask = 0x10, .update_val = 0x10, .update_val_idle = 0x18, .update_val_normal = 0x10, @@ -1092,6 +1100,7 @@ static struct ab8500_regulator_info .update_bank = 0x01, .update_reg = 0x56, .update_mask = 0x18, + .enable_mask = 0x10, .update_val = 0x10, .update_val_idle = 0x18, .update_val_normal = 0x10, @@ -1113,6 +1122,7 @@ static struct ab8500_regulator_info .update_bank = 0x03, .update_reg = 0x80, .update_mask = 0x44, + .enable_mask = 0x04, .update_val = 0x04, .update_val_idle = 0x44, .update_val_normal = 0x04, @@ -1141,6 +1151,7 @@ static struct ab8500_regulator_info .update_bank = 0x03, .update_reg = 0x80, .update_mask = 0x82, + .enable_mask = 0x02, .update_val = 0x02, .update_val_idle = 0x82, .update_val_normal = 0x02, -- cgit v1.2.3 From 71ac8878573058e2b85210760ccaeaac90796c35 Mon Sep 17 00:00:00 2001 From: Linus Walleij Date: Tue, 1 Sep 2026 22:02:11 +0200 Subject: regulator: ab8500: Propagate mode enable read errors For regulators whose enable and mode share a state field, set_mode() first reads that field so changing the requested mode does not enable a disabled rail. A register read error is currently treated as true and the driver proceeds to write the new mode, potentially enabling a rail whose state is unknown. Return the read error without changing the register or cached mode. References: AB8500 User Manual, UM0836 Rev 3, p. 227; AB8505 User Manual, DM00046744 Rev 3, p. 237 Fixes: 438e695b87e0 ("regulator: ab8500: Get rid of is_enabled from struct ab8500_regulator_info") Assisted-by: LLM Signed-off-by: Linus Walleij Link: https://patch.msgid.link/20260901-ux500-dts-snowball-regulator-v2-6-fe88b01829bf@kernel.org Signed-off-by: Mark Brown --- drivers/regulator/ab8500.c | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/drivers/regulator/ab8500.c b/drivers/regulator/ab8500.c index 05c6b9c7af0c..e4c3502c8dbc 100644 --- a/drivers/regulator/ab8500.c +++ b/drivers/regulator/ab8500.c @@ -433,7 +433,7 @@ static unsigned int ab8500_regulator_get_optimum_mode( static int ab8500_regulator_set_mode(struct regulator_dev *rdev, unsigned int mode) { - int ret = 0; + int enabled, ret = 0; u8 bank, reg, mask, val; bool lp_mode_req = false; struct ab8500_regulator_info *info = rdev_get_drvdata(rdev); @@ -490,7 +490,17 @@ static int ab8500_regulator_set_mode(struct regulator_dev *rdev, goto out_unlock; } - if (info->mode_mask || ab8500_regulator_is_enabled(rdev)) { + if (info->mode_mask) { + enabled = 1; + } else { + enabled = ab8500_regulator_is_enabled(rdev); + if (enabled < 0) { + ret = enabled; + goto out_unlock; + } + } + + if (enabled) { ret = abx500_mask_and_set_register_interruptible(info->dev, bank, reg, mask, val); if (ret < 0) { -- cgit v1.2.3 From e3030e052a0b3da577d2756d1d50a8201ee6afab Mon Sep 17 00:00:00 2001 From: Linus Walleij Date: Tue, 1 Sep 2026 22:02:12 +0200 Subject: regulator: ab8500: Use linear ranges for LDO voltages VINTCORE uses consecutive selectors with uniform 25 mV steps, with AB8505 duplicating the highest voltage at selector 7. AB8505 VAUDIO likewise has uniform 100 mV steps followed by a duplicate selector for its highest voltage. Describe these selector encodings with linear ranges and the matching regulator helpers instead of enumerated voltage tables. Keep tables for the irregular and non-monotonic VAUX and VANA selectors. Assisted-by: LLM Signed-off-by: Linus Walleij Link: https://patch.msgid.link/20260901-ux500-dts-snowball-regulator-v2-7-fe88b01829bf@kernel.org Signed-off-by: Mark Brown --- drivers/regulator/ab8500.c | 74 +++++++++++++++++++++++----------------------- 1 file changed, 37 insertions(+), 37 deletions(-) diff --git a/drivers/regulator/ab8500.c b/drivers/regulator/ab8500.c index e4c3502c8dbc..d1540099104c 100644 --- a/drivers/regulator/ab8500.c +++ b/drivers/regulator/ab8500.c @@ -258,25 +258,13 @@ static const unsigned int ldo_vaux56_voltages[] = { 2790000, }; -static const unsigned int ldo_vintcore_voltages[] = { - 1200000, - 1225000, - 1250000, - 1275000, - 1300000, - 1325000, - 1350000, +static const struct linear_range ldo_vintcore_ranges[] = { + REGULATOR_LINEAR_RANGE(1200000, 0, 6, 25000), }; -static const unsigned int ldo_vintcore_ab8505_voltages[] = { - 1200000, - 1225000, - 1250000, - 1275000, - 1300000, - 1325000, - 1350000, - 1350000, +static const struct linear_range ldo_vintcore_ab8505_ranges[] = { + REGULATOR_LINEAR_RANGE(1200000, 0, 6, 25000), + REGULATOR_LINEAR_RANGE(1350000, 7, 7, 0), }; static const unsigned int fixed_1200000_voltage[] = { @@ -306,15 +294,10 @@ static const unsigned int ldo_vana_voltages[] = { 1225000, }; -static const unsigned int ldo_vaudio_voltages[] = { - 2000000, - 2100000, - 2200000, - 2300000, - 2400000, - 2500000, - 2600000, - 2600000, /* Duplicated in Vaudio and IsoUicc Control register. */ +static const struct linear_range ldo_vaudio_ranges[] = { + REGULATOR_LINEAR_RANGE(2000000, 0, 6, 100000), + /* Duplicated in Vaudio and IsoUicc Control register. */ + REGULATOR_LINEAR_RANGE(2600000, 7, 7, 0), }; static DEFINE_MUTEX(shared_mode_mutex); @@ -720,13 +703,27 @@ static const struct regulator_ops ab8500_regulator_volt_mode_expand_ops = { .list_voltage = regulator_list_voltage_table, }; -static const struct regulator_ops ab8500_regulator_volt_ops = { +static const struct regulator_ops ab8500_regulator_linear_range_volt_mode_ops = { + .enable = ab8500_regulator_enable, + .disable = ab8500_regulator_disable, + .is_enabled = ab8500_regulator_is_enabled, + .get_optimum_mode = ab8500_regulator_get_optimum_mode, + .set_mode = ab8500_regulator_set_mode, + .get_mode = ab8500_regulator_get_mode, + .get_voltage_sel = ab8500_regulator_get_voltage_sel, + .set_voltage_sel = ab8500_regulator_set_voltage_sel, + .list_voltage = regulator_list_voltage_linear_range, + .map_voltage = regulator_map_voltage_linear_range, +}; + +static const struct regulator_ops ab8500_regulator_linear_range_volt_ops = { .enable = ab8500_regulator_enable, .disable = ab8500_regulator_disable, .is_enabled = ab8500_regulator_is_enabled, .get_voltage_sel = ab8500_regulator_get_voltage_sel, .set_voltage_sel = ab8500_regulator_set_voltage_sel, - .list_voltage = regulator_list_voltage_table, + .list_voltage = regulator_list_voltage_linear_range, + .map_voltage = regulator_map_voltage_linear_range, }; static const struct regulator_ops ab8500_regulator_mode_ops = { @@ -836,12 +833,13 @@ static struct ab8500_regulator_info [AB8500_LDO_INTCORE] = { .desc = { .name = "LDO-INTCORE", - .ops = &ab8500_regulator_volt_mode_ops, + .ops = &ab8500_regulator_linear_range_volt_mode_ops, .type = REGULATOR_VOLTAGE, .id = AB8500_LDO_INTCORE, .owner = THIS_MODULE, - .n_voltages = ARRAY_SIZE(ldo_vintcore_voltages), - .volt_table = ldo_vintcore_voltages, + .n_voltages = 7, + .linear_ranges = ldo_vintcore_ranges, + .n_linear_ranges = ARRAY_SIZE(ldo_vintcore_ranges), .enable_time = 750, }, .load_lp_uA = 5000, @@ -1121,12 +1119,13 @@ static struct ab8500_regulator_info [AB8505_LDO_INTCORE] = { .desc = { .name = "LDO-INTCORE", - .ops = &ab8500_regulator_volt_mode_ops, + .ops = &ab8500_regulator_linear_range_volt_mode_ops, .type = REGULATOR_VOLTAGE, .id = AB8505_LDO_INTCORE, .owner = THIS_MODULE, - .n_voltages = ARRAY_SIZE(ldo_vintcore_ab8505_voltages), - .volt_table = ldo_vintcore_ab8505_voltages, + .n_voltages = 8, + .linear_ranges = ldo_vintcore_ab8505_ranges, + .n_linear_ranges = ARRAY_SIZE(ldo_vintcore_ab8505_ranges), }, .load_lp_uA = 5000, .update_bank = 0x03, @@ -1169,12 +1168,13 @@ static struct ab8500_regulator_info [AB8505_LDO_AUDIO] = { .desc = { .name = "LDO-AUDIO", - .ops = &ab8500_regulator_volt_ops, + .ops = &ab8500_regulator_linear_range_volt_ops, .type = REGULATOR_VOLTAGE, .id = AB8505_LDO_AUDIO, .owner = THIS_MODULE, - .n_voltages = ARRAY_SIZE(ldo_vaudio_voltages), - .volt_table = ldo_vaudio_voltages, + .n_voltages = 8, + .linear_ranges = ldo_vaudio_ranges, + .n_linear_ranges = ARRAY_SIZE(ldo_vaudio_ranges), }, .update_bank = 0x03, .update_reg = 0x83, -- cgit v1.2.3 From f9400f0f49ef2a84c32187adde5db0d186cfb7a6 Mon Sep 17 00:00:00 2001 From: Linus Walleij Date: Tue, 1 Sep 2026 22:02:14 +0200 Subject: regulator: ab8500: Add buck converter support Register the SMPS1, SMPS2, SMPS3, ARM, APE and MOD buck converters on AB8500 and the VSMPSA, VSMPSB, VSAFE, VARM, VSMPSC and VSMPSM buck converters on AB8505 so that the new device tree nodes can supply consumers. Match each variant through its own device tree node names. AB8500 SMPS3 supplies Vsafe and AB8505 VSAFE occupies the corresponding control and selector registers at 0x0405 and 0x041b through 0x041d. AB8500 VAPE and AB8505 VSMPSC instead use 0x0402 and the 0x040e through 0x0410 selector registers. Keep separate AB8505 regulator descriptors and identifiers so these variant-specific rails are not conflated. Describe the hardware selector ranges and follow the selector-control registers when reading or changing voltage. This accounts for AB8505 using Sel2 after reset, its additional selector registers and its separate 7-bit VARM range. Use the AB8500-compatible and low-range OTP profiles found on the supported platforms for the other rails. SMPS1 through SMPS3 and VSMPSA, VSMPSB and VSAFE also expose enable and low-power mode control. Keep the ARM, APE, MOD, VARM, VSMPSC and VSMPSM rails voltage-only since their on/off state is managed with the SoC. Assisted-by: LLM Signed-off-by: Linus Walleij Link: https://patch.msgid.link/20260901-ux500-dts-snowball-regulator-v2-9-fe88b01829bf@kernel.org Signed-off-by: Mark Brown --- drivers/regulator/ab8500.c | 461 ++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 452 insertions(+), 9 deletions(-) diff --git a/drivers/regulator/ab8500.c b/drivers/regulator/ab8500.c index d1540099104c..130febf2680a 100644 --- a/drivers/regulator/ab8500.c +++ b/drivers/regulator/ab8500.c @@ -9,10 +9,12 @@ * AB8500 peripheral regulators * * AB8500 supports the following regulators: - * VAUX1/2/3, VINTCORE, VTVOUT, VUSB, VAUDIO, VAMIC1/2, VDMIC, VANA + * VSMPS1/2/3, VARM, VAPE, VMOD, VAUX1/2/3, VINTCORE, VTVOUT, + * VUSB, VAUDIO, VAMIC1/2, VDMIC, VANA * * AB8505 supports the following regulators: - * VAUX1/2/3/4/5/6, VINTCORE, VADC, VUSB, VAUDIO, VAMIC1/2, VDMIC, VANA + * VSMPSA/B/C/M, VSAFE, VARM, VAUX1/2/3/4/5/6, VINTCORE, + * VADC, VUSB, VAUDIO, VAMIC1/2, VDMIC, VANA */ #include #include @@ -39,6 +41,12 @@ enum ab8500_regulator_id { AB8500_LDO_ANAMIC2, AB8500_LDO_DMIC, AB8500_LDO_ANA, + AB8500_BUCK_SMPS1, + AB8500_BUCK_SMPS2, + AB8500_BUCK_SMPS3, + AB8500_BUCK_ARM, + AB8500_BUCK_APE, + AB8500_BUCK_MOD, AB8500_NUM_REGULATORS, }; @@ -57,6 +65,12 @@ enum ab8505_regulator_id { AB8505_LDO_ANAMIC2, AB8505_LDO_AUX8, AB8505_LDO_ANA, + AB8505_BUCK_SMPSA, + AB8505_BUCK_SMPSB, + AB8505_BUCK_SAFE, + AB8505_BUCK_ARM, + AB8505_BUCK_SMPSC, + AB8505_BUCK_SMPSM, AB8505_NUM_REGULATORS, }; @@ -172,9 +186,17 @@ struct ab8500_shared_mode { * @mode_val_idle: mode setting for low power * @mode_val_normal: mode setting for normal power * @voltage_bank: bank to control regulator voltage - * @voltage_reg: register to control regulator voltage + * @voltage_reg: first register containing a selectable regulator voltage * @voltage_mask: mask to control regulator voltage * @expand_register: additional register used to select an extra voltage + * @voltage_ctrl_bank: bank containing the voltage selector control + * @voltage_ctrl_reg: register containing the voltage selector control + * @voltage_ctrl_mask: mask selecting one of the first voltage registers + * @voltage_ext_ctrl_bank: bank containing the extended selector control + * @voltage_ext_ctrl_reg: register containing the extended selector control + * @voltage_ext_ctrl_mask: mask selecting one of the extended voltage registers + * @voltage_ext_reg: first extended voltage register + * @voltage_ext_regs: number of extended voltage registers */ struct ab8500_regulator_info { struct device *dev; @@ -202,6 +224,14 @@ struct ab8500_regulator_info { u8 voltage_reg; u8 voltage_mask; } expand_register; + u8 voltage_ctrl_bank; + u8 voltage_ctrl_reg; + u8 voltage_ctrl_mask; + u8 voltage_ext_ctrl_bank; + u8 voltage_ext_ctrl_reg; + u8 voltage_ext_ctrl_mask; + u8 voltage_ext_reg; + u8 voltage_ext_regs; }; /* voltage tables for the vauxn/vintcore supplies */ @@ -300,6 +330,40 @@ static const struct linear_range ldo_vaudio_ranges[] = { REGULATOR_LINEAR_RANGE(2600000, 7, 7, 0), }; +/* + * AB8505 buck ranges except VARM are selected by OTP. The supported + * platforms use the AB8500-compatible profiles for VSMPSA/B and the low + * profiles for VSAFE, VSMPSC and VSMPSM. + */ +static const struct linear_range buck_low_voltages[] = { + REGULATOR_LINEAR_RANGE(700000, 0, 53, 12500), + REGULATOR_LINEAR_RANGE(1362500, 54, 63, 0), +}; + +/* VSMPS3 and VSAFE have a 7-bit selector, but the same low range. */ +static const struct linear_range buck_low_7bit_voltages[] = { + REGULATOR_LINEAR_RANGE(700000, 0, 53, 12500), + REGULATOR_LINEAR_RANGE(1362500, 54, 127, 0), +}; + +/* AB8505 VARM uses a separate 0.6 V to 1.39375 V selector range. */ +static const struct linear_range ab8505_buck_arm_voltages[] = { + REGULATOR_LINEAR_RANGE(600000, 0, 127, 6250), +}; + +/* VSMPS1 and the VSMPSA AB8500-compatible profile clamp to this range. */ +static const struct linear_range buck_smps1_voltages[] = { + REGULATOR_LINEAR_RANGE(1100000, 0, 32, 0), + REGULATOR_LINEAR_RANGE(1112500, 33, 48, 12500), + REGULATOR_LINEAR_RANGE(1300000, 49, 63, 0), +}; + +/* VSMPS2 and the VSMPSB AB8500-compatible profile clamp to this range. */ +static const struct linear_range buck_smps2_voltages[] = { + REGULATOR_LINEAR_RANGE(1800000, 0, 57, 0), + REGULATOR_LINEAR_RANGE(1812500, 58, 63, 12500), +}; + static DEFINE_MUTEX(shared_mode_mutex); static struct ab8500_shared_mode ldo_anamic1_shared; static struct ab8500_shared_mode ldo_anamic2_shared; @@ -558,11 +622,67 @@ static unsigned int ab8500_regulator_get_mode(struct regulator_dev *rdev) return ret; } +static int ab8500_regulator_get_voltage_reg(struct regulator_dev *rdev, + u8 *voltage_reg) +{ + struct ab8500_regulator_info *info = rdev_get_drvdata(rdev); + u8 regval; + unsigned int selector; + int ret; + + if (info->voltage_ext_ctrl_mask) { + ret = abx500_get_register_interruptible(info->dev, + info->voltage_ext_ctrl_bank, + info->voltage_ext_ctrl_reg, ®val); + if (ret < 0) + return ret; + + selector = (regval & info->voltage_ext_ctrl_mask) >> + (ffs(info->voltage_ext_ctrl_mask) - 1); + if (selector) { + selector = min_t(unsigned int, selector, + info->voltage_ext_regs); + *voltage_reg = info->voltage_ext_reg + selector - 1; + return 0; + } + } + + if (!info->voltage_ctrl_mask) { + *voltage_reg = info->voltage_reg; + return 0; + } + + ret = abx500_get_register_interruptible(info->dev, + info->voltage_ctrl_bank, + info->voltage_ctrl_reg, ®val); + if (ret < 0) + return ret; + + /* The three hardware selector layouts all use consecutive registers. */ + switch (info->voltage_ctrl_mask) { + case 0x0c: + selector = min((unsigned int)((regval & 0x0c) >> 2), 2U); + break; + case 0x24: + selector = regval & BIT(5) ? 2 : !!(regval & BIT(2)); + break; + case 0x04: + selector = !!(regval & BIT(2)); + break; + default: + return -EINVAL; + } + + *voltage_reg = info->voltage_reg + selector; + + return 0; +} + static int ab8500_regulator_get_voltage_sel(struct regulator_dev *rdev) { int ret, voltage_shift; struct ab8500_regulator_info *info = rdev_get_drvdata(rdev); - u8 regval; + u8 regval, voltage_reg; if (info == NULL) { dev_err(rdev_get_dev(rdev), "regulator info null pointer\n"); @@ -571,8 +691,15 @@ static int ab8500_regulator_get_voltage_sel(struct regulator_dev *rdev) voltage_shift = ffs(info->voltage_mask) - 1; + ret = ab8500_regulator_get_voltage_reg(rdev, &voltage_reg); + if (ret < 0) { + dev_err(rdev_get_dev(rdev), + "couldn't read voltage selector control\n"); + return ret; + } + ret = abx500_get_register_interruptible(info->dev, - info->voltage_bank, info->voltage_reg, ®val); + info->voltage_bank, voltage_reg, ®val); if (ret < 0) { dev_err(rdev_get_dev(rdev), "couldn't read voltage reg for regulator\n"); @@ -583,7 +710,7 @@ static int ab8500_regulator_get_voltage_sel(struct regulator_dev *rdev) "%s-get_voltage (bank, reg, mask, shift, value): " "0x%x, 0x%x, 0x%x, 0x%x, 0x%x\n", info->desc.name, info->voltage_bank, - info->voltage_reg, info->voltage_mask, + voltage_reg, info->voltage_mask, voltage_shift, regval); return (regval & info->voltage_mask) >> voltage_shift; @@ -594,7 +721,7 @@ static int ab8500_regulator_set_voltage_sel(struct regulator_dev *rdev, { int ret, voltage_shift; struct ab8500_regulator_info *info = rdev_get_drvdata(rdev); - u8 regval; + u8 regval, voltage_reg; if (info == NULL) { dev_err(rdev_get_dev(rdev), "regulator info null pointer\n"); @@ -603,10 +730,17 @@ static int ab8500_regulator_set_voltage_sel(struct regulator_dev *rdev, voltage_shift = ffs(info->voltage_mask) - 1; + ret = ab8500_regulator_get_voltage_reg(rdev, &voltage_reg); + if (ret < 0) { + dev_err(rdev_get_dev(rdev), + "couldn't read voltage selector control\n"); + return ret; + } + /* set the registers for the request */ regval = (u8)selector << voltage_shift; ret = abx500_mask_and_set_register_interruptible(info->dev, - info->voltage_bank, info->voltage_reg, + info->voltage_bank, voltage_reg, info->voltage_mask, regval); if (ret < 0) dev_err(rdev_get_dev(rdev), @@ -615,7 +749,7 @@ static int ab8500_regulator_set_voltage_sel(struct regulator_dev *rdev, dev_vdbg(rdev_get_dev(rdev), "%s-set_voltage (bank, reg, mask, value): 0x%x, 0x%x, 0x%x," " 0x%x\n", - info->desc.name, info->voltage_bank, info->voltage_reg, + info->desc.name, info->voltage_bank, voltage_reg, info->voltage_mask, regval); return ret; @@ -726,6 +860,26 @@ static const struct regulator_ops ab8500_regulator_linear_range_volt_ops = { .map_voltage = regulator_map_voltage_linear_range, }; +static const struct regulator_ops ab8500_buck_ops = { + .enable = ab8500_regulator_enable, + .disable = ab8500_regulator_disable, + .is_enabled = ab8500_regulator_is_enabled, + .get_optimum_mode = ab8500_regulator_get_optimum_mode, + .set_mode = ab8500_regulator_set_mode, + .get_mode = ab8500_regulator_get_mode, + .get_voltage_sel = ab8500_regulator_get_voltage_sel, + .set_voltage_sel = ab8500_regulator_set_voltage_sel, + .list_voltage = regulator_list_voltage_linear_range, + .map_voltage = regulator_map_voltage_linear_range, +}; + +static const struct regulator_ops ab8500_buck_voltage_ops = { + .get_voltage_sel = ab8500_regulator_get_voltage_sel, + .set_voltage_sel = ab8500_regulator_set_voltage_sel, + .list_voltage = regulator_list_voltage_linear_range, + .map_voltage = regulator_map_voltage_linear_range, +}; + static const struct regulator_ops ab8500_regulator_mode_ops = { .enable = ab8500_regulator_enable, .disable = ab8500_regulator_disable, @@ -967,6 +1121,137 @@ static struct ab8500_regulator_info .update_val_idle = 0x0c, .update_val_normal = 0x04, }, + + /* Buck converters */ + [AB8500_BUCK_SMPS1] = { + .desc = { + .name = "BUCK-SMPS1", + .ops = &ab8500_buck_ops, + .type = REGULATOR_VOLTAGE, + .id = AB8500_BUCK_SMPS1, + .owner = THIS_MODULE, + .n_voltages = 64, + .linear_ranges = buck_smps1_voltages, + .n_linear_ranges = ARRAY_SIZE(buck_smps1_voltages), + }, + .load_lp_uA = 20000, + .update_bank = 0x04, + .update_reg = 0x03, + .update_mask = 0x03, + .update_val = 0x01, + .update_val_idle = 0x03, + .update_val_normal = 0x01, + .voltage_bank = 0x04, + .voltage_reg = 0x13, + .voltage_mask = 0x3f, + .voltage_ctrl_bank = 0x04, + .voltage_ctrl_reg = 0x03, + .voltage_ctrl_mask = 0x0c, + }, + [AB8500_BUCK_SMPS2] = { + .desc = { + .name = "BUCK-SMPS2", + .ops = &ab8500_buck_ops, + .type = REGULATOR_VOLTAGE, + .id = AB8500_BUCK_SMPS2, + .owner = THIS_MODULE, + .n_voltages = 64, + .linear_ranges = buck_smps2_voltages, + .n_linear_ranges = ARRAY_SIZE(buck_smps2_voltages), + }, + .load_lp_uA = 20000, + .update_bank = 0x04, + .update_reg = 0x04, + .update_mask = 0x03, + .update_val = 0x01, + .update_val_idle = 0x03, + .update_val_normal = 0x01, + .voltage_bank = 0x04, + .voltage_reg = 0x17, + .voltage_mask = 0x3f, + .voltage_ctrl_bank = 0x04, + .voltage_ctrl_reg = 0x04, + .voltage_ctrl_mask = 0x0c, + }, + [AB8500_BUCK_SMPS3] = { + .desc = { + .name = "BUCK-SMPS3", + .ops = &ab8500_buck_ops, + .type = REGULATOR_VOLTAGE, + .id = AB8500_BUCK_SMPS3, + .owner = THIS_MODULE, + .n_voltages = 128, + .linear_ranges = buck_low_7bit_voltages, + .n_linear_ranges = ARRAY_SIZE(buck_low_7bit_voltages), + }, + .load_lp_uA = 50000, + .update_bank = 0x04, + .update_reg = 0x05, + .update_mask = 0x03, + .update_val = 0x01, + .update_val_idle = 0x03, + .update_val_normal = 0x01, + .voltage_bank = 0x04, + .voltage_reg = 0x1b, + .voltage_mask = 0x7f, + .voltage_ctrl_bank = 0x04, + .voltage_ctrl_reg = 0x05, + .voltage_ctrl_mask = 0x0c, + }, + [AB8500_BUCK_ARM] = { + .desc = { + .name = "BUCK-ARM", + .ops = &ab8500_buck_voltage_ops, + .type = REGULATOR_VOLTAGE, + .id = AB8500_BUCK_ARM, + .owner = THIS_MODULE, + .n_voltages = 64, + .linear_ranges = buck_low_voltages, + .n_linear_ranges = ARRAY_SIZE(buck_low_voltages), + }, + .voltage_bank = 0x04, + .voltage_reg = 0x0b, + .voltage_mask = 0x3f, + .voltage_ctrl_bank = 0x04, + .voltage_ctrl_reg = 0x00, + .voltage_ctrl_mask = 0x0c, + }, + [AB8500_BUCK_APE] = { + .desc = { + .name = "BUCK-APE", + .ops = &ab8500_buck_voltage_ops, + .type = REGULATOR_VOLTAGE, + .id = AB8500_BUCK_APE, + .owner = THIS_MODULE, + .n_voltages = 64, + .linear_ranges = buck_low_voltages, + .n_linear_ranges = ARRAY_SIZE(buck_low_voltages), + }, + .voltage_bank = 0x04, + .voltage_reg = 0x0e, + .voltage_mask = 0x3f, + .voltage_ctrl_bank = 0x04, + .voltage_ctrl_reg = 0x02, + .voltage_ctrl_mask = 0x24, + }, + [AB8500_BUCK_MOD] = { + .desc = { + .name = "BUCK-MOD", + .ops = &ab8500_buck_voltage_ops, + .type = REGULATOR_VOLTAGE, + .id = AB8500_BUCK_MOD, + .owner = THIS_MODULE, + .n_voltages = 64, + .linear_ranges = buck_low_voltages, + .n_linear_ranges = ARRAY_SIZE(buck_low_voltages), + }, + .voltage_bank = 0x04, + .voltage_reg = 0x41, + .voltage_mask = 0x3f, + .voltage_ctrl_bank = 0x04, + .voltage_ctrl_reg = 0x40, + .voltage_ctrl_mask = 0x04, + }, }; /* AB8505 regulator information */ @@ -1265,6 +1550,152 @@ static struct ab8500_regulator_info .voltage_reg = 0x29, .voltage_mask = 0x7, }, + + /* Buck converters */ + [AB8505_BUCK_SMPSA] = { + .desc = { + .name = "BUCK-SMPSA", + .ops = &ab8500_buck_ops, + .type = REGULATOR_VOLTAGE, + .id = AB8505_BUCK_SMPSA, + .owner = THIS_MODULE, + .n_voltages = 64, + .linear_ranges = buck_smps1_voltages, + .n_linear_ranges = ARRAY_SIZE(buck_smps1_voltages), + }, + .load_lp_uA = 20000, + .update_bank = 0x04, + .update_reg = 0x03, + .update_mask = 0x03, + .update_val = 0x01, + .update_val_idle = 0x03, + .update_val_normal = 0x01, + .voltage_bank = 0x04, + .voltage_reg = 0x13, + .voltage_mask = 0x3f, + .voltage_ctrl_bank = 0x04, + .voltage_ctrl_reg = 0x03, + .voltage_ctrl_mask = 0x0c, + }, + [AB8505_BUCK_SMPSB] = { + .desc = { + .name = "BUCK-SMPSB", + .ops = &ab8500_buck_ops, + .type = REGULATOR_VOLTAGE, + .id = AB8505_BUCK_SMPSB, + .owner = THIS_MODULE, + .n_voltages = 64, + .linear_ranges = buck_smps2_voltages, + .n_linear_ranges = ARRAY_SIZE(buck_smps2_voltages), + }, + .load_lp_uA = 20000, + .update_bank = 0x04, + .update_reg = 0x04, + .update_mask = 0x03, + .update_val = 0x01, + .update_val_idle = 0x03, + .update_val_normal = 0x01, + .voltage_bank = 0x04, + .voltage_reg = 0x17, + .voltage_mask = 0x3f, + .voltage_ctrl_bank = 0x04, + .voltage_ctrl_reg = 0x04, + .voltage_ctrl_mask = 0x0c, + }, + [AB8505_BUCK_SAFE] = { + .desc = { + .name = "BUCK-SAFE", + .ops = &ab8500_buck_ops, + .type = REGULATOR_VOLTAGE, + .id = AB8505_BUCK_SAFE, + .owner = THIS_MODULE, + .n_voltages = 128, + .linear_ranges = buck_low_7bit_voltages, + .n_linear_ranges = ARRAY_SIZE(buck_low_7bit_voltages), + }, + .load_lp_uA = 50000, + .update_bank = 0x04, + .update_reg = 0x05, + .update_mask = 0x03, + .update_val = 0x01, + .update_val_idle = 0x03, + .update_val_normal = 0x01, + .voltage_bank = 0x04, + .voltage_reg = 0x1b, + .voltage_mask = 0x7f, + .voltage_ctrl_bank = 0x04, + .voltage_ctrl_reg = 0x05, + .voltage_ctrl_mask = 0x0c, + }, + [AB8505_BUCK_ARM] = { + .desc = { + .name = "BUCK-ARM", + .ops = &ab8500_buck_voltage_ops, + .type = REGULATOR_VOLTAGE, + .id = AB8505_BUCK_ARM, + .owner = THIS_MODULE, + .n_voltages = 128, + .linear_ranges = ab8505_buck_arm_voltages, + .n_linear_ranges = ARRAY_SIZE(ab8505_buck_arm_voltages), + }, + .voltage_bank = 0x04, + .voltage_reg = 0x0b, + .voltage_mask = 0x7f, + .voltage_ctrl_bank = 0x04, + .voltage_ctrl_reg = 0x00, + .voltage_ctrl_mask = 0x0c, + .voltage_ext_ctrl_bank = 0x04, + .voltage_ext_ctrl_reg = 0x28, + .voltage_ext_ctrl_mask = 0x07, + .voltage_ext_reg = 0x24, + .voltage_ext_regs = 4, + }, + [AB8505_BUCK_SMPSC] = { + .desc = { + .name = "BUCK-SMPSC", + .ops = &ab8500_buck_voltage_ops, + .type = REGULATOR_VOLTAGE, + .id = AB8505_BUCK_SMPSC, + .owner = THIS_MODULE, + .n_voltages = 64, + .linear_ranges = buck_low_voltages, + .n_linear_ranges = ARRAY_SIZE(buck_low_voltages), + }, + .voltage_bank = 0x04, + .voltage_reg = 0x0e, + .voltage_mask = 0x3f, + .voltage_ctrl_bank = 0x04, + .voltage_ctrl_reg = 0x02, + .voltage_ctrl_mask = 0x24, + .voltage_ext_ctrl_bank = 0x04, + .voltage_ext_ctrl_reg = 0x2a, + .voltage_ext_ctrl_mask = 0x03, + .voltage_ext_reg = 0x2b, + .voltage_ext_regs = 2, + }, + [AB8505_BUCK_SMPSM] = { + .desc = { + .name = "BUCK-SMPSM", + .ops = &ab8500_buck_voltage_ops, + .type = REGULATOR_VOLTAGE, + .id = AB8505_BUCK_SMPSM, + .owner = THIS_MODULE, + .n_voltages = 64, + .linear_ranges = buck_low_voltages, + .n_linear_ranges = ARRAY_SIZE(buck_low_voltages), + }, + .voltage_bank = 0x04, + .voltage_reg = 0x41, + .voltage_mask = 0x3f, + .voltage_ctrl_bank = 0x04, + .voltage_ctrl_reg = 0x40, + .voltage_ctrl_mask = 0x04, + .voltage_ext_ctrl_bank = 0x04, + .voltage_ext_ctrl_reg = 0x47, + .voltage_ext_ctrl_mask = 0x03, + .voltage_ext_reg = 0x45, + .voltage_ext_regs = 2, + }, }; static struct ab8500_shared_mode ldo_anamic1_shared = { @@ -1740,6 +2171,12 @@ static struct of_regulator_match ab8500_regulator_match[] = { { .name = "ab8500_ldo_anamic2", .driver_data = (void *) AB8500_LDO_ANAMIC2, }, { .name = "ab8500_ldo_dmic", .driver_data = (void *) AB8500_LDO_DMIC, }, { .name = "ab8500_ldo_ana", .driver_data = (void *) AB8500_LDO_ANA, }, + { .name = "ab8500_buck_smps1", .driver_data = (void *)AB8500_BUCK_SMPS1, }, + { .name = "ab8500_buck_smps2", .driver_data = (void *)AB8500_BUCK_SMPS2, }, + { .name = "ab8500_buck_smps3", .driver_data = (void *)AB8500_BUCK_SMPS3, }, + { .name = "ab8500_buck_arm", .driver_data = (void *)AB8500_BUCK_ARM, }, + { .name = "ab8500_buck_ape", .driver_data = (void *)AB8500_BUCK_APE, }, + { .name = "ab8500_buck_mod", .driver_data = (void *)AB8500_BUCK_MOD, }, }; static struct of_regulator_match ab8505_regulator_match[] = { @@ -1756,6 +2193,12 @@ static struct of_regulator_match ab8505_regulator_match[] = { { .name = "ab8500_ldo_anamic2", .driver_data = (void *) AB8505_LDO_ANAMIC2, }, { .name = "ab8500_ldo_aux8", .driver_data = (void *) AB8505_LDO_AUX8, }, { .name = "ab8500_ldo_ana", .driver_data = (void *) AB8505_LDO_ANA, }, + { .name = "ab8505_buck_smpsa", .driver_data = (void *)AB8505_BUCK_SMPSA, }, + { .name = "ab8505_buck_smpsb", .driver_data = (void *)AB8505_BUCK_SMPSB, }, + { .name = "ab8505_buck_safe", .driver_data = (void *)AB8505_BUCK_SAFE, }, + { .name = "ab8505_buck_arm", .driver_data = (void *)AB8505_BUCK_ARM, }, + { .name = "ab8505_buck_smpsc", .driver_data = (void *)AB8505_BUCK_SMPSC, }, + { .name = "ab8505_buck_smpsm", .driver_data = (void *)AB8505_BUCK_SMPSM, }, }; static struct { -- cgit v1.2.3 From ef3f3dc934305c1c4920addd361697add82381d8 Mon Sep 17 00:00:00 2001 From: Linus Walleij Date: Tue, 1 Sep 2026 22:02:15 +0200 Subject: regulator: ab8500: Preserve OTP-enabled buck regulators The SMPS enable fields are initialized from OTP and may leave a rail enabled for discrete consumers which cannot be described in the device tree. Such a rail currently looks unused to the regulator core and is disabled when constraints are completed. Read the enable field while registering each switchable buck regulator. If it is nonzero, mark the regulator boot-on and always-on dynamically so the unused-regulator sweep leaves it alone. Keep the enable operation idempotent so applying the always-on constraint preserves an OTP-selected hardware-control or low-power mode instead of forcing high-power mode. Synchronize the cached mode with the preserved field so an OTP-selected low-power state is also reported correctly. Regulators which are disabled by OTP retain normal switchable behavior. Assisted-by: LLM Signed-off-by: Linus Walleij Link: https://patch.msgid.link/20260901-ux500-dts-snowball-regulator-v2-10-fe88b01829bf@kernel.org Signed-off-by: Mark Brown --- drivers/regulator/ab8500.c | 76 ++++++++++++++++++++++++++++++++++++++++------ 1 file changed, 67 insertions(+), 9 deletions(-) diff --git a/drivers/regulator/ab8500.c b/drivers/regulator/ab8500.c index 130febf2680a..57ef3d4610e6 100644 --- a/drivers/regulator/ab8500.c +++ b/drivers/regulator/ab8500.c @@ -422,11 +422,10 @@ static int ab8500_regulator_disable(struct regulator_dev *rdev) return ret; } -static int ab8500_regulator_is_enabled(struct regulator_dev *rdev) +static int ab8500_regulator_get_enable_value(struct regulator_dev *rdev) { int ret; struct ab8500_regulator_info *info = rdev_get_drvdata(rdev); - u8 enable_mask; u8 regval; if (info == NULL) { @@ -442,18 +441,71 @@ static int ab8500_regulator_is_enabled(struct regulator_dev *rdev) return ret; } - enable_mask = info->enable_mask ? info->enable_mask : info->update_mask; - dev_vdbg(rdev_get_dev(rdev), "%s-is_enabled (bank, reg, mask, value): 0x%x, 0x%x, 0x%x," " 0x%x\n", info->desc.name, info->update_bank, info->update_reg, - enable_mask, regval); + info->update_mask, regval); + + return regval & info->update_mask; +} + +static int ab8500_regulator_is_enabled(struct regulator_dev *rdev) +{ + struct ab8500_regulator_info *info = rdev_get_drvdata(rdev); + u8 enable_mask; + int ret; + + ret = ab8500_regulator_get_enable_value(rdev); + if (ret < 0) + return ret; + + enable_mask = info->enable_mask ? info->enable_mask : info->update_mask; + + return !!(ret & enable_mask); +} - if (regval & enable_mask) - return 1; +static int ab8500_buck_enable(struct regulator_dev *rdev) +{ + int ret; + + /* Keep an OTP-selected hardware or low-power mode intact. */ + ret = ab8500_regulator_is_enabled(rdev); + if (ret) + return ret < 0 ? ret : 0; + + return ab8500_regulator_enable(rdev); +} + +static int ab8500_buck_init(struct regulator_dev *rdev, + struct regulator_config *config) +{ + struct ab8500_regulator_info *info = config->driver_data; + int ret; + + ret = ab8500_regulator_get_enable_value(rdev); + if (ret <= 0) + return ret; + + /* Report forced LP accurately; HP and hardware control are normal mode. */ + if (ret == info->update_val_idle) + info->update_val = info->update_val_idle; else - return 0; + info->update_val = info->update_val_normal; + + /* + * The SMPS enable state is selected by OTP. An enabled rail may + * supply discrete board components which are not represented as + * regulator consumers, so keep it out of the unused-regulator sweep. + */ + rdev->constraints->boot_on = true; + rdev->constraints->always_on = true; + rdev->constraints->valid_ops_mask &= ~REGULATOR_CHANGE_STATUS; + + dev_dbg(config->dev, "%s: preserving OTP-enabled state\n", + info->desc.name); + + return 0; } static unsigned int ab8500_regulator_get_optimum_mode( @@ -861,7 +913,7 @@ static const struct regulator_ops ab8500_regulator_linear_range_volt_ops = { }; static const struct regulator_ops ab8500_buck_ops = { - .enable = ab8500_regulator_enable, + .enable = ab8500_buck_enable, .disable = ab8500_regulator_disable, .is_enabled = ab8500_regulator_is_enabled, .get_optimum_mode = ab8500_regulator_get_optimum_mode, @@ -1127,6 +1179,7 @@ static struct ab8500_regulator_info .desc = { .name = "BUCK-SMPS1", .ops = &ab8500_buck_ops, + .init_cb = ab8500_buck_init, .type = REGULATOR_VOLTAGE, .id = AB8500_BUCK_SMPS1, .owner = THIS_MODULE, @@ -1152,6 +1205,7 @@ static struct ab8500_regulator_info .desc = { .name = "BUCK-SMPS2", .ops = &ab8500_buck_ops, + .init_cb = ab8500_buck_init, .type = REGULATOR_VOLTAGE, .id = AB8500_BUCK_SMPS2, .owner = THIS_MODULE, @@ -1177,6 +1231,7 @@ static struct ab8500_regulator_info .desc = { .name = "BUCK-SMPS3", .ops = &ab8500_buck_ops, + .init_cb = ab8500_buck_init, .type = REGULATOR_VOLTAGE, .id = AB8500_BUCK_SMPS3, .owner = THIS_MODULE, @@ -1556,6 +1611,7 @@ static struct ab8500_regulator_info .desc = { .name = "BUCK-SMPSA", .ops = &ab8500_buck_ops, + .init_cb = ab8500_buck_init, .type = REGULATOR_VOLTAGE, .id = AB8505_BUCK_SMPSA, .owner = THIS_MODULE, @@ -1581,6 +1637,7 @@ static struct ab8500_regulator_info .desc = { .name = "BUCK-SMPSB", .ops = &ab8500_buck_ops, + .init_cb = ab8500_buck_init, .type = REGULATOR_VOLTAGE, .id = AB8505_BUCK_SMPSB, .owner = THIS_MODULE, @@ -1606,6 +1663,7 @@ static struct ab8500_regulator_info .desc = { .name = "BUCK-SAFE", .ops = &ab8500_buck_ops, + .init_cb = ab8500_buck_init, .type = REGULATOR_VOLTAGE, .id = AB8505_BUCK_SAFE, .owner = THIS_MODULE, -- cgit v1.2.3 From 55551a09e153421482b792b02445cbd805f5ac7e Mon Sep 17 00:00:00 2001 From: Linus Walleij Date: Tue, 1 Sep 2026 22:02:16 +0200 Subject: regulator: ab8500: Use scoped guard for shared mode mutex Use a scoped mutex guard in ab8500_regulator_set_mode(). Assisted-by: LLM Signed-off-by: Linus Walleij Link: https://patch.msgid.link/20260901-ux500-dts-snowball-regulator-v2-11-fe88b01829bf@kernel.org Signed-off-by: Mark Brown --- drivers/regulator/ab8500.c | 23 ++++++++--------------- 1 file changed, 8 insertions(+), 15 deletions(-) diff --git a/drivers/regulator/ab8500.c b/drivers/regulator/ab8500.c index 57ef3d4610e6..3c1962ad85d4 100644 --- a/drivers/regulator/ab8500.c +++ b/drivers/regulator/ab8500.c @@ -20,6 +20,7 @@ #include #include #include +#include #include #include #include @@ -542,6 +543,8 @@ static int ab8500_regulator_set_mode(struct regulator_dev *rdev, return -EINVAL; } + guard(mutex)(&shared_mode_mutex); + if (info->mode_mask) { bank = info->mode_bank; reg = info->mode_reg; @@ -552,9 +555,6 @@ static int ab8500_regulator_set_mode(struct regulator_dev *rdev, mask = info->update_mask; } - if (info->shared_mode) - mutex_lock(&shared_mode_mutex); - switch (mode) { case REGULATOR_MODE_NORMAL: if (info->shared_mode) @@ -573,7 +573,7 @@ static int ab8500_regulator_set_mode(struct regulator_dev *rdev, if (!shared_regulator->shared_mode->lp_mode_req) { /* Other regulator prevent LP mode */ info->shared_mode->lp_mode_req = true; - goto out_unlock; + return 0; } lp_mode_req = true; @@ -585,18 +585,15 @@ static int ab8500_regulator_set_mode(struct regulator_dev *rdev, val = info->update_val_idle; break; default: - ret = -EINVAL; - goto out_unlock; + return -EINVAL; } if (info->mode_mask) { enabled = 1; } else { enabled = ab8500_regulator_is_enabled(rdev); - if (enabled < 0) { - ret = enabled; - goto out_unlock; - } + if (enabled < 0) + return enabled; } if (enabled) { @@ -605,7 +602,7 @@ static int ab8500_regulator_set_mode(struct regulator_dev *rdev, if (ret < 0) { dev_err(rdev_get_dev(rdev), "couldn't set regulator mode\n"); - goto out_unlock; + return ret; } dev_vdbg(rdev_get_dev(rdev), @@ -621,10 +618,6 @@ static int ab8500_regulator_set_mode(struct regulator_dev *rdev, if (info->shared_mode) info->shared_mode->lp_mode_req = lp_mode_req; -out_unlock: - if (info->shared_mode) - mutex_unlock(&shared_mode_mutex); - return ret; } -- cgit v1.2.3 From b89f8972f7547afa74a9ced5a68862892c22121a Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Sun, 13 Sep 2026 14:32:13 +0200 Subject: regulator: dt-bindings: Use consistent indentation in the example Correct indentation in the examples to consistent 2- or 4-spaces indentation to fix dt-check-style warnings ("example 0 [indent-consistent] indent mismatch ..."). Preferred is 4-spaces, but re-indenting entire example just for that is too much churn. Signed-off-by: Krzysztof Kozlowski Link: https://patch.msgid.link/20260913123212.99817-2-krzysztof.kozlowski@oss.qualcomm.com Signed-off-by: Mark Brown --- .../bindings/regulator/maxim,max77826.yaml | 4 +- .../bindings/regulator/maxim,max77838.yaml | 4 +- .../devicetree/bindings/regulator/mps,mp5416.yaml | 36 ++++++++-------- .../devicetree/bindings/regulator/mps,mp886x.yaml | 14 +++--- .../devicetree/bindings/regulator/mps,mpq7920.yaml | 50 +++++++++++----------- .../devicetree/bindings/regulator/nxp,pf0900.yaml | 2 +- .../bindings/regulator/onnn,fan53880.yaml | 4 +- .../bindings/regulator/pwm-regulator.yaml | 2 +- .../regulator/richtek,rtmv20-regulator.yaml | 6 +-- .../bindings/regulator/silergy,sy8824x.yaml | 8 ++-- .../bindings/regulator/silergy,sy8827n.yaml | 4 +- 11 files changed, 67 insertions(+), 67 deletions(-) diff --git a/Documentation/devicetree/bindings/regulator/maxim,max77826.yaml b/Documentation/devicetree/bindings/regulator/maxim,max77826.yaml index 6d6bbfbd26d4..3c02f98a38e9 100644 --- a/Documentation/devicetree/bindings/regulator/maxim,max77826.yaml +++ b/Documentation/devicetree/bindings/regulator/maxim,max77826.yaml @@ -62,6 +62,6 @@ examples: regulator-max-microvolt = <3587500>; }; }; - }; - }; + }; + }; ... diff --git a/Documentation/devicetree/bindings/regulator/maxim,max77838.yaml b/Documentation/devicetree/bindings/regulator/maxim,max77838.yaml index bed36af5493d..bbfc06fbf547 100644 --- a/Documentation/devicetree/bindings/regulator/maxim,max77838.yaml +++ b/Documentation/devicetree/bindings/regulator/maxim,max77838.yaml @@ -63,6 +63,6 @@ examples: regulator-max-microvolt = <1800000>; }; }; - }; - }; + }; + }; ... diff --git a/Documentation/devicetree/bindings/regulator/mps,mp5416.yaml b/Documentation/devicetree/bindings/regulator/mps,mp5416.yaml index f825ee9efd81..4b05e07f5537 100644 --- a/Documentation/devicetree/bindings/regulator/mps,mp5416.yaml +++ b/Documentation/devicetree/bindings/regulator/mps,mp5416.yaml @@ -53,26 +53,26 @@ examples: #size-cells = <0>; pmic@69 { - compatible = "mps,mp5416"; - reg = <0x69>; + compatible = "mps,mp5416"; + reg = <0x69>; - regulators { + regulators { - buck1 { - regulator-name = "buck1"; - regulator-min-microvolt = <600000>; - regulator-max-microvolt = <2187500>; - regulator-min-microamp = <3800000>; - regulator-max-microamp = <6800000>; - regulator-boot-on; - }; + buck1 { + regulator-name = "buck1"; + regulator-min-microvolt = <600000>; + regulator-max-microvolt = <2187500>; + regulator-min-microamp = <3800000>; + regulator-max-microamp = <6800000>; + regulator-boot-on; + }; - ldo2 { - regulator-name = "ldo2"; - regulator-min-microvolt = <800000>; - regulator-max-microvolt = <3975000>; + ldo2 { + regulator-name = "ldo2"; + regulator-min-microvolt = <800000>; + regulator-max-microvolt = <3975000>; + }; }; - }; - }; - }; + }; + }; ... diff --git a/Documentation/devicetree/bindings/regulator/mps,mp886x.yaml b/Documentation/devicetree/bindings/regulator/mps,mp886x.yaml index 6cf7c1c3c0c3..68f64e86e476 100644 --- a/Documentation/devicetree/bindings/regulator/mps,mp886x.yaml +++ b/Documentation/devicetree/bindings/regulator/mps,mp886x.yaml @@ -62,13 +62,13 @@ examples: #address-cells = <1>; #size-cells = <0>; regulator@62 { - compatible = "mps,mp8869"; - regulator-name = "vcpu"; - regulator-min-microvolt = <800000>; - regulator-max-microvolt = <1150000>; - enable-gpios = <&porta 1 GPIO_ACTIVE_LOW>; - mps,fb-voltage-divider = <80 240>; - reg = <0x62>; + compatible = "mps,mp8869"; + regulator-name = "vcpu"; + regulator-min-microvolt = <800000>; + regulator-max-microvolt = <1150000>; + enable-gpios = <&porta 1 GPIO_ACTIVE_LOW>; + mps,fb-voltage-divider = <80 240>; + reg = <0x62>; }; }; diff --git a/Documentation/devicetree/bindings/regulator/mps,mpq7920.yaml b/Documentation/devicetree/bindings/regulator/mps,mpq7920.yaml index 0d34af98403f..726aaeac054e 100644 --- a/Documentation/devicetree/bindings/regulator/mps,mpq7920.yaml +++ b/Documentation/devicetree/bindings/regulator/mps,mpq7920.yaml @@ -88,30 +88,30 @@ examples: #size-cells = <0>; pmic@69 { - compatible = "mps,mpq7920"; - reg = <0x69>; - - regulators { - mps,switch-freq = /bits/ 8 <1>; - - buck1 { - regulator-name = "buck1"; - regulator-min-microvolt = <400000>; - regulator-max-microvolt = <3587500>; - regulator-min-microamp = <460000>; - regulator-max-microamp = <7600000>; - regulator-boot-on; - mps,buck-ovp-disable; - mps,buck-phase-delay = /bits/ 8 <2>; - mps,buck-softstart = /bits/ 8 <1>; + compatible = "mps,mpq7920"; + reg = <0x69>; + + regulators { + mps,switch-freq = /bits/ 8 <1>; + + buck1 { + regulator-name = "buck1"; + regulator-min-microvolt = <400000>; + regulator-max-microvolt = <3587500>; + regulator-min-microamp = <460000>; + regulator-max-microamp = <7600000>; + regulator-boot-on; + mps,buck-ovp-disable; + mps,buck-phase-delay = /bits/ 8 <2>; + mps,buck-softstart = /bits/ 8 <1>; + }; + + ldo2 { + regulator-name = "ldo2"; + regulator-min-microvolt = <650000>; + regulator-max-microvolt = <3587500>; + }; }; - - ldo2 { - regulator-name = "ldo2"; - regulator-min-microvolt = <650000>; - regulator-max-microvolt = <3587500>; - }; - }; - }; - }; + }; + }; ... diff --git a/Documentation/devicetree/bindings/regulator/nxp,pf0900.yaml b/Documentation/devicetree/bindings/regulator/nxp,pf0900.yaml index 8c8fc2cd4ced..38fe80749c3c 100644 --- a/Documentation/devicetree/bindings/regulator/nxp,pf0900.yaml +++ b/Documentation/devicetree/bindings/regulator/nxp,pf0900.yaml @@ -160,4 +160,4 @@ examples: }; }; }; - }; + }; diff --git a/Documentation/devicetree/bindings/regulator/onnn,fan53880.yaml b/Documentation/devicetree/bindings/regulator/onnn,fan53880.yaml index b5181719daa1..1618e8f1c4c4 100644 --- a/Documentation/devicetree/bindings/regulator/onnn,fan53880.yaml +++ b/Documentation/devicetree/bindings/regulator/onnn,fan53880.yaml @@ -82,6 +82,6 @@ examples: regulator-max-microvolt = <1200000>; }; }; - }; - }; + }; + }; ... diff --git a/Documentation/devicetree/bindings/regulator/pwm-regulator.yaml b/Documentation/devicetree/bindings/regulator/pwm-regulator.yaml index 80ecf938b749..a7f48d33bad5 100644 --- a/Documentation/devicetree/bindings/regulator/pwm-regulator.yaml +++ b/Documentation/devicetree/bindings/regulator/pwm-regulator.yaml @@ -116,7 +116,7 @@ examples: regulator-max-microvolt = <1114000>; regulator-name = "vdd_logic"; - /* Voltage Duty-Cycle */ + /* Voltage Duty-Cycle */ voltage-table = <1114000 0>, <1095000 10>, <1076000 20>, diff --git a/Documentation/devicetree/bindings/regulator/richtek,rtmv20-regulator.yaml b/Documentation/devicetree/bindings/regulator/richtek,rtmv20-regulator.yaml index fec3d396ca50..1526cd071b61 100644 --- a/Documentation/devicetree/bindings/regulator/richtek,rtmv20-regulator.yaml +++ b/Documentation/devicetree/bindings/regulator/richtek,rtmv20-regulator.yaml @@ -151,9 +151,9 @@ examples: richtek,vsync-polarity-high; lsw { - regulator-name = "rtmv20,lsw"; - regulator-min-microamp = <0>; - regulator-max-microamp = <6000000>; + regulator-name = "rtmv20,lsw"; + regulator-min-microamp = <0>; + regulator-max-microamp = <6000000>; }; }; }; diff --git a/Documentation/devicetree/bindings/regulator/silergy,sy8824x.yaml b/Documentation/devicetree/bindings/regulator/silergy,sy8824x.yaml index 82af4d656177..0da920f84f89 100644 --- a/Documentation/devicetree/bindings/regulator/silergy,sy8824x.yaml +++ b/Documentation/devicetree/bindings/regulator/silergy,sy8824x.yaml @@ -35,10 +35,10 @@ examples: #address-cells = <1>; #size-cells = <0>; regulator@60 { - compatible = "silergy,sy8824c"; - regulator-min-microvolt = <800000>; - regulator-max-microvolt = <1150000>; - reg = <0x60>; + compatible = "silergy,sy8824c"; + regulator-min-microvolt = <800000>; + regulator-max-microvolt = <1150000>; + reg = <0x60>; }; }; diff --git a/Documentation/devicetree/bindings/regulator/silergy,sy8827n.yaml b/Documentation/devicetree/bindings/regulator/silergy,sy8827n.yaml index b222adabc7b4..77da91c28c19 100644 --- a/Documentation/devicetree/bindings/regulator/silergy,sy8827n.yaml +++ b/Documentation/devicetree/bindings/regulator/silergy,sy8827n.yaml @@ -39,8 +39,8 @@ examples: #address-cells = <1>; #size-cells = <0>; regulator@60 { - compatible = "silergy,sy8827n"; - reg = <0x60>; + compatible = "silergy,sy8827n"; + reg = <0x60>; }; }; -- cgit v1.2.3 From 51d6888b51e0c962250311b2cbfe5666da31dc0e Mon Sep 17 00:00:00 2001 From: Karl Mehltretter Date: Sat, 12 Sep 2026 02:06:06 +0200 Subject: regulator: qcom-rpmh: Fix the return value in rpmh_regulator_vrm_get_optimum_mode() kernel-doc rpmh_regulator_vrm_get_optimum_mode() returns REGULATOR_MODE_NORMAL or REGULATOR_MODE_IDLE and cannot fail, but its kernel-doc says "0 on success, or a negative error number on failure", which was never true. Describe the mode. Fixes: efb0cb50c427 ("regulator: qcom-rpmh: Implement get_optimum_mode(), not set_load()") Assisted-by: LLM Signed-off-by: Karl Mehltretter Link: https://patch.msgid.link/20260912000606.34614-1-kmehltretter@gmail.com Signed-off-by: Mark Brown --- drivers/regulator/qcom-rpmh-regulator.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/regulator/qcom-rpmh-regulator.c b/drivers/regulator/qcom-rpmh-regulator.c index 7d20f3e47760..4c90d206e63b 100644 --- a/drivers/regulator/qcom-rpmh-regulator.c +++ b/drivers/regulator/qcom-rpmh-regulator.c @@ -400,7 +400,7 @@ static unsigned int rpmh_regulator_vrm_get_mode(struct regulator_dev *rdev) * This function is used in the regulator_ops for VRM type RPMh regulator * devices. * - * Return: 0 on success, or a negative error number on failure + * Return: the regulator mode to use for the load */ static unsigned int rpmh_regulator_vrm_get_optimum_mode( struct regulator_dev *rdev, int input_uV, int output_uV, int load_uA) -- cgit v1.2.3 From 7a145b72280c5c3e497bfec15962611d06bde3aa Mon Sep 17 00:00:00 2001 From: Tapio Reijonen Date: Sun, 13 Sep 2026 11:40:16 +0000 Subject: regulator: dt-bindings: mps,mpq4210: Use the -ohms unit suffix The feedback divider property was added without the standard unit suffix. Rename mps,fb-voltage-divider to mps,fb-voltage-divider-ohms. The suffix is worth more here than the convention alone: mps,mp886x.yaml already describes a property of the exact same name whose values are in kilo ohms, so two bindings from the same vendor spelled the resistances identically while meaning different units. The suffix states the unit where it cannot be missed. Drop the explicit uint32-array $ref along with the rename. Properties ending in -ohms are typed by property-units.yaml, which reports the type error itself, so restating it only produced a duplicate complaint. The binding has not appeared in a release and has no in-tree users, so nothing depends on the old name. The driver is updated in the next patch. Fixes: e3c05a881fc9 ("regulator: dt-bindings: Add MPS MPQ4210") Suggested-by: Krzysztof Kozlowski Link: https://lore.kernel.org/r/20260911-gaur-of-satisfying-action-1a3b0f@quoll Signed-off-by: Tapio Reijonen Link: https://patch.msgid.link/20260913-mpq4210-ohms-fixup-v1-1-dcff627001ff@vaisala.com Signed-off-by: Mark Brown --- Documentation/devicetree/bindings/regulator/mps,mpq4210.yaml | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/Documentation/devicetree/bindings/regulator/mps,mpq4210.yaml b/Documentation/devicetree/bindings/regulator/mps,mpq4210.yaml index e9e7a87e7533..c1914aa1a9d6 100644 --- a/Documentation/devicetree/bindings/regulator/mps,mpq4210.yaml +++ b/Documentation/devicetree/bindings/regulator/mps,mpq4210.yaml @@ -34,16 +34,15 @@ properties: be permanently asserted. maxItems: 1 - mps,fb-voltage-divider: + mps,fb-voltage-divider-ohms: description: An array of two integers containing the resistor values R1 - and R2 of the output feedback voltage divider in ohms. - $ref: /schemas/types.yaml#/definitions/uint32-array + and R2 of the output feedback voltage divider. maxItems: 2 required: - compatible - reg - - mps,fb-voltage-divider + - mps,fb-voltage-divider-ohms unevaluatedProperties: false @@ -62,7 +61,7 @@ examples: regulator-max-microvolt = <20000000>; enable-gpios = <&gpio0 2 GPIO_ACTIVE_LOW>; /* R1 = 82 kOhm, R2 = 9.1 kOhm */ - mps,fb-voltage-divider = <82000 9100>; + mps,fb-voltage-divider-ohms = <82000 9100>; /* 50 mV/ms reference ramp x (82000 + 9100) / 9100 */ regulator-ramp-delay = <500>; }; -- cgit v1.2.3 From 69bd71e55b71c024bf5c105cf10ccec380861886 Mon Sep 17 00:00:00 2001 From: Tapio Reijonen Date: Sun, 13 Sep 2026 11:40:17 +0000 Subject: regulator: mpq4210: Use the -ohms feedback divider property Follow the binding rename of mps,fb-voltage-divider to mps,fb-voltage-divider-ohms. The old name was never in a release and this driver is its only reader, so it is dropped rather than kept as a fallback. Fixes: 61879d561e91 ("regulator: Add MPS MPQ4210 buck-boost regulator driver") Suggested-by: Krzysztof Kozlowski Link: https://lore.kernel.org/r/20260911-gaur-of-satisfying-action-1a3b0f@quoll Signed-off-by: Tapio Reijonen Reviewed-by: Krzysztof Kozlowski Link: https://patch.msgid.link/20260913-mpq4210-ohms-fixup-v1-2-dcff627001ff@vaisala.com Signed-off-by: Mark Brown --- drivers/regulator/mpq4210.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/drivers/regulator/mpq4210.c b/drivers/regulator/mpq4210.c index 227136d82258..315f8e02ff2a 100644 --- a/drivers/regulator/mpq4210.c +++ b/drivers/regulator/mpq4210.c @@ -144,11 +144,12 @@ static int mpq4210_i2c_probe(struct i2c_client *client) u32 r[2]; int ret; - ret = of_property_read_u32_array(dev->of_node, "mps,fb-voltage-divider", + ret = of_property_read_u32_array(dev->of_node, + "mps,fb-voltage-divider-ohms", r, ARRAY_SIZE(r)); if (ret) return dev_err_probe(dev, ret, - "failed to read mps,fb-voltage-divider\n"); + "failed to read mps,fb-voltage-divider-ohms\n"); if (!r[1]) return dev_err_probe(dev, -EINVAL, -- cgit v1.2.3 From 4cc0c5739ab8381b8c07cf6e9b66659b2f1b7530 Mon Sep 17 00:00:00 2001 From: Tapio Reijonen Date: Sun, 13 Sep 2026 11:40:18 +0000 Subject: regulator: mpq4210: Drop the mod_devicetable.h include MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit is meant to go away, and this driver does not need it: already supplies struct i2c_device_id and struct of_device_id, and both are included already. Suggested-by: Uwe Kleine-König Link: https://lore.kernel.org/r/aqRMb8q7BT3uZ9iF@monoceros Signed-off-by: Tapio Reijonen Acked-by: Uwe Kleine-König Link: https://patch.msgid.link/20260913-mpq4210-ohms-fixup-v1-3-dcff627001ff@vaisala.com Signed-off-by: Mark Brown --- drivers/regulator/mpq4210.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/regulator/mpq4210.c b/drivers/regulator/mpq4210.c index 315f8e02ff2a..293e7b209a98 100644 --- a/drivers/regulator/mpq4210.c +++ b/drivers/regulator/mpq4210.c @@ -10,7 +10,6 @@ #include #include #include -#include #include #include #include -- cgit v1.2.3 From c41b69e9f76fd9632662714c1d37860468e8d773 Mon Sep 17 00:00:00 2001 From: Wentao Liang Date: Thu, 17 Sep 2026 14:25:35 +0000 Subject: regulator: core: Fix c_rdev reference leak in regulator_resolve_coupling() of_parse_coupled_regulator() returns the coupled regulator with its device reference incremented, but regulator_resolve_coupling() returns without dropping it when the coupled regulator belongs to a different coupler, leaking the reference. Fixes: d8ca7d184b33 ("regulator: core: Introduce API for regulators coupling customization") Cc: stable@vger.kernel.org Signed-off-by: Wentao Liang Link: https://patch.msgid.link/20260917142535.2156720-1-vulab@iscas.ac.cn Signed-off-by: Mark Brown --- drivers/regulator/core.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/regulator/core.c b/drivers/regulator/core.c index 1e950260f441..b54e1d5a2f0c 100644 --- a/drivers/regulator/core.c +++ b/drivers/regulator/core.c @@ -5861,6 +5861,7 @@ static void regulator_resolve_coupling(struct regulator_dev *rdev) if (c_rdev->coupling_desc.coupler != coupler) { rdev_err(rdev, "coupler mismatch with %s\n", rdev_get_name(c_rdev)); + put_device(&c_rdev->dev); return; } -- cgit v1.2.3 From 195bbe5e1c29aa1349655a6162958149c1176034 Mon Sep 17 00:00:00 2001 From: Wentao Liang Date: Thu, 17 Sep 2026 14:28:10 +0000 Subject: regulator: core: Fix rdev reference leak in regulator_resolve_supply() regulator_resolve_supply() takes a reference on the looked-up regulator with regulator_dev_lookup(), but when the supply resolves to the regulator itself that reference is never dropped: it leaks on the early return and is lost as well when r is replaced with the dummy regulator. Release the reference before handling the self-referent case. Fixes: 4b639e254d3d ("regulator: avoid resolve_supply() infinite recursion") Cc: stable@vger.kernel.org Signed-off-by: Wentao Liang Link: https://patch.msgid.link/20260917142810.2156816-1-vulab@iscas.ac.cn Signed-off-by: Mark Brown --- drivers/regulator/core.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/regulator/core.c b/drivers/regulator/core.c index b54e1d5a2f0c..631b55142809 100644 --- a/drivers/regulator/core.c +++ b/drivers/regulator/core.c @@ -2239,6 +2239,7 @@ static int regulator_resolve_supply(struct regulator_dev *rdev) if (r == rdev) { dev_err(dev, "Supply for %s (%s) resolved to itself\n", rdev->desc->name, rdev->supply_name); + put_device(&rdev->dev); if (!have_full_constraints()) { ret = -EINVAL; goto out; -- cgit v1.2.3 From b53a09c957b682ce1d1f8e94a362c4466b6b74f6 Mon Sep 17 00:00:00 2001 From: Kees Cook Date: Thu, 17 Sep 2026 14:13:16 -0700 Subject: regulator: axp20x: Remove const from new_desc allocation types In preparation for making the devm_kmalloc family of allocators type aware, we need to make sure that the returned type from the allocation matches the type of the variable being assigned. (Before, the allocator would always return "void *", which can be implicitly cast to any pointer type.) The assigned type is "struct regulator_desc *", but the converted allocation types would be "const struct regulator_desc *", as all three sizeof()s were taken from "*desc", and "desc" is "const struct regulator_desc *". As there is no general way to remove const qualifiers, take the size from the assignment target instead. No change in allocation size results. Build tested ARCH=x86_64 allmodconfig with GCC 16.2.0: drivers/regulator/axp20x-regulator.o Assisted-by: LLM coccinelle Signed-off-by: Kees Cook Link: https://patch.msgid.link/20260917211315.i.973-kees@kernel.org Signed-off-by: Mark Brown --- drivers/regulator/axp20x-regulator.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/regulator/axp20x-regulator.c b/drivers/regulator/axp20x-regulator.c index da891415efc0..ec6ec071ffde 100644 --- a/drivers/regulator/axp20x-regulator.c +++ b/drivers/regulator/axp20x-regulator.c @@ -1652,7 +1652,7 @@ static int axp20x_regulator_probe(struct platform_device *pdev) (regulators == axp803_regulators && i == AXP803_DC1SW) || (regulators == axp809_regulators && i == AXP809_DC1SW) || (regulators == axp15060_regulators && i == AXP15060_SW)) { - new_desc = devm_kzalloc(&pdev->dev, sizeof(*desc), + new_desc = devm_kzalloc(&pdev->dev, sizeof(*new_desc), GFP_KERNEL); if (!new_desc) return -ENOMEM; @@ -1665,7 +1665,7 @@ static int axp20x_regulator_probe(struct platform_device *pdev) if ((regulators == axp22x_regulators && i == AXP22X_DC5LDO) || (regulators == axp809_regulators && i == AXP809_DC5LDO) || (regulators == axp15060_regulators && i == AXP15060_CPUSLDO)) { - new_desc = devm_kzalloc(&pdev->dev, sizeof(*desc), + new_desc = devm_kzalloc(&pdev->dev, sizeof(*new_desc), GFP_KERNEL); if (!new_desc) return -ENOMEM; @@ -1677,7 +1677,7 @@ static int axp20x_regulator_probe(struct platform_device *pdev) if (regulators == axp15060_regulators && i == AXP15060_RTC_LDO) { - new_desc = devm_kzalloc(&pdev->dev, sizeof(*desc), + new_desc = devm_kzalloc(&pdev->dev, sizeof(*new_desc), GFP_KERNEL); if (!new_desc) return -ENOMEM; -- cgit v1.2.3 From e0d673e5a5c4084f0da90c06ed3b0bc45e47d679 Mon Sep 17 00:00:00 2001 From: Wentao Liang Date: Wed, 16 Sep 2026 07:25:41 +0000 Subject: regulator: rt6190: Fix runtime PM imbalance in rt6190_out_enable() In rt6190_out_enable(), pm_runtime_get_sync() is called at the start of the function. However, if any subsequent regmap or regulator operation fails, the function returns directly without dropping the runtime PM reference, causing a runtime PM reference leak. Add an error handling path with pm_runtime_put() to keep the reference count balanced on failure. Fixes: e6999e7cca7e ("regulator: rt6190: Add support for Richtek RT6190 regulator") Cc: stable@vger.kernel.org Signed-off-by: Wentao Liang Reviewed-by: ChiYuan Huang Link: https://patch.msgid.link/20260916072541.1968033-1-vulab@iscas.ac.cn Signed-off-by: Mark Brown --- drivers/regulator/rt6190-regulator.c | 18 +++++++++++++----- 1 file changed, 13 insertions(+), 5 deletions(-) diff --git a/drivers/regulator/rt6190-regulator.c b/drivers/regulator/rt6190-regulator.c index f2cd9540038d..21ced348a2cf 100644 --- a/drivers/regulator/rt6190-regulator.c +++ b/drivers/regulator/rt6190-regulator.c @@ -108,19 +108,27 @@ static int rt6190_out_enable(struct regulator_dev *rdev) ret = regmap_raw_read(regmap, RT6190_REG_OUTV, out_cfg, sizeof(out_cfg)); if (ret) - return ret; + goto err_pm_put; ret = regulator_enable_regmap(rdev); if (ret) - return ret; + goto err_pm_put; ret = regmap_raw_write(regmap, RT6190_REG_OUTV, out_cfg, sizeof(out_cfg)); if (ret) - return ret; + goto err_pm_put; + + ret = regmap_update_bits(regmap, RT6190_REG_SET5, RT6190_ENGCP_MASK, + RT6190_ENGCP_MASK); + if (ret) + goto err_pm_put; + + return 0; - return regmap_update_bits(regmap, RT6190_REG_SET5, RT6190_ENGCP_MASK, - RT6190_ENGCP_MASK); +err_pm_put: + pm_runtime_put(data->dev); + return ret; } static int rt6190_out_disable(struct regulator_dev *rdev) -- cgit v1.2.3 From 819a3e62d37a2fe73c1e7f241f2ac086042e7757 Mon Sep 17 00:00:00 2001 From: Neil Armstrong Date: Mon, 21 Sep 2026 11:51:30 +0200 Subject: dt-bindings: vendor-prefixes: add vendor prefix for Nexperia B.V. Document the vendor prefix for the semiconductor company Nexperia B.V. The company website is https://www.nexperia.com/ Signed-off-by: Neil Armstrong Link: https://patch.msgid.link/20260921-topic-sm8x50-nex10000ub-v2-1-eeeaf9b0c913@linaro.org Signed-off-by: Mark Brown --- Documentation/devicetree/bindings/vendor-prefixes.yaml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Documentation/devicetree/bindings/vendor-prefixes.yaml b/Documentation/devicetree/bindings/vendor-prefixes.yaml index ba2002969373..9103ced78b91 100644 --- a/Documentation/devicetree/bindings/vendor-prefixes.yaml +++ b/Documentation/devicetree/bindings/vendor-prefixes.yaml @@ -1192,6 +1192,8 @@ patternProperties: description: New Vision Display (Shenzhen) Co., Ltd. "^nexbox,.*": description: Nexbox + "^nexperia,.*": + description: Nexperia B.V. "^nextthing,.*": description: Next Thing Co. "^ni,.*": -- cgit v1.2.3 From fe7052c3993a77243548b790b0428e36b3c2a1c2 Mon Sep 17 00:00:00 2001 From: Neil Armstrong Date: Mon, 21 Sep 2026 11:51:31 +0200 Subject: regulator: dt-bindings: document the Nexperia NEX10000UB dual output LCD bias power supply Document the Nexperia NEX10000UB dual output LCD bias power supply which provides programmable positive and negative output voltages mainly for display panels applications. Product datashet can be found online at [1]. [1] https://assets.nexperia.com/documents/data-sheet/NEX10000UB.pdf Signed-off-by: Neil Armstrong Link: https://patch.msgid.link/20260921-topic-sm8x50-nex10000ub-v2-2-eeeaf9b0c913@linaro.org Signed-off-by: Mark Brown --- .../bindings/regulator/nexperia,nex10000ub.yaml | 69 ++++++++++++++++++++++ 1 file changed, 69 insertions(+) create mode 100644 Documentation/devicetree/bindings/regulator/nexperia,nex10000ub.yaml diff --git a/Documentation/devicetree/bindings/regulator/nexperia,nex10000ub.yaml b/Documentation/devicetree/bindings/regulator/nexperia,nex10000ub.yaml new file mode 100644 index 000000000000..3c0db59b8c1f --- /dev/null +++ b/Documentation/devicetree/bindings/regulator/nexperia,nex10000ub.yaml @@ -0,0 +1,69 @@ +# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/regulator/nexperia,nex10000ub.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Nexperia NEX10000UB dual output LCD bias power supply + +maintainers: + - Neil Armstrong + +description: + The NEX10000UB is designed to supply positive/negative supplies for display Panels. + +properties: + compatible: + enum: + - nexperia,nex10000ub + + reg: + maxItems: 1 + + vin-supply: true + +patternProperties: + "^(vpos|vneg)$": + type: object + $ref: regulator.yaml# + unevaluatedProperties: false + + properties: + enable-gpios: + maxItems: 1 + + required: + - enable-gpios + +required: + - compatible + - reg + +additionalProperties: false + +examples: + - | + #include + + i2c { + #address-cells = <1>; + #size-cells = <0>; + + regulator@3e { + compatible = "nexperia,nex10000ub"; + reg = <0x3e>; + vin-supply = <&supply>; + + vpos { + regulator-name = "outp"; + regulator-boot-on; + enable-gpios = <&gpio 23 GPIO_ACTIVE_HIGH>; + }; + + vneg { + regulator-name = "outn"; + regulator-boot-on; + enable-gpios = <&gpio 40 GPIO_ACTIVE_HIGH>; + }; + }; + }; -- cgit v1.2.3 From 53bb6f50be851976b726712256f7fd05722a4941 Mon Sep 17 00:00:00 2001 From: Neil Armstrong Date: Mon, 21 Sep 2026 11:51:32 +0200 Subject: regulator: add regulator driver for the Nexperia NEX10000UB Add regulator support for the Nexperia NEX10000UB dual output LCD bias power supply which provides programmable positive and negative output voltages mainly for display panels applications. The driver supports setting the output voltage from 4V to 6V in 100mV steps for each output via the I2C programming interface and supports the enable GPIOs for both outputs. Product datashet can be found online at [1]. [1] https://assets.nexperia.com/documents/data-sheet/NEX10000UB.pdf Signed-off-by: Neil Armstrong Link: https://patch.msgid.link/20260921-topic-sm8x50-nex10000ub-v2-3-eeeaf9b0c913@linaro.org Signed-off-by: Mark Brown --- drivers/regulator/Kconfig | 8 ++ drivers/regulator/Makefile | 1 + drivers/regulator/nex10000ub-regulator.c | 147 +++++++++++++++++++++++++++++++ 3 files changed, 156 insertions(+) create mode 100644 drivers/regulator/nex10000ub-regulator.c diff --git a/drivers/regulator/Kconfig b/drivers/regulator/Kconfig index 89789ac7a786..4b98ce62ba01 100644 --- a/drivers/regulator/Kconfig +++ b/drivers/regulator/Kconfig @@ -1020,6 +1020,14 @@ config REGULATOR_MTK_DVFSRC of Mediatek. It allows for voting on regulator state between multiple users. +config REGULATOR_NEX10000UB + tristate "Nexperia NEX10000UB Dual Output Power regulators" + depends on I2C && GPIOLIB + select REGMAP_I2C + help + This driver supports the NEX10000UB single inductor - dual output + power supply specifically designed for display panels. + config REGULATOR_PALMAS tristate "TI Palmas PMIC Regulators" depends on MFD_PALMAS diff --git a/drivers/regulator/Makefile b/drivers/regulator/Makefile index 5a764cec8df8..907efdf644eb 100644 --- a/drivers/regulator/Makefile +++ b/drivers/regulator/Makefile @@ -120,6 +120,7 @@ obj-$(CONFIG_REGULATOR_MT6370) += mt6370-regulator.o obj-$(CONFIG_REGULATOR_MT6380) += mt6380-regulator.o obj-$(CONFIG_REGULATOR_MT6397) += mt6397-regulator.o obj-$(CONFIG_REGULATOR_MTK_DVFSRC) += mtk-dvfsrc-regulator.o +obj-$(CONFIG_REGULATOR_NEX10000UB) += nex10000ub-regulator.o obj-$(CONFIG_REGULATOR_QCOM_LABIBB) += qcom-labibb-regulator.o obj-$(CONFIG_REGULATOR_QCOM_PM8008) += qcom-pm8008-regulator.o obj-$(CONFIG_REGULATOR_QCOM_REFGEN) += qcom-refgen-regulator.o diff --git a/drivers/regulator/nex10000ub-regulator.c b/drivers/regulator/nex10000ub-regulator.c new file mode 100644 index 000000000000..f44b8b7906b9 --- /dev/null +++ b/drivers/regulator/nex10000ub-regulator.c @@ -0,0 +1,147 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Nexperia NEX10000UB Regulator driver + * + * Copyright (C) 2026 Linaro Limited. + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#define NEX10000UB_REG_VPOS 0x00 +#define NEX10000UB_REG_VNEG 0x01 +#define NEX10000UB_REG_ID 0x02 + +#define NEX10000UB_VOUT_MASK 0x1F +#define NEX10000UB_VOUT_N_VOLTAGE 0x15 +#define NEX10000UB_VOUT_VMIN 4000000 +#define NEX10000UB_VOUT_VMAX 6000000 +#define NEX10000UB_VOUT_STEP 100000 + +#define NEX10000UB_REGULATOR_ID_VPOS 0 +#define NEX10000UB_REGULATOR_ID_VNEG 1 +#define NEX10000UB_MAX_REGULATORS 2 + +static const struct regulator_ops nex10000ub_regulator_ops = { + .enable = regulator_enable_regmap, + .disable = regulator_disable_regmap, + .is_enabled = regulator_is_enabled_regmap, + .list_voltage = regulator_list_voltage_linear, + .map_voltage = regulator_map_voltage_linear, + .get_voltage_sel = regulator_get_voltage_sel_regmap, + .set_voltage_sel = regulator_set_voltage_sel_regmap, +}; + +static int nex10000ub_of_parse_cb(struct device_node *np, + const struct regulator_desc *desc, + struct regulator_config *config) +{ + struct gpio_desc *ena_gpiod; + + ena_gpiod = fwnode_gpiod_get_index(of_fwnode_handle(np), "enable", 0, + GPIOD_OUT_LOW, desc->name); + if (IS_ERR(ena_gpiod)) + return PTR_ERR(ena_gpiod); + + config->ena_gpiod = ena_gpiod; + + return 0; +} + +#define NEX10000UB_REGULATOR_DESC(_id, _name) \ + [NEX10000UB_REGULATOR_ID_##_id] = { \ + .name = "nex10000ub-"#_name, \ + .supply_name = "vin", \ + .id = NEX10000UB_REGULATOR_ID_##_id, \ + .of_match = of_match_ptr(#_name), \ + .of_parse_cb = nex10000ub_of_parse_cb, \ + .ops = &nex10000ub_regulator_ops, \ + .n_voltages = NEX10000UB_VOUT_N_VOLTAGE, \ + .min_uV = NEX10000UB_VOUT_VMIN, \ + .uV_step = NEX10000UB_VOUT_STEP, \ + .enable_time = 2000, \ + .vsel_mask = NEX10000UB_VOUT_MASK, \ + .vsel_reg = NEX10000UB_REG_##_id, \ + .type = REGULATOR_VOLTAGE, \ + .owner = THIS_MODULE, \ + } + +static const struct regulator_desc nex10000_regs_desc[NEX10000UB_MAX_REGULATORS] = { + NEX10000UB_REGULATOR_DESC(VPOS, vpos), + NEX10000UB_REGULATOR_DESC(VNEG, vneg), +}; + +static const struct regmap_config nex10000ub_regmap_config = { + .reg_bits = 8, + .val_bits = 8, + .max_register = NEX10000UB_REG_ID, + .cache_type = REGCACHE_NONE, +}; + +static int nex10000ub_probe(struct i2c_client *client) +{ + struct device *dev = &client->dev; + struct regmap *map; + int id; + int ret; + + map = devm_regmap_init_i2c(client, &nex10000ub_regmap_config); + if (IS_ERR(map)) { + ret = PTR_ERR(map); + dev_err(dev, "regmap init failed: %d\n", ret); + return ret; + } + + for (id = 0; id < NEX10000UB_MAX_REGULATORS; ++id) { + struct regulator_config config = { }; + struct regulator_dev *rdev; + + config.regmap = map; + config.dev = dev; + + rdev = devm_regulator_register(dev, &nex10000_regs_desc[id], + &config); + if (IS_ERR(rdev)) { + ret = PTR_ERR(rdev); + dev_err(dev, "regulator %s register failed: %d\n", + nex10000_regs_desc[id].name, ret); + return ret; + } + } + + return 0; +} + +static const struct i2c_device_id nex10000ub_id[] = { + { .name = "nex10000ub" }, + { } +}; +MODULE_DEVICE_TABLE(i2c, nex10000ub_id); + +static const struct of_device_id __maybe_unused nex10000ub_of_match[] = { + { .compatible = "nexperia,nex10000ub" }, + {}, +}; +MODULE_DEVICE_TABLE(of, nex10000ub_of_match); + +static struct i2c_driver nex10000ub_i2c_driver = { + .driver = { + .name = "nex10000ub", + .probe_type = PROBE_PREFER_ASYNCHRONOUS, + .of_match_table = of_match_ptr(nex10000ub_of_match), + }, + .probe = nex10000ub_probe, + .id_table = nex10000ub_id, +}; + +module_i2c_driver(nex10000ub_i2c_driver); + +MODULE_DESCRIPTION("NEX10000UB regulator driver"); +MODULE_AUTHOR("Neil Armstrong "); +MODULE_LICENSE("GPL"); -- cgit v1.2.3 From 87121c42fadc7683469aee96ad833bc560197a55 Mon Sep 17 00:00:00 2001 From: Jisheng Zhang Date: Wed, 9 Sep 2026 22:39:56 +0800 Subject: regulator: mp886x: check get_voltage_sel() return value The get_voltage_sel() can fail, resulting in negative error codes stored in unsigned integers and corrupted state logic. Fixes: 97be82880b61 ("regulator: add support for MP8869 regulator") Signed-off-by: Jisheng Zhang Closes: https://sashiko.dev/#/patchset/20260901043123.5401-1-jszhang@kernel.org?part=1 Link: https://patch.msgid.link/20260909143957.9284-2-jszhang@kernel.org Signed-off-by: Mark Brown --- drivers/regulator/mp886x.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/drivers/regulator/mp886x.c b/drivers/regulator/mp886x.c index e0b62bc02a1e..bc25cba33c8b 100644 --- a/drivers/regulator/mp886x.c +++ b/drivers/regulator/mp886x.c @@ -256,6 +256,7 @@ static int mp886x_regulator_register(struct mp886x_device_info *di, { struct regulator_desc *rdesc = &di->desc; struct regulator_dev *rdev; + int sel; rdesc->name = "mp886x-reg"; rdesc->supply_name = "vin"; @@ -277,7 +278,12 @@ static int mp886x_regulator_register(struct mp886x_device_info *di, rdev = devm_regulator_register(di->dev, &di->desc, config); if (IS_ERR(rdev)) return PTR_ERR(rdev); - di->sel = rdesc->ops->get_voltage_sel(rdev); + + sel = rdesc->ops->get_voltage_sel(rdev); + if (sel < 0) + return sel; + di->sel = sel; + return 0; } -- cgit v1.2.3 From d16ef5debccc4289c1f25309a2cccfbbe879601a Mon Sep 17 00:00:00 2001 From: Jisheng Zhang Date: Wed, 9 Sep 2026 22:39:57 +0800 Subject: regulator: mp886x: fix pontential division by zero If the "mps,fb-voltage-divider" 2nd var is 0, there will be division by zero bug. Fixes: 97be82880b61 ("regulator: add support for MP8869 regulator") Signed-off-by: Jisheng Zhang Closes: https://sashiko.dev/#/patchset/20260901043123.5401-1-jszhang@kernel.org?part=1 Link: https://patch.msgid.link/20260909143957.9284-3-jszhang@kernel.org Signed-off-by: Mark Brown --- drivers/regulator/mp886x.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/regulator/mp886x.c b/drivers/regulator/mp886x.c index bc25cba33c8b..dda34bf0a74d 100644 --- a/drivers/regulator/mp886x.c +++ b/drivers/regulator/mp886x.c @@ -317,6 +317,9 @@ static int mp886x_i2c_probe(struct i2c_client *client) if (ret) return ret; + if (di->r[1] == 0) + return -EINVAL; + di->en_gpio = devm_gpiod_get(dev, "enable", GPIOD_OUT_HIGH); if (IS_ERR(di->en_gpio)) return PTR_ERR(di->en_gpio); -- cgit v1.2.3 From 22fe14c9bcb6f249818f5aea23fec72b53d4b09f Mon Sep 17 00:00:00 2001 From: "Rob Herring (Arm)" Date: Tue, 22 Sep 2026 14:55:01 -0500 Subject: regulator: dt-bindings: Convert mediatek,mt6380-regulator to DT schema Convert the MediaTek mediatek,mt6380-regulator binding to DT schema format. It's a straight forward conversion. The regulators are part of the "pwrap" block, so add a $ref to them. Assisted-by: LLM Signed-off-by: Rob Herring (Arm) Link: https://patch.msgid.link/20260922195502.818012-1-robh@kernel.org Signed-off-by: Mark Brown --- .../regulator/mediatek,mt6380-regulator.yaml | 117 +++++++++++++++++++++ .../bindings/regulator/mt6380-regulator.txt | 89 ---------------- .../bindings/soc/mediatek/mediatek,pwrap.yaml | 3 + 3 files changed, 120 insertions(+), 89 deletions(-) create mode 100644 Documentation/devicetree/bindings/regulator/mediatek,mt6380-regulator.yaml delete mode 100644 Documentation/devicetree/bindings/regulator/mt6380-regulator.txt diff --git a/Documentation/devicetree/bindings/regulator/mediatek,mt6380-regulator.yaml b/Documentation/devicetree/bindings/regulator/mediatek,mt6380-regulator.yaml new file mode 100644 index 000000000000..0b3c604da727 --- /dev/null +++ b/Documentation/devicetree/bindings/regulator/mediatek,mt6380-regulator.yaml @@ -0,0 +1,117 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/regulator/mediatek,mt6380-regulator.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: MediaTek MT6380 Regulator + +maintainers: + - Sean Wang + +properties: + compatible: + const: mediatek,mt6380-regulator + +patternProperties: + '^buck-(vcore1?|vrf)$': + description: BUCK regulators + $ref: regulator.yaml# + unevaluatedProperties: false + + required: + - regulator-min-microvolt + - regulator-max-microvolt + - regulator-ramp-delay + + '^ldo-v([mat]|phy|ddr)$': + type: object + description: LDO regulators + $ref: regulator.yaml# + unevaluatedProperties: false + + required: + - regulator-min-microvolt + - regulator-max-microvolt + - regulator-ramp-delay + +required: + - compatible + +additionalProperties: false + +examples: + - | + regulators { + compatible = "mediatek,mt6380-regulator"; + + buck-vcore1 { + regulator-name = "vcore1"; + regulator-min-microvolt = <600000>; + regulator-max-microvolt = <1393750>; + regulator-ramp-delay = <6250>; + regulator-always-on; + regulator-boot-on; + }; + + buck-vcore { + regulator-name = "vcore"; + regulator-min-microvolt = <600000>; + regulator-max-microvolt = <1393750>; + regulator-ramp-delay = <6250>; + }; + + buck-vrf { + regulator-name = "vrf"; + regulator-min-microvolt = <1200000>; + regulator-max-microvolt = <1575000>; + regulator-ramp-delay = <0>; + regulator-always-on; + regulator-boot-on; + }; + + ldo-vm { + regulator-name = "vm"; + regulator-min-microvolt = <1050000>; + regulator-max-microvolt = <1400000>; + regulator-ramp-delay = <0>; + regulator-always-on; + regulator-boot-on; + }; + + ldo-va { + regulator-name = "va"; + regulator-min-microvolt = <2200000>; + regulator-max-microvolt = <3300000>; + regulator-ramp-delay = <0>; + regulator-always-on; + regulator-boot-on; + }; + + ldo-vphy { + regulator-name = "vphy"; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + regulator-ramp-delay = <0>; + regulator-always-on; + regulator-boot-on; + }; + + ldo-vddr { + regulator-name = "vddr"; + regulator-min-microvolt = <1240000>; + regulator-max-microvolt = <1840000>; + regulator-ramp-delay = <0>; + regulator-always-on; + regulator-boot-on; + }; + + ldo-vt { + regulator-name = "vt"; + regulator-min-microvolt = <2200000>; + regulator-max-microvolt = <3300000>; + regulator-ramp-delay = <0>; + regulator-always-on; + regulator-boot-on; + }; + }; diff --git a/Documentation/devicetree/bindings/regulator/mt6380-regulator.txt b/Documentation/devicetree/bindings/regulator/mt6380-regulator.txt deleted file mode 100644 index 0058441f16d2..000000000000 --- a/Documentation/devicetree/bindings/regulator/mt6380-regulator.txt +++ /dev/null @@ -1,89 +0,0 @@ -MediaTek MT6380 Regulator - -All voltage regulators provided by the MT6380 PMIC are described as the -subnodes of the MT6380 regulators node. Each regulator is named according -to its regulator type, buck- and ldo-. The definition for each -of these nodes is defined using the standard binding for regulators at -Documentation/devicetree/bindings/regulator/regulator.txt. - -The valid names for regulators are: -BUCK: - buck-core1, buck-vcore, buck-vrf -LDO: - ldo-vm ,ldo-va , ldo-vphy, ldo-vddr, ldo-vt - -Example: - - regulators { - compatible = "mediatek,mt6380-regulator"; - - mt6380_vcpu_reg: buck-vcore1 { - regulator-name = "vcore1"; - regulator-min-microvolt = < 600000>; - regulator-max-microvolt = <1393750>; - regulator-ramp-delay = <6250>; - regulator-always-on; - regulator-boot-on; - }; - - mt6380_vcore_reg: buck-vcore { - regulator-name = "vcore"; - regulator-min-microvolt = <600000>; - regulator-max-microvolt = <1393750>; - regulator-ramp-delay = <6250>; - }; - - mt6380_vrf_reg: buck-vrf { - regulator-name = "vrf"; - regulator-min-microvolt = <1200000>; - regulator-max-microvolt = <1575000>; - regulator-ramp-delay = <0>; - regulator-always-on; - regulator-boot-on; - }; - - mt6380_vm_reg: ldo-vm { - regulator-name = "vm"; - regulator-min-microvolt = <1050000>; - regulator-max-microvolt = <1400000>; - regulator-ramp-delay = <0>; - regulator-always-on; - regulator-boot-on; - }; - - mt6380_va_reg: ldo-va { - regulator-name = "va"; - regulator-min-microvolt = <2200000>; - regulator-max-microvolt = <3300000>; - regulator-ramp-delay = <0>; - regulator-always-on; - regulator-boot-on; - }; - - mt6380_vphy_reg: ldo-vphy { - regulator-name = "vphy"; - regulator-min-microvolt = <1800000>; - regulator-max-microvolt = <1800000>; - regulator-ramp-delay = <0>; - regulator-always-on; - regulator-boot-on; - }; - - mt6380_vddr_reg: ldo-vddr { - regulator-name = "vddr"; - regulator-min-microvolt = <1240000>; - regulator-max-microvolt = <1840000>; - regulator-ramp-delay = <0>; - regulator-always-on; - regulator-boot-on; - }; - - mt6380_vt_reg: ldo-vt { - regulator-name = "vt"; - regulator-min-microvolt = <2200000>; - regulator-max-microvolt = <3300000>; - regulator-ramp-delay = <0>; - regulator-always-on; - regulator-boot-on; - }; - }; diff --git a/Documentation/devicetree/bindings/soc/mediatek/mediatek,pwrap.yaml b/Documentation/devicetree/bindings/soc/mediatek/mediatek,pwrap.yaml index e7c4a3984c60..79b755858bad 100644 --- a/Documentation/devicetree/bindings/soc/mediatek/mediatek,pwrap.yaml +++ b/Documentation/devicetree/bindings/soc/mediatek/mediatek,pwrap.yaml @@ -105,6 +105,9 @@ properties: pmic: type: object + regulators: + $ref: /schemas/regulator/mediatek,mt6380-regulator.yaml# + required: - compatible - reg -- cgit v1.2.3 From 3944065c67f5209953cdc64bf7ab81a13845b516 Mon Sep 17 00:00:00 2001 From: "Rob Herring (Arm)" Date: Tue, 22 Sep 2026 16:21:39 -0500 Subject: regulator: dt-bindings: Add MAX20024 sd4 Allow the MAX20024 extra sd4 regulator and its in-sd4 supply in the MAX77620 regulator schema. The other DCDC and LDO names remain unchanged. Assisted-by: LLM Signed-off-by: Rob Herring (Arm) Reviewed-by: Svyatoslav Ryhel Link: https://patch.msgid.link/20260922212140.1118832-1-robh@kernel.org Signed-off-by: Mark Brown --- .../bindings/regulator/maxim,max77620-regulator.yaml | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/Documentation/devicetree/bindings/regulator/maxim,max77620-regulator.yaml b/Documentation/devicetree/bindings/regulator/maxim,max77620-regulator.yaml index 7118c34961ba..0f2901cab8af 100644 --- a/Documentation/devicetree/bindings/regulator/maxim,max77620-regulator.yaml +++ b/Documentation/devicetree/bindings/regulator/maxim,max77620-regulator.yaml @@ -10,17 +10,17 @@ maintainers: - Svyatoslav Ryhel description: - Device has multiple DCDC(sd[0-3]) and LDOs(ldo[0-8]). The input supply - of these regulators are defined under parent device node. Details of - regulator properties are defined as child node under sub-node "regulators" - which is child node of device node. + Device has multiple DCDC (sd[0-3], plus sd4 on MAX20024) and LDOs + (ldo[0-8]). The input supply of these regulators are defined under parent + device node. Details of regulator properties are defined as child node under + sub-node "regulators" which is child node of device node. patternProperties: - "^in-(sd[0-3]|ldo(0-1|2|3-5|4-6|7-8))-supply$": + "^in-(sd[0-4]|ldo(0-1|2|3-5|4-6|7-8))-supply$": $ref: /schemas/types.yaml#/definitions/phandle description: Input supply for DCDC or LDO - "^(sd[0-3]|ldo[0-8])$": + "^(sd[0-4]|ldo[0-8])$": type: object $ref: /schemas/regulator/regulator.yaml# unevaluatedProperties: false -- cgit v1.2.3 From 05a3330f490cfa266831c0fc7f8c6df942866d59 Mon Sep 17 00:00:00 2001 From: Bhargav Joshi Date: Sat, 19 Sep 2026 02:31:25 +0530 Subject: regulator: dt-bindings: ti,tps6586x: Convert to DT schema Convert Texas Instruments tps6586x regulator binding from text to DT schema. Reference to nvidia,tegra-regulators-coupling in child regulator nodes. Reviewed-by: Rob Herring (Arm) Signed-off-by: Bhargav Joshi Link: https://patch.msgid.link/20260919-ti-tps6586x-v3-4-63dd240f4684@gmail.com Signed-off-by: Mark Brown --- .../devicetree/bindings/regulator/ti,tps6586x.yaml | 196 +++++++++++++++++++++ .../devicetree/bindings/regulator/tps6586x.txt | 135 -------------- 2 files changed, 196 insertions(+), 135 deletions(-) create mode 100644 Documentation/devicetree/bindings/regulator/ti,tps6586x.yaml delete mode 100644 Documentation/devicetree/bindings/regulator/tps6586x.txt diff --git a/Documentation/devicetree/bindings/regulator/ti,tps6586x.yaml b/Documentation/devicetree/bindings/regulator/ti,tps6586x.yaml new file mode 100644 index 000000000000..1f7c7b35066f --- /dev/null +++ b/Documentation/devicetree/bindings/regulator/ti,tps6586x.yaml @@ -0,0 +1,196 @@ +# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/regulator/ti,tps6586x.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: TI TPS6586x family of regulators + +maintainers: + - Thierry Reding + +properties: + compatible: + const: ti,tps6586x + + reg: + maxItems: 1 + + interrupts: + maxItems: 1 + + "#gpio-cells": + const: 2 + + gpio-controller: true + + sys-supply: + description: The input supply for SYS. + + ti,system-power-controller: + type: boolean + description: + Whether or not this PMIC is controlling the system power. + + regulators: + type: object + additionalProperties: false + description: + list of regulators provided by this controller, LDO5 and LDO_RTC is + supplied by SYS regulator internally and driver take care of making + proper parent child relationship. + + properties: + sys: + type: object + $ref: regulator.yaml# + unevaluatedProperties: false + + patternProperties: + "^ldo([0-9]|_rtc)$": + type: object + allOf: + - $ref: /schemas/regulator/regulator.yaml# + - $ref: /schemas/regulator/nvidia,tegra-regulators-coupling.yaml# + unevaluatedProperties: false + + "^sm[0-2]$": + type: object + allOf: + - $ref: /schemas/regulator/regulator.yaml# + - $ref: /schemas/regulator/nvidia,tegra-regulators-coupling.yaml# + unevaluatedProperties: false + +patternProperties: + "^vin-sm[0-2]-supply$": + description: The input supply for the corresponding SM (SM0, SM1, or SM2). + + "^vinldo(01|23|4|678|9)-supply$": + description: The input supply for the corresponding LDO or group of LDOs. + +required: + - compatible + - reg + - interrupts + - regulators + - "#gpio-cells" + - gpio-controller + - sys-supply + - vin-sm0-supply + - vin-sm1-supply + - vin-sm2-supply + - vinldo01-supply + - vinldo23-supply + - vinldo4-supply + - vinldo678-supply + - vinldo9-supply + +additionalProperties: false + +examples: + - | + i2c { + #address-cells = <1>; + #size-cells = <0>; + + pmic@34 { + compatible = "ti,tps6586x"; + reg = <0x34>; + interrupts = <0 88 0x4>; + + #gpio-cells = <2>; + gpio-controller; + + ti,system-power-controller; + + sys-supply = <&vdd_5v0_sys>; + vin-sm0-supply = <&sys_reg>; + vin-sm1-supply = <&sys_reg>; + vin-sm2-supply = <&sys_reg>; + vinldo01-supply = <&sm2_reg>; + vinldo23-supply = <&sm2_reg>; + vinldo4-supply = <&sm2_reg>; + vinldo678-supply = <&sm2_reg>; + vinldo9-supply = <&sm2_reg>; + + regulators { + sys { + regulator-name = "vdd_sys"; + regulator-boot-on; + regulator-always-on; + }; + + sm0 { + regulator-min-microvolt = < 725000>; + regulator-max-microvolt = <1500000>; + regulator-boot-on; + regulator-always-on; + }; + + sm1 { + regulator-min-microvolt = < 725000>; + regulator-max-microvolt = <1500000>; + regulator-boot-on; + regulator-always-on; + }; + + sm2 { + regulator-min-microvolt = <3000000>; + regulator-max-microvolt = <4550000>; + regulator-boot-on; + regulator-always-on; + }; + + ldo0 { + regulator-name = "PCIE CLK"; + regulator-min-microvolt = <3300000>; + regulator-max-microvolt = <3300000>; + }; + + ldo1 { + regulator-min-microvolt = < 725000>; + regulator-max-microvolt = <1500000>; + }; + + ldo2 { + regulator-min-microvolt = < 725000>; + regulator-max-microvolt = <1500000>; + }; + + ldo3 { + regulator-min-microvolt = <1250000>; + regulator-max-microvolt = <3300000>; + }; + + ldo4 { + regulator-min-microvolt = <1700000>; + regulator-max-microvolt = <2475000>; + }; + + ldo5 { + regulator-min-microvolt = <1250000>; + regulator-max-microvolt = <3300000>; + }; + + ldo6 { + regulator-min-microvolt = <1250000>; + regulator-max-microvolt = <3300000>; + }; + + ldo7 { + regulator-min-microvolt = <1250000>; + regulator-max-microvolt = <3300000>; + }; + + ldo8 { + regulator-min-microvolt = <1250000>; + regulator-max-microvolt = <3300000>; + }; + + ldo9 { + regulator-min-microvolt = <1250000>; + regulator-max-microvolt = <3300000>; + }; + }; + }; + }; diff --git a/Documentation/devicetree/bindings/regulator/tps6586x.txt b/Documentation/devicetree/bindings/regulator/tps6586x.txt deleted file mode 100644 index 8b40cac24d93..000000000000 --- a/Documentation/devicetree/bindings/regulator/tps6586x.txt +++ /dev/null @@ -1,135 +0,0 @@ -TPS6586x family of regulators - -Required properties: -- compatible: "ti,tps6586x" -- reg: I2C slave address -- interrupts: the interrupt outputs of the controller -- #gpio-cells: number of cells to describe a GPIO -- gpio-controller: mark the device as a GPIO controller -- regulators: A node that houses a sub-node for each regulator within the - device. Each sub-node is identified using the node's name (or the deprecated - regulator-compatible property if present), with valid values listed below. - The content of each sub-node is defined by the standard binding for - regulators; see regulator.txt. - sys, sm[0-2], ldo[0-9] and ldo_rtc -- sys-supply: The input supply for SYS. -- vin-sm0-supply: The input supply for the SM0. -- vin-sm1-supply: The input supply for the SM1. -- vin-sm2-supply: The input supply for the SM2. -- vinldo01-supply: The input supply for the LDO1 and LDO2 -- vinldo23-supply: The input supply for the LDO2 and LDO3 -- vinldo4-supply: The input supply for the LDO4 -- vinldo678-supply: The input supply for the LDO6, LDO7 and LDO8 -- vinldo9-supply: The input supply for the LDO9 - -Optional properties: -- ti,system-power-controller: Telling whether or not this pmic is controlling - the system power. - -Each regulator is defined using the standard binding for regulators. - -Note: LDO5 and LDO_RTC is supplied by SYS regulator internally and driver - take care of making proper parent child relationship. - -Example: - - pmu: tps6586x@34 { - compatible = "ti,tps6586x"; - reg = <0x34>; - interrupts = <0 88 0x4>; - - #gpio-cells = <2>; - gpio-controller; - - ti,system-power-controller; - - sys-supply = <&some_reg>; - vin-sm0-supply = <&some_reg>; - vin-sm1-supply = <&some_reg>; - vin-sm2-supply = <&some_reg>; - vinldo01-supply = <...>; - vinldo23-supply = <...>; - vinldo4-supply = <...>; - vinldo678-supply = <...>; - vinldo9-supply = <...>; - - regulators { - sys_reg: sys { - regulator-name = "vdd_sys"; - regulator-boot-on; - regulator-always-on; - }; - - sm0_reg: sm0 { - regulator-min-microvolt = < 725000>; - regulator-max-microvolt = <1500000>; - regulator-boot-on; - regulator-always-on; - }; - - sm1_reg: sm1 { - regulator-min-microvolt = < 725000>; - regulator-max-microvolt = <1500000>; - regulator-boot-on; - regulator-always-on; - }; - - sm2_reg: sm2 { - regulator-min-microvolt = <3000000>; - regulator-max-microvolt = <4550000>; - regulator-boot-on; - regulator-always-on; - }; - - ldo0_reg: ldo0 { - regulator-name = "PCIE CLK"; - regulator-min-microvolt = <3300000>; - regulator-max-microvolt = <3300000>; - }; - - ldo1_reg: ldo1 { - regulator-min-microvolt = < 725000>; - regulator-max-microvolt = <1500000>; - }; - - ldo2_reg: ldo2 { - regulator-min-microvolt = < 725000>; - regulator-max-microvolt = <1500000>; - }; - - ldo3_reg: ldo3 { - regulator-min-microvolt = <1250000>; - regulator-max-microvolt = <3300000>; - }; - - ldo4_reg: ldo4 { - regulator-min-microvolt = <1700000>; - regulator-max-microvolt = <2475000>; - }; - - ldo5_reg: ldo5 { - regulator-min-microvolt = <1250000>; - regulator-max-microvolt = <3300000>; - }; - - ldo6_reg: ldo6 { - regulator-min-microvolt = <1250000>; - regulator-max-microvolt = <3300000>; - }; - - ldo7_reg: ldo7 { - regulator-min-microvolt = <1250000>; - regulator-max-microvolt = <3300000>; - }; - - ldo8_reg: ldo8 { - regulator-min-microvolt = <1250000>; - regulator-max-microvolt = <3300000>; - }; - - ldo9_reg: ldo9 { - regulator-min-microvolt = <1250000>; - regulator-max-microvolt = <3300000>; - }; - }; - }; -- cgit v1.2.3 From b9205f0837ca91a0bbe6aa9002207656840c1406 Mon Sep 17 00:00:00 2001 From: Wentao Liang Date: Thu, 17 Sep 2026 14:30:52 +0000 Subject: regulator: core: Fix coupled regulators reference leak on removal of_parse_coupled_regulator() returns the coupled regulator with its device reference incremented and regulator_resolve_coupling() stores it in coupling_desc.coupled_rdevs[]. regulator_remove_coupling() clears those pointers without dropping the references, so they are leaked when the couple is torn down. Release the reference of each coupled regulator while removing the coupling. Fixes: d3d64537c339 ("regulator: core: Resolve coupled regulators") Cc: stable@vger.kernel.org Signed-off-by: Wentao Liang Link: https://patch.msgid.link/20260917143052.2156903-1-vulab@iscas.ac.cn Signed-off-by: Mark Brown --- drivers/regulator/core.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/regulator/core.c b/drivers/regulator/core.c index 631b55142809..50fe91b6f267 100644 --- a/drivers/regulator/core.c +++ b/drivers/regulator/core.c @@ -5909,6 +5909,8 @@ static void regulator_remove_coupling(struct regulator_dev *rdev) c_desc->coupled_rdevs[i] = NULL; c_desc->n_resolved--; + + put_device(&c_rdev->dev); } if (coupler && coupler->detach_regulator) { -- cgit v1.2.3 From 59951bd9c6b63d4d98539db96becef729ad60b4a Mon Sep 17 00:00:00 2001 From: Justin Yeh Date: Thu, 3 Sep 2026 14:20:46 +0800 Subject: regulator: core: Export helpers used by regulator couplers regulator_check_voltage(), regulator_check_consumers(), regulator_do_balance_voltage() and regulator_coupler_register() are already declared in include/linux/regulator/coupler.h for regulator coupler implementations to use, but none of them is exported. That limits couplers to being built into the kernel. Export them so that coupler drivers can be built as loadable modules. Signed-off-by: Justin Yeh Link: https://patch.msgid.link/20260903062056.1024263-2-justin.yeh@mediatek.com Signed-off-by: Mark Brown --- drivers/regulator/core.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/drivers/regulator/core.c b/drivers/regulator/core.c index 6a4008f387b5..6b7e613fbaaa 100644 --- a/drivers/regulator/core.c +++ b/drivers/regulator/core.c @@ -462,6 +462,7 @@ int regulator_check_voltage(struct regulator_dev *rdev, return 0; } +EXPORT_SYMBOL_GPL(regulator_check_voltage); /* return 0 if the state is valid */ static int regulator_check_states(suspend_state_t state) @@ -502,6 +503,7 @@ int regulator_check_consumers(struct regulator_dev *rdev, return 0; } +EXPORT_SYMBOL_GPL(regulator_check_consumers); /* current constraint check */ static int regulator_check_current_limit(struct regulator_dev *rdev, @@ -4468,6 +4470,7 @@ int regulator_do_balance_voltage(struct regulator_dev *rdev, out: return ret; } +EXPORT_SYMBOL_GPL(regulator_do_balance_voltage); static int regulator_balance_voltage(struct regulator_dev *rdev, suspend_state_t state) @@ -5797,6 +5800,7 @@ int regulator_coupler_register(struct regulator_coupler *coupler) return 0; } +EXPORT_SYMBOL_GPL(regulator_coupler_register); static struct regulator_coupler * regulator_find_coupler(struct regulator_dev *rdev) -- cgit v1.2.3 From 3fe744bac408579c1d65e2d70b4c04d0c3818008 Mon Sep 17 00:00:00 2001 From: Duje Mihanović Date: Sat, 13 Jun 2026 16:20:55 +0200 Subject: regulator: 88pm886: Add Vbus regulator MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add support for the PMIC's Vbus regulator. This regulator is mandatory for USB OTG support on boards using the PMIC. Reviewed-by: Karel Balej Signed-off-by: Duje Mihanović Link: https://patch.msgid.link/20260613-88pm886-vbus-v2-3-021dfb02c6bb@dujemihanovic.xyz Signed-off-by: Mark Brown --- drivers/regulator/88pm886-regulator.c | 26 ++++++++++++++++++++++++++ include/linux/mfd/88pm886.h | 7 +++++++ 2 files changed, 33 insertions(+) diff --git a/drivers/regulator/88pm886-regulator.c b/drivers/regulator/88pm886-regulator.c index 7328cd1cf265..1961a7968982 100644 --- a/drivers/regulator/88pm886-regulator.c +++ b/drivers/regulator/88pm886-regulator.c @@ -337,6 +337,25 @@ static struct regulator_desc pm886_regulators[] = { }, }; +static const struct linear_range pm886_vbus_volt_ranges[] = { + REGULATOR_LINEAR_RANGE(3750000, 0, 7, 250000) +}; + +static struct regulator_desc pm886_vbus_regulator = { + .name = "vbus", + .regulators_node = "regulators", + .of_match = "vbus", + .ops = &pm886_buck_ops, + .type = REGULATOR_VOLTAGE, + .n_voltages = 8, + .linear_ranges = pm886_vbus_volt_ranges, + .n_linear_ranges = ARRAY_SIZE(pm886_vbus_volt_ranges), + .vsel_reg = PM886_REG_BOOST_CONFIG1, + .vsel_mask = PM886_REG_BOOST_MASK, + .enable_reg = PM886_REG_BATTERY_CONFIG1, + .enable_mask = PM886_REG_VBUS_EN, +}; + static int pm886_regulator_probe(struct platform_device *pdev) { struct pm886_chip *chip = dev_get_drvdata(pdev->dev.parent); @@ -369,6 +388,13 @@ static int pm886_regulator_probe(struct platform_device *pdev) "Failed to register %s\n", rdesc->name); } + rcfg.regmap = chip->regmap_battery; + rdesc = &pm886_vbus_regulator; + rdev = devm_regulator_register(dev, rdesc, &rcfg); + if (IS_ERR(rdev)) + return dev_err_probe(dev, PTR_ERR(rdev), + "Failed to register %s\n", rdesc->name); + return 0; } diff --git a/include/linux/mfd/88pm886.h b/include/linux/mfd/88pm886.h index 2c24dd3032ab..9e96d2cb92f5 100644 --- a/include/linux/mfd/88pm886.h +++ b/include/linux/mfd/88pm886.h @@ -2,6 +2,7 @@ #ifndef __MFD_88PM886_H #define __MFD_88PM886_H +#include #include #include @@ -130,6 +131,12 @@ #define PM886_GPADC_INDEX_TO_BIAS_uA(i) (1 + (i) * 5) /* Battery block register definitions */ +#define PM886_REG_BATTERY_CONFIG1 0x28 +#define PM886_REG_VBUS_EN BIT(7) + +#define PM886_REG_BOOST_CONFIG1 0x6b +#define PM886_REG_BOOST_MASK GENMASK(2, 0) + #define PM886_REG_CLS_CONFIG1 0x71 struct pm886_chip { -- cgit v1.2.3