From 1a81f4f6344f7cd4203be508150daeedc00fbedb Mon Sep 17 00:00:00 2001 From: Joseph Chen Date: Thu, 29 May 2025 11:39:58 +0800 Subject: [PATCH] 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 Change-Id: I29e60c2a717cee5c9d1e3c6e46ee687352d4a1be --- drivers/mfd/rk808.c | 97 +++++++++++++++++++++++++++-- drivers/regulator/rk801-regulator.c | 93 ++++++++++----------------- include/linux/mfd/rk808.h | 7 +++ 3 files changed, 132 insertions(+), 65 deletions(-) diff --git a/drivers/mfd/rk808.c b/drivers/mfd/rk808.c index 09198cba45eb..3e9094c8cc0e 100644 --- a/drivers/mfd/rk808.c +++ b/drivers/mfd/rk808.c @@ -18,6 +18,7 @@ #include #include #include +#include #include #include #include @@ -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; diff --git a/drivers/regulator/rk801-regulator.c b/drivers/regulator/rk801-regulator.c index 489b5eba0305..ae8be3e65d33 100644 --- a/drivers/regulator/rk801-regulator.c +++ b/drivers/regulator/rk801-regulator.c @@ -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; diff --git a/include/linux/mfd/rk808.h b/include/linux/mfd/rk808.h index 565d8ec8edd7..c374be50e1f2 100644 --- a/include/linux/mfd/rk808.h +++ b/include/linux/mfd/rk808.h @@ -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 */