]> git.ipfire.org Git - thirdparty/linux.git/commitdiff
regulator: pca9450: Add support for setting debounce settings
authorMartijn de Gouw <martijn.de.gouw@prodrive-technologies.com>
Mon, 17 Nov 2025 20:22:14 +0000 (21:22 +0100)
committerMark Brown <broonie@kernel.org>
Tue, 18 Nov 2025 18:55:22 +0000 (18:55 +0000)
Make the different debounce timers configurable from the devicetree.
Depending on the board design, these have to be set different than the
default register values.

Signed-off-by: Martijn de Gouw <martijn.de.gouw@prodrive-technologies.com>
Link: https://patch.msgid.link/20251117202215.1936139-2-martijn.de.gouw@prodrive-technologies.com
Signed-off-by: Mark Brown <broonie@kernel.org>
drivers/regulator/pca9450-regulator.c
include/linux/regulator/pca9450.h

index 247f12df8974e9816c724afda1c4f5c65dcdf779..93154c9c98dd663b85d97e239dd31090c1522a63 100644 (file)
@@ -1147,6 +1147,143 @@ static int pca9450_i2c_restart_handler(struct sys_off_data *data)
        return 0;
 }
 
+static int pca9450_of_init(struct pca9450 *pca9450)
+{
+       struct i2c_client *i2c = container_of(pca9450->dev, struct i2c_client, dev);
+       int ret;
+       unsigned int val;
+       unsigned int reset_ctrl;
+       unsigned int rstb_deb_ctrl;
+       unsigned int t_on_deb, t_off_deb;
+       unsigned int t_on_step, t_off_step;
+       unsigned int t_restart;
+
+       if (of_property_read_bool(i2c->dev.of_node, "nxp,wdog_b-warm-reset"))
+               reset_ctrl = WDOG_B_CFG_WARM;
+       else
+               reset_ctrl = WDOG_B_CFG_COLD_LDO12;
+
+       /* Set reset behavior on assertion of WDOG_B signal */
+       ret = regmap_update_bits(pca9450->regmap, PCA9450_REG_RESET_CTRL,
+                                WDOG_B_CFG_MASK, reset_ctrl);
+       if (ret)
+               return dev_err_probe(&i2c->dev, ret, "Failed to set WDOG_B reset behavior\n");
+
+       ret = of_property_read_u32(i2c->dev.of_node, "npx,pmic-rst-b-debounce-ms", &val);
+       if (ret == -EINVAL)
+               rstb_deb_ctrl = T_PMIC_RST_DEB_50MS;
+       else if (ret)
+               return ret;
+       else {
+               switch (val) {
+               case 10: rstb_deb_ctrl = T_PMIC_RST_DEB_10MS; break;
+               case 50: rstb_deb_ctrl = T_PMIC_RST_DEB_50MS; break;
+               case 100: rstb_deb_ctrl = T_PMIC_RST_DEB_100MS; break;
+               case 500: rstb_deb_ctrl = T_PMIC_RST_DEB_500MS; break;
+               case 1000: rstb_deb_ctrl = T_PMIC_RST_DEB_1S; break;
+               case 2000: rstb_deb_ctrl = T_PMIC_RST_DEB_2S; break;
+               case 4000: rstb_deb_ctrl = T_PMIC_RST_DEB_4S; break;
+               case 8000: rstb_deb_ctrl = T_PMIC_RST_DEB_8S; break;
+               default: return -EINVAL;
+               }
+       }
+       ret = regmap_update_bits(pca9450->regmap, PCA9450_REG_RESET_CTRL,
+                                T_PMIC_RST_DEB_MASK, rstb_deb_ctrl);
+       if (ret)
+               return dev_err_probe(&i2c->dev, ret, "Failed to set PMIC_RST_B debounce time\n");
+
+       ret = of_property_read_u32(i2c->dev.of_node, "nxp,pmic-on-req-on-debounce-us", &val);
+       if (ret == -EINVAL)
+               t_on_deb = T_ON_DEB_20MS;
+       else if (ret)
+               return ret;
+       else {
+               switch (val) {
+               case 120: t_on_deb = T_ON_DEB_120US; break;
+               case 20000: t_on_deb = T_ON_DEB_20MS; break;
+               case 100000: t_on_deb = T_ON_DEB_100MS; break;
+               case 750000: t_on_deb = T_ON_DEB_750MS; break;
+               default: return -EINVAL;
+               }
+       }
+
+       ret = of_property_read_u32(i2c->dev.of_node, "nxp,pmic-on-req-off-debounce-us", &val);
+       if (ret == -EINVAL)
+               t_off_deb = T_OFF_DEB_120US;
+       else if (ret)
+               return ret;
+       else {
+               switch (val) {
+               case 120: t_off_deb = T_OFF_DEB_120US; break;
+               case 2000: t_off_deb = T_OFF_DEB_2MS; break;
+               default: return -EINVAL;
+               }
+       }
+
+       ret = of_property_read_u32(i2c->dev.of_node, "nxp,power-on-step-ms", &val);
+       if (ret == -EINVAL)
+               t_on_step = T_ON_STEP_2MS;
+       else if (ret)
+               return ret;
+       else {
+               switch (val) {
+               case 1: t_on_step = T_ON_STEP_1MS; break;
+               case 2: t_on_step = T_ON_STEP_2MS; break;
+               case 4: t_on_step = T_ON_STEP_4MS; break;
+               case 8: t_on_step = T_ON_STEP_8MS; break;
+               default: return -EINVAL;
+               }
+       }
+
+       ret = of_property_read_u32(i2c->dev.of_node, "nxp,power-down-step-ms", &val);
+       if (ret == -EINVAL)
+               t_off_step = T_OFF_STEP_8MS;
+       else if (ret)
+               return ret;
+       else {
+               switch (val) {
+               case 2: t_off_step = T_OFF_STEP_2MS; break;
+               case 4: t_off_step = T_OFF_STEP_4MS; break;
+               case 8: t_off_step = T_OFF_STEP_8MS; break;
+               case 16: t_off_step = T_OFF_STEP_16MS; break;
+               default: return -EINVAL;
+               }
+       }
+
+       ret = of_property_read_u32(i2c->dev.of_node, "nxp,restart-ms", &val);
+       if (ret == -EINVAL)
+               t_restart = T_RESTART_250MS;
+       else if (ret)
+               return ret;
+       else {
+               switch (val) {
+               case 250: t_restart = T_RESTART_250MS; break;
+               case 500: t_restart = T_RESTART_500MS; break;
+               default: return -EINVAL;
+               }
+       }
+
+       ret = regmap_update_bits(pca9450->regmap, PCA9450_REG_PWRCTRL,
+                                T_ON_DEB_MASK | T_OFF_DEB_MASK | T_ON_STEP_MASK |
+                                T_OFF_STEP_MASK | T_RESTART_MASK,
+                                t_on_deb | t_off_deb | t_on_step |
+                                t_off_step | t_restart);
+       if (ret)
+               return dev_err_probe(&i2c->dev, ret,
+                                    "Failed to set PWR_CTRL debounce configuration\n");
+
+       if (of_property_read_bool(i2c->dev.of_node, "nxp,i2c-lt-enable")) {
+               /* Enable I2C Level Translator */
+               ret = regmap_update_bits(pca9450->regmap, PCA9450_REG_CONFIG2,
+                                        I2C_LT_MASK, I2C_LT_ON_STANDBY_RUN);
+               if (ret)
+                       return dev_err_probe(&i2c->dev, ret,
+                                            "Failed to enable I2C level translator\n");
+       }
+
+       return 0;
+}
+
 static int pca9450_i2c_probe(struct i2c_client *i2c)
 {
        enum pca9450_chip_type type = (unsigned int)(uintptr_t)
@@ -1156,7 +1293,6 @@ static int pca9450_i2c_probe(struct i2c_client *i2c)
        struct regulator_dev *ldo5;
        struct pca9450 *pca9450;
        unsigned int device_id, i;
-       unsigned int reset_ctrl;
        int ret;
 
        pca9450 = devm_kzalloc(&i2c->dev, sizeof(struct pca9450), GFP_KERNEL);
@@ -1254,25 +1390,9 @@ static int pca9450_i2c_probe(struct i2c_client *i2c)
        if (ret)
                return dev_err_probe(&i2c->dev, ret,  "Failed to clear PRESET_EN bit\n");
 
-       if (of_property_read_bool(i2c->dev.of_node, "nxp,wdog_b-warm-reset"))
-               reset_ctrl = WDOG_B_CFG_WARM;
-       else
-               reset_ctrl = WDOG_B_CFG_COLD_LDO12;
-
-       /* Set reset behavior on assertion of WDOG_B signal */
-       ret = regmap_update_bits(pca9450->regmap, PCA9450_REG_RESET_CTRL,
-                                WDOG_B_CFG_MASK, reset_ctrl);
+       ret = pca9450_of_init(pca9450);
        if (ret)
-               return dev_err_probe(&i2c->dev, ret, "Failed to set WDOG_B reset behavior\n");
-
-       if (of_property_read_bool(i2c->dev.of_node, "nxp,i2c-lt-enable")) {
-               /* Enable I2C Level Translator */
-               ret = regmap_update_bits(pca9450->regmap, PCA9450_REG_CONFIG2,
-                                        I2C_LT_MASK, I2C_LT_ON_STANDBY_RUN);
-               if (ret)
-                       return dev_err_probe(&i2c->dev, ret,
-                                            "Failed to enable I2C level translator\n");
-       }
+               return dev_err_probe(&i2c->dev, ret, "Unable to parse OF data\n");
 
        /*
         * For LDO5 we need to be able to check the status of the SD_VSEL input in
index 85b4fecc10d8239a3be97f457f3337d4fd48d274..0df8b3c48082f9614e75dadf15ff309ae4d80af0 100644 (file)
@@ -223,12 +223,44 @@ enum {
 #define IRQ_THERM_105                  0x02
 #define IRQ_THERM_125                  0x01
 
+/* PCA9450_REG_PWRCTRL bits */
+#define T_ON_DEB_MASK                  0xC0
+#define T_ON_DEB_120US                 (0 << 6)
+#define T_ON_DEB_20MS                  (1 << 6)
+#define T_ON_DEB_100MS                 (2 << 6)
+#define T_ON_DEB_750MS                 (3 << 6)
+#define T_OFF_DEB_MASK                 0x20
+#define T_OFF_DEB_120US                        (0 << 5)
+#define T_OFF_DEB_2MS                  (1 << 5)
+#define T_ON_STEP_MASK                 0x18
+#define T_ON_STEP_1MS                  (0 << 3)
+#define T_ON_STEP_2MS                  (1 << 3)
+#define T_ON_STEP_4MS                  (2 << 3)
+#define T_ON_STEP_8MS                  (3 << 3)
+#define T_OFF_STEP_MASK                        0x06
+#define T_OFF_STEP_2MS                 (0 << 1)
+#define T_OFF_STEP_4MS                 (1 << 1)
+#define T_OFF_STEP_8MS                 (2 << 1)
+#define T_OFF_STEP_16MS                        (3 << 1)
+#define T_RESTART_MASK                 0x01
+#define T_RESTART_250MS                        0
+#define T_RESTART_500MS                        1
+
 /* PCA9450_REG_RESET_CTRL bits */
 #define WDOG_B_CFG_MASK                        0xC0
 #define WDOG_B_CFG_NONE                        0x00
 #define WDOG_B_CFG_WARM                        0x40
 #define WDOG_B_CFG_COLD_LDO12          0x80
 #define WDOG_B_CFG_COLD                        0xC0
+#define T_PMIC_RST_DEB_MASK            0x07
+#define T_PMIC_RST_DEB_10MS            0x00
+#define T_PMIC_RST_DEB_50MS            0x01
+#define T_PMIC_RST_DEB_100MS           0x02
+#define T_PMIC_RST_DEB_500MS           0x03
+#define T_PMIC_RST_DEB_1S              0x04
+#define T_PMIC_RST_DEB_2S              0x05
+#define T_PMIC_RST_DEB_4S              0x06
+#define T_PMIC_RST_DEB_8S              0x07
 
 /* PCA9450_REG_CONFIG2 bits */
 #define I2C_LT_MASK                    0x03