From: Paul Geurts Date: Mon, 5 May 2025 11:59:36 +0000 (+0200) Subject: regulator: pca9450: Add restart handler X-Git-Tag: v6.16-rc1~167^2~4 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=6157e62b07d9331cc1d4d9d525dab33d45b0e83c;p=thirdparty%2Flinux.git regulator: pca9450: Add restart handler 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 Link: https://patch.msgid.link/20250505115936.1946891-1-paul.geurts@prodrive-technologies.com Signed-off-by: Mark Brown --- diff --git a/drivers/regulator/pca9450-regulator.c b/drivers/regulator/pca9450-regulator.c index a56f3ab754fa9..14d19a6d66557 100644 --- a/drivers/regulator/pca9450-regulator.c +++ b/drivers/regulator/pca9450-regulator.c @@ -9,6 +9,7 @@ #include #include #include +#include #include #include #include @@ -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")); diff --git a/include/linux/regulator/pca9450.h b/include/linux/regulator/pca9450.h index b427b5873de1a..85b4fecc10d82 100644 --- a/include/linux/regulator/pca9450.h +++ b/include/linux/regulator/pca9450.h @@ -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__ */