The family of PCA9450 PMICs have the ability to perform system resets. Restarting via PMIC is preferred method of restarting the system as all the peripherals are brought to a know state after a power-cycle. The PCA9450 features a cold restart procedure which is initiated by an I2C command 0x14 to the SW_RST register.
Support in Linux for restarting via PCA9450 PMIC has been added by Linux commit 6157e62b07d9 ("regulator: pca9450: Add restart handler"). Now add support for it also in the U-Boot via sysreset framework. Signed-off-by: Primoz Fiser <primoz.fi...@norik.com> Reviewed-by: Paul Geurts <paul.geu...@prodrive-technologies.com> --- Changes in v3: - rebase custodians/u-boot-mmc branch: next - add Reviewed-by: tags Link to v2: https://lore.kernel.org/all/20250814094741.4177431-1-primoz.fi...@norik.com/ drivers/power/pmic/pca9450.c | 44 ++++++++++++++++++++++++++++++++++++ include/power/pca9450.h | 2 ++ 2 files changed, 46 insertions(+) diff --git a/drivers/power/pmic/pca9450.c b/drivers/power/pmic/pca9450.c index 0e3d14abf154..8b98c2239e13 100644 --- a/drivers/power/pmic/pca9450.c +++ b/drivers/power/pmic/pca9450.c @@ -6,13 +6,17 @@ #include <fdtdec.h> #include <errno.h> #include <dm.h> +#include <dm/device_compat.h> +#include <dm/lists.h> #include <i2c.h> #include <log.h> #include <asm/global_data.h> +#include <linux/delay.h> #include <linux/printk.h> #include <power/pmic.h> #include <power/regulator.h> #include <power/pca9450.h> +#include <sysreset.h> DECLARE_GLOBAL_DATA_PTR; @@ -79,6 +83,15 @@ static int pca9450_bind(struct udevice *dev) static int pca9450_probe(struct udevice *dev) { unsigned int reset_ctrl; + int ret; + + if (CONFIG_IS_ENABLED(SYSRESET)) { + ret = device_bind_driver_to_node(dev, "pca9450_sysreset", + "pca9450_sysreset", + dev_ofnode(dev), NULL); + if (ret) + return ret; + } if (ofnode_read_bool(dev_ofnode(dev), "nxp,wdog_b-warm-reset")) reset_ctrl = PCA9450_PMIC_RESET_WDOG_B_CFG_WARM; @@ -112,3 +125,34 @@ U_BOOT_DRIVER(pmic_pca9450) = { .probe = pca9450_probe, .ops = &pca9450_ops, }; + +#ifdef CONFIG_SYSRESET +static int pca9450_sysreset_request(struct udevice *dev, enum sysreset_t type) +{ + u8 cmd = PCA9450_SW_RST_COLD_RST; + + if (type != SYSRESET_COLD) + return -EPROTONOSUPPORT; + + if (pmic_write(dev->parent, PCA9450_SW_RST, &cmd, 1)) { + dev_err(dev, "reset command failed\n"); + } else { + /* tRESTART is 250ms, delay 300ms just to be sure */ + mdelay(300); + /* Should not get here, warn if we do */ + dev_warn(dev, "didn't respond to reset command\n"); + } + + return -EINPROGRESS; +} + +static struct sysreset_ops pca9450_sysreset_ops = { + .request = pca9450_sysreset_request, +}; + +U_BOOT_DRIVER(pca9450_sysreset) = { + .name = "pca9450_sysreset", + .id = UCLASS_SYSRESET, + .ops = &pca9450_sysreset_ops, +}; +#endif /* CONFIG_SYSRESET */ diff --git a/include/power/pca9450.h b/include/power/pca9450.h index e5ab09fb8c83..9119ef793b1f 100644 --- a/include/power/pca9450.h +++ b/include/power/pca9450.h @@ -75,4 +75,6 @@ enum { #define PCA9450_PMIC_RESET_WDOG_B_CFG_WARM 0x40 #define PCA9450_PMIC_RESET_WDOG_B_CFG_COLD_LDO12 0x80 +#define PCA9450_SW_RST_COLD_RST 0x14 + #endif -- 2.34.1