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 <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>
This commit is contained in:
Paul Geurts 2025-05-05 13:59:36 +02:00 committed by Mark Brown
parent d5cc09847f
commit 6157e62b07
No known key found for this signature in database
GPG Key ID: 24D68B725D5487D0
2 changed files with 32 additions and 0 deletions

View 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"));

View 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__ */