]> git.ipfire.org Git - thirdparty/linux.git/commitdiff
regulator: pca9450: Add restart handler
authorPaul Geurts <paul.geurts@prodrive-technologies.com>
Mon, 5 May 2025 11:59:36 +0000 (13:59 +0200)
committerMark Brown <broonie@kernel.org>
Mon, 12 May 2025 12:09:50 +0000 (21:09 +0900)
When restarting a CPU powered by the PCA9450 power management IC, it
is beneficial to use the PCA9450 to power cycle the CPU and all its
connected peripherals to start up in a known state. The PCA9450 features
a cold start procedure initiated by an I2C command.

Add a restart handler so that the PCA9450 is used to restart the CPU.
The restart handler sends command 0x14 to the SW_RST register,
initiating a cold reset (Power recycle all regulators except LDO1, LDO2
and CLK_32K_OUT)

As the PCA9450 is a PMIC specific for the i.MX8M family CPU, the restart
handler priority is set just slightly higher than imx2_wdt and the PSCI
restart handler. This makes sure this restart handler takes precedence.

Signed-off-by: Paul Geurts <paul.geurts@prodrive-technologies.com>
Link: https://patch.msgid.link/20250505115936.1946891-1-paul.geurts@prodrive-technologies.com
Signed-off-by: Mark Brown <broonie@kernel.org>
drivers/regulator/pca9450-regulator.c
include/linux/regulator/pca9450.h

index a56f3ab754fa92e466b063a68a2fa5dc323e4c4d..14d19a6d665573e56877784c33c3490b8f41d755 100644 (file)
@@ -9,6 +9,7 @@
 #include <linux/i2c.h>
 #include <linux/interrupt.h>
 #include <linux/kernel.h>
+#include <linux/reboot.h>
 #include <linux/module.h>
 #include <linux/of.h>
 #include <linux/platform_device.h>
@@ -33,6 +34,7 @@ struct pca9450 {
        struct device *dev;
        struct regmap *regmap;
        struct gpio_desc *sd_vsel_gpio;
+       struct notifier_block restart_nb;
        enum pca9450_chip_type type;
        unsigned int rcnt;
        int irq;
@@ -965,6 +967,25 @@ static irqreturn_t pca9450_irq_handler(int irq, void *data)
        return IRQ_HANDLED;
 }
 
+static int pca9450_i2c_restart_handler(struct notifier_block *nb,
+                               unsigned long action, void *data)
+{
+       struct pca9450 *pca9450 = container_of(nb, struct pca9450, restart_nb);
+       struct i2c_client *i2c = container_of(pca9450->dev, struct i2c_client, dev);
+
+       dev_dbg(&i2c->dev, "Restarting device..\n");
+       if (i2c_smbus_write_byte_data(i2c, PCA9450_REG_SWRST, SW_RST_COMMAND) == 0) {
+               /* tRESTART is 250ms, so 300 should be enough to make sure it happened */
+               mdelay(300);
+               /* When we get here, the PMIC didn't power cycle for some reason. so warn.*/
+               dev_warn(&i2c->dev, "Device didn't respond to restart command\n");
+       } else {
+               dev_err(&i2c->dev, "Restart command failed\n");
+       }
+
+       return 0;
+}
+
 static int pca9450_i2c_probe(struct i2c_client *i2c)
 {
        enum pca9450_chip_type type = (unsigned int)(uintptr_t)
@@ -1107,6 +1128,12 @@ static int pca9450_i2c_probe(struct i2c_client *i2c)
        pca9450->sd_vsel_fixed_low =
                of_property_read_bool(ldo5->dev.of_node, "nxp,sd-vsel-fixed-low");
 
+       pca9450->restart_nb.notifier_call = pca9450_i2c_restart_handler;
+       pca9450->restart_nb.priority = PCA9450_RESTART_HANDLER_PRIORITY;
+
+       if (register_restart_handler(&pca9450->restart_nb))
+               dev_warn(&i2c->dev, "Failed to register restart handler\n");
+
        dev_info(&i2c->dev, "%s probed.\n",
                type == PCA9450_TYPE_PCA9450A ? "pca9450a" :
                (type == PCA9450_TYPE_PCA9451A ? "pca9451a" : "pca9450bc"));
index b427b5873de1a184504a87502474a2101b58cd52..85b4fecc10d8239a3be97f457f3337d4fd48d274 100644 (file)
@@ -35,6 +35,8 @@ enum {
        PCA9450_DVS_LEVEL_MAX,
 };
 
+#define PCA9450_RESTART_HANDLER_PRIORITY 130
+
 #define PCA9450_BUCK1_VOLTAGE_NUM      0x80
 #define PCA9450_BUCK2_VOLTAGE_NUM      0x80
 #define PCA9450_BUCK3_VOLTAGE_NUM      0x80
@@ -235,4 +237,7 @@ enum {
 #define I2C_LT_ON_RUN                  0x02
 #define I2C_LT_FORCE_ENABLE            0x03
 
+/* PCA9450_REG_SW_RST command */
+#define SW_RST_COMMAND                 0x14
+
 #endif /* __LINUX_REG_PCA9450_H__ */