mfd: rk801: Add support for pwrctrl active pol set and reboot rst

- Don't require pwrctrl dvs if hw compatible version >= 3.
- Auto parse pwrctrl active pol from GPIO_ACTIVE_{HIGH,LOW} flag.
- Reset pmic and soc when system reboot if required.

Signed-off-by: Joseph Chen <chenjh@rock-chips.com>
Change-Id: I29e60c2a717cee5c9d1e3c6e46ee687352d4a1be
This commit is contained in:
Joseph Chen
2025-05-29 11:39:58 +08:00
committed by Tao Huang
parent 0e2ee0944a
commit 1a81f4f634
3 changed files with 132 additions and 65 deletions

View File

@@ -18,6 +18,7 @@
#include <linux/mfd/core.h>
#include <linux/module.h>
#include <linux/of_device.h>
#include <linux/of_gpio.h>
#include <linux/regmap.h>
#include <linux/reboot.h>
#include <linux/syscore_ops.h>
@@ -299,8 +300,7 @@ static const struct mfd_cell rk818s[] = {
static const struct rk808_reg_data rk801_pre_init_reg[] = {
{ RK801_SLEEP_CFG_REG, RK801_SLEEP_FUN_MSK, RK801_NONE_FUN },
{ RK801_SYS_CFG2_REG, RK801_SLEEP_POL_MSK, RK801_SLEEP_ACT_H },
{ RK801_SYS_CFG2_REG, RK801_RST_MSK, RK801_RST_RESTART_REG },
{ RK801_SYS_CFG2_REG, RK801_RST_MSK, RK801_RST_RESTART_REG_RESETB },
{ RK801_INT_CONFIG_REG, RK801_INT_POL_MSK, RK801_INT_ACT_L },
{ RK801_POWER_FPWM_EN_REG, RK801_PLDO_HRDEC_EN, RK801_PLDO_HRDEC_EN },
{ RK801_BUCK_DEBUG5_REG, 0xff, 0x54 },
@@ -850,6 +850,46 @@ static struct i2c_client *rk808_i2c_client;
static struct rk808_reg_data *suspend_reg, *resume_reg;
static int suspend_reg_num, resume_reg_num;
static inline int rk801_act_pol(bool act_low)
{
return act_low ? RK801_SLEEP_ACT_L : RK801_SLEEP_ACT_H;
}
static inline int rk801_inact_pol(bool act_low)
{
return act_low ? RK801_SLEEP_ACT_H : RK801_SLEEP_ACT_L;
}
static void rk801_device_reboot(void)
{
struct rk808 *rk808 = i2c_get_clientdata(rk808_i2c_client);
int ret, act_pol;
if (!rk808->pins || !rk808->pins->reset)
return;
regmap_update_bits(rk808->regmap, RK801_SLEEP_CFG_REG,
RK801_SLEEP_FUN_MSK, RK801_NONE_FUN);
ret = pinctrl_select_state(rk808->pins->p, rk808->pins->reset);
if (ret)
pr_err("failed to pmic-reset pinctrl state, ret=%d\n", ret);
/* raw value ! */
act_pol = gpiod_get_raw_value(rk808->pwrctrl.gpio) ?
RK801_SLEEP_ACT_L : RK801_SLEEP_ACT_H;
regmap_update_bits(rk808->regmap, RK801_SYS_CFG2_REG,
RK801_SLEEP_POL_MSK, act_pol);
/* pmic rst func: register + 5ms-npor-signal */
regmap_update_bits(rk808->regmap, RK801_SYS_CFG2_REG,
RK801_RST_MSK, RK801_RST_RESTART_REG_RESETB);
regmap_update_bits(rk808->regmap, RK801_SLEEP_CFG_REG,
RK801_SLEEP_FUN_MSK, RK801_RESET_FUN);
dev_info(&rk808_i2c_client->dev, "rk801 system reboot ready\n");
}
static int rk801_device_shutdown_prepare(struct sys_off_data *data)
{
int ret = 0;
@@ -859,7 +899,8 @@ static int rk801_device_shutdown_prepare(struct sys_off_data *data)
return -1;
ret = regmap_update_bits(rk808->regmap, RK801_SYS_CFG2_REG,
RK801_SLEEP_POL_MSK, RK801_SLEEP_ACT_H);
RK801_SLEEP_POL_MSK,
rk801_act_pol(rk808->pwrctrl.act_low));
if (ret < 0)
return ret;
@@ -966,6 +1007,7 @@ static void rk8xx_device_shutdown(void)
/* Called in syscore shutdown */
static void (*pm_shutdown)(void);
static void (*pm_reboot)(void);
static void rk8xx_syscore_shutdown(void)
{
@@ -1017,6 +1059,11 @@ static void rk8xx_syscore_shutdown(void)
while (1)
;
}
} else if (system_state == SYSTEM_RESTART) {
if (pm_reboot) {
dev_info(&rk808_i2c_client->dev, "System reboot\n");
pm_reboot();
}
}
}
@@ -1088,6 +1135,42 @@ out:
return count;
}
static int rk801_pinctrl_init(struct device *dev, struct rk808 *rk808)
{
struct gpio_desc *gpio;
/* init soc-pwrctrl inactive pol (GPIOD_OUT_LOW is logic value) */
gpio = devm_gpiod_get_optional(dev, "pwrctrl", GPIOD_OUT_LOW);
if (IS_ERR_OR_NULL(gpio)) {
dev_err(dev, "there is no pwrctrl gpio!\n");
return -EINVAL;
}
rk808->pwrctrl.gpio = gpio;
rk808->pwrctrl.act_low = gpiod_is_active_low(gpio);
/* init pmic-pwrctrl active pol */
regmap_update_bits(rk808->regmap, RK801_SYS_CFG2_REG,
RK801_SLEEP_POL_MSK,
rk801_act_pol(rk808->pwrctrl.act_low));
/* pinctrl */
rk808->pins = devm_kzalloc(dev, sizeof(struct rk808_pin_info), GFP_KERNEL);
if (!rk808->pins)
return -ENOMEM;
rk808->pins->p = devm_pinctrl_get(dev);
if (IS_ERR(rk808->pins->p)) {
dev_err(dev, "no pinctrl settings\n");
return -EINVAL;
}
rk808->pins->reset = pinctrl_lookup_state(rk808->pins->p, "pmic-reset");
if (IS_ERR(rk808->pins->reset))
rk808->pins->reset = NULL;
return 0;
}
static int rk817_pinctrl_init(struct device *dev, struct rk808 *rk808)
{
int ret;
@@ -1327,6 +1410,7 @@ static int rk808_probe(struct i2c_client *client,
struct device *dev) = NULL;
int (*pinctrl_init)(struct device *dev, struct rk808 *rk808) = NULL;
void (*device_shutdown_fn)(void) = NULL;
void (*device_reboot_fn)(void) = NULL;
rk808 = devm_kzalloc(&client->dev, sizeof(*rk808), GFP_KERNEL);
if (!rk808)
@@ -1364,6 +1448,7 @@ static int rk808_probe(struct i2c_client *client,
switch (rk808->variant) {
case RK801_ID:
rk808->pwrctrl.req_pwrctrl_dvs = (lsb & 0x0f) < 3;
rk808->regmap_cfg = &rk801_regmap_config;
rk808->regmap_irq_chip = &rk801_irq_chip;
pre_init_reg = rk801_pre_init_reg;
@@ -1373,6 +1458,8 @@ static int rk808_probe(struct i2c_client *client,
on_source = RK801_ON_SOURCE_REG;
off_source = RK801_OFF_SOURCE_REG;
device_shutdown_fn = rk8xx_device_shutdown;
device_reboot_fn = rk801_device_reboot;
pinctrl_init = rk801_pinctrl_init;
break;
case RK805_ID:
rk808->regmap_cfg = &rk805_regmap_config;
@@ -1577,6 +1664,7 @@ static int rk808_probe(struct i2c_client *client,
register_syscore_ops(&rk808_syscore_ops);
/* power off system in the syscore shutdown ! */
pm_shutdown = device_shutdown_fn;
pm_reboot = device_reboot_fn;
}
}
@@ -1637,7 +1725,8 @@ static int __maybe_unused rk8xx_suspend(struct device *dev)
switch (rk808->variant) {
case RK801_ID:
ret = regmap_update_bits(rk808->regmap, RK801_SYS_CFG2_REG,
RK801_SLEEP_POL_MSK, RK801_SLEEP_ACT_H);
RK801_SLEEP_POL_MSK,
rk801_act_pol(rk808->pwrctrl.act_low));
if (ret < 0)
return ret;

View File

@@ -256,29 +256,34 @@ static int rk801_set_voltage_sel(struct regulator_dev *rdev, unsigned sel)
{
struct rk801_regulator_data *pdata = rdev_get_drvdata(rdev);
struct gpio_desc *gpio = pdata->pwrctrl_gpio;
unsigned int reg0 = rdev->desc->vsel_reg;
unsigned int reg1 = rdev->desc->vsel_reg + RK801_SLP_REG_OFFSET;
unsigned int reg;
int ret, gpio_level;
unsigned int reg_normal = rdev->desc->vsel_reg;
unsigned int reg_sleep = rdev->desc->vsel_reg + RK801_SLP_REG_OFFSET;
unsigned int reg_target;
int act_level; /* logic value */
int ret;
if (pdata->req_pwrctrl_dvs) {
gpio_level = gpiod_get_value(gpio);
reg = (gpio_level == 1) ? reg0 : reg1;
/*
* act_level=1: active on reg_sleep now -> target: reg_normal
* act_level=0: inactive on reg_normal now -> target: reg_sleep
*/
act_level = gpiod_get_value(gpio);
reg_target = act_level ? reg_normal : reg_sleep;
sel <<= ffs(rdev->desc->vsel_mask) - 1;
ret = regmap_update_bits(rdev->regmap, reg, rdev->desc->vsel_mask, sel);
ret = regmap_update_bits(rdev->regmap, reg_target, rdev->desc->vsel_mask, sel);
if (ret)
return ret;
udelay(40); /* hw sync */
gpiod_set_value(gpio, !gpio_level);
gpiod_set_value(gpio, !act_level);
if (reg == reg0)
ret = regmap_update_bits(rdev->regmap, reg1,
if (reg_target == reg_normal)
ret = regmap_update_bits(rdev->regmap, reg_sleep,
rdev->desc->vsel_mask, sel);
else
ret = regmap_update_bits(rdev->regmap, reg0,
ret = regmap_update_bits(rdev->regmap, reg_normal,
rdev->desc->vsel_mask, sel);
} else {
ret = regulator_set_voltage_sel_regmap(rdev, sel);
@@ -416,38 +421,6 @@ static const struct regulator_desc rk801_reg[] = {
ENABLE_MASK(2), ENABLE_VAL(2), DISABLE_VAL(2), 400),
};
static int rk801_regulator_dt_parse_pdata(struct device *dev,
struct device *client_dev,
struct regmap *map,
struct rk801_regulator_data *pdata)
{
struct device_node *np;
int ret = 0;
np = of_get_child_by_name(client_dev->of_node, "regulators");
if (!np)
return -ENXIO;
if (pdata->req_pwrctrl_dvs) {
pdata->pwrctrl_gpio = devm_gpiod_get_optional(client_dev,
"pwrctrl", GPIOD_OUT_LOW);
if (IS_ERR(pdata->pwrctrl_gpio)) {
ret = PTR_ERR(pdata->pwrctrl_gpio);
dev_err(dev, "failed to get pwrctrl gpio! ret=%d\n", ret);
goto dt_parse_end;
}
if (!pdata->pwrctrl_gpio) {
dev_err(dev, "there is no pwrctrl gpio!\n");
ret = -EINVAL;
}
}
dt_parse_end:
of_node_put(np);
return ret;
}
static int rk801_regulator_init(struct device *dev)
{
struct rk808 *rk808 = dev_get_drvdata(dev->parent);
@@ -459,12 +432,18 @@ static int rk801_regulator_init(struct device *dev)
{ RK801_LDO1_ON_VSEL_REG, RK801_LDO1_SLP_VSEL_REG },
{ RK801_LDO2_ON_VSEL_REG, RK801_LDO2_SLP_VSEL_REG },
};
uint val, en0, en1;
int i, ret;
uint act_pol, en0, en1;
int i, ret, val;
if (!pdata->req_pwrctrl_dvs)
return 0;
/* set pmic-pwrctrl active pol and use sleep function */
act_pol = rk808->pwrctrl.act_low ?
RK801_SLEEP_ACT_L : RK801_SLEEP_ACT_H;
/* pwrctrl gpio active high and use sleep function */
ret = regmap_update_bits(rk808->regmap, RK801_SYS_CFG2_REG,
RK801_SLEEP_POL_MSK, RK801_SLEEP_ACT_H);
RK801_SLEEP_POL_MSK, act_pol);
if (ret)
return ret;
@@ -562,7 +541,7 @@ static int rk801_regulator_suspend_late(struct device *dev)
if (!pdata->req_pwrctrl_dvs)
return 0;
/* set pwrctrl pin low */
/* set soc-pwrctrl inactive (0:inactive) */
gpiod_set_value(gpio, 0);
udelay(40);
@@ -595,26 +574,18 @@ static int rk801_regulator_probe(struct platform_device *pdev)
struct regulator_config config = {};
struct regulator_dev *rk801_rdev;
struct rk801_regulator_data *pdata;
int id_lsb, i, ret;
int i, ret;
pdata = devm_kzalloc(&pdev->dev, sizeof(*pdata), GFP_KERNEL);
if (!pdata)
return -ENOMEM;
ret = regmap_read(rk808->regmap, RK801_ID_LSB, &id_lsb);
if (ret)
return ret;
pdata->req_pwrctrl_dvs = (id_lsb & 0x0f) < 4;
dev_info(&pdev->dev, "req pwrctrl dvs: %d\n", pdata->req_pwrctrl_dvs);
ret = rk801_regulator_dt_parse_pdata(&pdev->dev, &client->dev,
rk808->regmap, pdata);
if (ret < 0)
return ret;
pdata->req_pwrctrl_dvs = rk808->pwrctrl.req_pwrctrl_dvs;
pdata->pwrctrl_gpio = rk808->pwrctrl.gpio;
dev_info(&pdev->dev, "req pwrctrl dvs: %d, act: %s\n",
pdata->req_pwrctrl_dvs, rk808->pwrctrl.act_low ? "low" : "high");
platform_set_drvdata(pdev, pdata);
config.dev = &client->dev;
config.driver_data = pdata;
config.regmap = rk808->regmap;

View File

@@ -1350,6 +1350,12 @@ struct rk808_pin_info {
struct pinctrl_state *sleep;
};
struct rk808_pwrctrl {
struct gpio_desc *gpio;
bool req_pwrctrl_dvs;
bool act_low;
};
struct rk808 {
struct i2c_client *i2c;
struct regmap_irq_chip_data *irq_data;
@@ -1360,5 +1366,6 @@ struct rk808 {
const struct regmap_irq_chip *regmap_irq_chip;
void (*pm_pwroff_prep_fn)(void);
struct rk808_pin_info *pins;
struct rk808_pwrctrl pwrctrl;
};
#endif /* __LINUX_REGULATOR_RK808_H */