Unverified Commit 6157e62b authored by Paul Geurts's avatar Paul Geurts Committed by Mark Brown
Browse files

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: default avatarPaul Geurts <paul.geurts@prodrive-technologies.com>
Link: https://patch.msgid.link/20250505115936.1946891-1-paul.geurts@prodrive-technologies.com


Signed-off-by: default avatarMark Brown <broonie@kernel.org>
parent d5cc0984
Loading
Loading
Loading
Loading
+27 −0
Original line number Diff line number Diff line
@@ -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"));
+5 −0
Original line number Diff line number Diff line
@@ -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__ */