mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/chenhuacai/linux-loongson
synced 2025-09-01 06:39:05 +00:00
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:
parent
d5cc09847f
commit
6157e62b07
@ -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"));
|
||||
|
@ -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__ */
|
||||
|
Loading…
Reference in New Issue
Block a user