mirror of
https://github.com/hardkernel/linux.git
synced 2026-06-05 18:41:58 +09:00
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:
@@ -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;
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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 */
|
||||
|
||||
Reference in New Issue
Block a user