From cfe40315e8180c2b4fd409aa3242082cbdeedd9c Mon Sep 17 00:00:00 2001 From: Tony Xie Date: Wed, 7 Feb 2018 15:05:03 +0800 Subject: [PATCH] pinctrl: support pinctrl driver for the RK817&RK809 PMIC Change-Id: I9a24ee0d9266a000d582f8ffff8b0c872e3a0769 Signed-off-by: Tony Xie --- drivers/mfd/rk808.c | 202 +++++++++++++++++++++++++++ drivers/pinctrl/pinctrl-rk805.c | 232 +++++++++++++++++++++++++++++--- include/linux/mfd/rk808.h | 8 ++ 3 files changed, 424 insertions(+), 18 deletions(-) diff --git a/drivers/mfd/rk808.c b/drivers/mfd/rk808.c index 096b22adedb4..dc0919ea61f2 100644 --- a/drivers/mfd/rk808.c +++ b/drivers/mfd/rk808.c @@ -28,6 +28,8 @@ #include #include #include +#include +#include struct rk808_reg_data { int addr; @@ -777,6 +779,50 @@ static void rk816_device_shutdown(void) dev_err(&rk808_i2c_client->dev, "Failed to shutdown device!\n"); } +static void rk817_shutdown_prepare(void) +{ + int ret; + struct rk808 *rk808 = i2c_get_clientdata(rk808_i2c_client); + + /* close rtc int when power off */ + regmap_update_bits(rk808->regmap, + RK817_INT_STS_MSK_REG1, + (0x3 << 5), (0x3 << 5)); + regmap_update_bits(rk808->regmap, + RK817_RTC_INT_REG, + (0x3 << 2), (0x0 << 2)); + + if (rk808->pins->p && rk808->pins->power_off) { + ret = regmap_update_bits(rk808->regmap, + RK817_SYS_CFG(3), + RK817_SLPPIN_FUNC_MSK, + SLPPIN_NULL_FUN); + if (ret) { + pr_err("shutdown: config SLPPIN_NULL_FUN error!\n"); + } + + ret = regmap_update_bits(rk808->regmap, + RK817_SYS_CFG(3), + RK817_SLPPOL_MSK, + RK817_SLPPOL_H); + if (ret) { + pr_err("shutdown: config RK817_SLPPOL_H error!\n"); + } + ret = pinctrl_select_state(rk808->pins->p, + rk808->pins->power_off); + if (ret) + pr_info("%s:failed to activate pwroff state\n", + __func__); + } + + /* pmic sleep shutdown function */ + ret = regmap_update_bits(rk808->regmap, + RK817_SYS_CFG(3), + RK817_SLPPIN_FUNC_MSK, SLPPIN_DN_FUN); + if (ret) + dev_err(&rk808_i2c_client->dev, "Failed to shutdown device!\n"); +} + static void rk818_device_shutdown(void) { int ret; @@ -895,6 +941,131 @@ out: return count; } +static int rk817_pinctrl_init(struct device *dev, struct rk808 *rk808) +{ + int ret; + struct platform_device *pinctrl_dev; + struct pinctrl_state *default_st; + + pinctrl_dev = platform_device_alloc("rk805-pinctrl", -1); + if (!pinctrl_dev) { + dev_err(dev, "Alloc pinctrl dev failed!\n"); + return -ENOMEM; + } + + pinctrl_dev->dev.parent = dev; + + ret = platform_device_add(pinctrl_dev); + + if (ret) { + platform_device_put(pinctrl_dev); + dev_err(dev, "Add rk805-pinctrl dev failed!\n"); + return ret; + } + if (dev->pins && !IS_ERR(dev->pins->p)) { + dev_info(dev, "had get a pinctrl!\n"); + return 0; + } + + 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)) { + rk808->pins->p = NULL; + dev_err(dev, "no pinctrl handle\n"); + return 0; + } + + default_st = pinctrl_lookup_state(rk808->pins->p, + PINCTRL_STATE_DEFAULT); + + if (IS_ERR(default_st)) { + dev_dbg(dev, "no default pinctrl state\n"); + return -EINVAL; + } + + ret = pinctrl_select_state(rk808->pins->p, default_st); + if (ret) { + dev_dbg(dev, "failed to activate default pinctrl state\n"); + return -EINVAL; + } + + rk808->pins->power_off = pinctrl_lookup_state(rk808->pins->p, + "pmic-power-off"); + if (IS_ERR(rk808->pins->power_off)) { + rk808->pins->power_off = NULL; + dev_dbg(dev, "no power-off pinctrl state\n"); + } + + rk808->pins->sleep = pinctrl_lookup_state(rk808->pins->p, + "pmic-sleep"); + if (IS_ERR(rk808->pins->sleep)) { + rk808->pins->sleep = NULL; + dev_dbg(dev, "no sleep-setting state\n"); + } + + rk808->pins->reset = pinctrl_lookup_state(rk808->pins->p, + "pmic-reset"); + if (IS_ERR(rk808->pins->reset)) { + rk808->pins->reset = NULL; + dev_dbg(dev, "no reset-setting pinctrl state\n"); + return 0; + } + + ret = regmap_update_bits(rk808->regmap, + RK817_SYS_CFG(3), + RK817_SLPPOL_MSK, + RK817_SLPPOL_L); + if (ret) { + dev_err(dev, "init: config RK817_SLPPOL_L error!\n"); + return -1; + } + + ret = pinctrl_select_state(rk808->pins->p, rk808->pins->reset); + + if (ret) + dev_dbg(dev, "failed to activate reset-setting pinctrl state\n"); + + return 0; +} + +static void rk817_of_property_prepare(struct rk808 *rk808, struct device *dev) +{ + u32 inner; + int ret, func, msk, val; + struct device_node *np = dev->of_node; + + ret = of_property_read_u32_index(np, "fb-inner-reg-idxs", 0, &inner); + if (!ret && inner == RK817_ID_DCDC3) + regmap_update_bits(rk808->regmap, RK817_POWER_CONFIG, + RK817_BUCK3_FB_RES_MSK, + RK817_BUCK3_FB_RES_INTER); + else + regmap_update_bits(rk808->regmap, RK817_POWER_CONFIG, + RK817_BUCK3_FB_RES_MSK, + RK817_BUCK3_FB_RES_EXT); + dev_info(dev, "support dcdc3 fb mode:%d, %d\n", ret, inner); + + ret = of_property_read_u32(np, "pmic-reset-func", &func); + + msk = RK817_SLPPIN_FUNC_MSK | RK817_RST_FUNC_MSK; + val = SLPPIN_NULL_FUN; + + if (!ret && func < RK817_RST_FUNC_CNT) { + val |= RK817_RST_FUNC_MSK & + (func << RK817_RST_FUNC_SFT); + } else { + val |= RK817_RST_FUNC_REG; + } + + regmap_update_bits(rk808->regmap, RK817_SYS_CFG(3), msk, val); + + dev_info(dev, "support pmic reset mode:%d,%d\n", ret, func); +} + static struct kobject *rk8xx_kobj; static struct device_attribute rk8xx_attrs = __ATTR(rk8xx_dbg, 0200, NULL, rk8xx_dbg_store); @@ -924,6 +1095,9 @@ static int rk808_probe(struct i2c_client *client, unsigned char pmic_id_msb, pmic_id_lsb; int ret; int i; + void (*of_property_prepare_fn)(struct rk808 *rk808, + struct device *dev) = NULL; + int (*pinctrl_init)(struct device *dev, struct rk808 *rk808) = NULL; rk808 = devm_kzalloc(&client->dev, sizeof(*rk808), GFP_KERNEL); if (!rk808) @@ -1020,6 +1194,9 @@ static int rk808_probe(struct i2c_client *client, suspend_reg_num = ARRAY_SIZE(rk817_suspend_reg); resume_reg = rk817_resume_reg; resume_reg_num = ARRAY_SIZE(rk817_resume_reg); + rk808->pm_pwroff_prep_fn = rk817_shutdown_prepare; + of_property_prepare_fn = rk817_of_property_prepare; + pinctrl_init = rk817_pinctrl_init; break; default: dev_err(&client->dev, "Unsupported RK8XX ID %lu\n", @@ -1042,6 +1219,19 @@ static int rk808_probe(struct i2c_client *client, return -EINVAL; } + if (of_property_prepare_fn) + of_property_prepare_fn(rk808, &client->dev); + + i2c_set_clientdata(client, rk808); + rk808->i2c = client; + rk808_i2c_client = client; + + if (pinctrl_init) { + ret = pinctrl_init(&client->dev, rk808); + if (ret) + return ret; + } + ret = regmap_add_irq_chip(rk808->regmap, client->irq, IRQF_ONESHOT | IRQF_SHARED, -1, rk808->regmap_irq_chip, &rk808->irq_data); @@ -1158,6 +1348,13 @@ static int rk8xx_suspend(struct device *dev) } } + if (rk808->pins && rk808->pins->p && rk808->pins->sleep) { + ret = pinctrl_select_state(rk808->pins->p, rk808->pins->sleep); + if (ret) { + dev_err(dev, "failed to act slp pinctrl state\n"); + return -1; + } + } return ret; } @@ -1177,6 +1374,11 @@ static int rk8xx_resume(struct device *dev) return ret; } } + if (rk808->pins && rk808->pins->p && rk808->pins->reset) { + ret = pinctrl_select_state(rk808->pins->p, rk808->pins->reset); + if (ret) + dev_dbg(dev, "failed to act reset pinctrl state\n"); + } return ret; } SIMPLE_DEV_PM_OPS(rk8xx_pm_ops, rk8xx_suspend, rk8xx_resume); diff --git a/drivers/pinctrl/pinctrl-rk805.c b/drivers/pinctrl/pinctrl-rk805.c index b0bfd3082a1b..8810aabb7555 100644 --- a/drivers/pinctrl/pinctrl-rk805.c +++ b/drivers/pinctrl/pinctrl-rk805.c @@ -136,12 +136,118 @@ static struct rk805_pin_config rk805_gpio_cfgs[] = { }, }; +enum rk817_pinmux_option { + RK817_PINMUX_FUN0 = 0, + RK817_PINMUX_FUN1, + RK817_PINMUX_FUN2, + RK817_PINMUX_FUN3 +}; + +enum { + RK817_GPIO_SLP, + RK817_GPIO_TS, + RK817_GPIO_GT +}; + +/* for rk809 only a sleep pin */ +static const char *const rk817_gpio_groups[] = { + "gpio_slp", + "gpio_ts", + "gpio_gt", +}; + +static const struct pinctrl_pin_desc rk817_pins_desc[] = { + PINCTRL_PIN(RK817_GPIO_SLP, "gpio_slp"), /* sleep pin */ + PINCTRL_PIN(RK817_GPIO_TS, "gpio_ts"), /* ts pin */ + PINCTRL_PIN(RK817_GPIO_GT, "gpio_gt")/* gate pin */ +}; + +static const struct rk805_pin_function rk817_pin_functions[] = { + { + .name = "pin_fun0", + .groups = rk817_gpio_groups, + .ngroups = ARRAY_SIZE(rk817_gpio_groups), + .mux_option = RK817_PINMUX_FUN0, + }, + { + .name = "pin_fun1", + .groups = rk817_gpio_groups, + .ngroups = ARRAY_SIZE(rk817_gpio_groups), + .mux_option = RK817_PINMUX_FUN1, + }, + { + .name = "pin_fun2", + .groups = rk817_gpio_groups, + .ngroups = ARRAY_SIZE(rk817_gpio_groups), + .mux_option = RK817_PINMUX_FUN2, + }, + { + .name = "pin_fun3", + .groups = rk817_gpio_groups, + .ngroups = ARRAY_SIZE(rk817_gpio_groups), + .mux_option = RK817_PINMUX_FUN3, + }, +}; + +/* for rk809 only a sleep pin */ +static const struct rk805_pin_group rk817_pin_groups[] = { + { + .name = "gpio_slp", + .pins = { RK817_GPIO_SLP }, + .npins = 1, + }, + { + .name = "gpio_ts", + .pins = { RK817_GPIO_TS }, + .npins = 1, + }, + { + .name = "gpio_gt", + .pins = { RK817_GPIO_GT }, + .npins = 1, + } +}; + +#define RK817_GPIOTS_VAL_MSK BIT(3) +#define RK817_GPIOGT_VAL_MSK BIT(6) +#define RK817_GPIOTS_FUNC_MSK BIT(2) +#define RK817_GPIOGT_FUNC_MSK BIT(5) +#define RK817_GPIOTS_DIR_MSK BIT(4) +#define RK817_GPIOGT_DIR_MSK BIT(7) + +static struct rk805_pin_config rk817_gpio_cfgs[] = { + { + .reg = RK817_SYS_CFG(3), + .val_msk = 0, + .fun_msk = RK817_SLPPIN_FUNC_MSK, + .dir_msk = 0 + }, + { + .reg = RK817_GPIO_INT_CFG, + .val_msk = RK817_GPIOTS_VAL_MSK, + .fun_msk = RK817_GPIOTS_FUNC_MSK, + .dir_msk = RK817_GPIOTS_DIR_MSK + }, + { + .reg = RK817_GPIO_INT_CFG, + .val_msk = RK817_GPIOGT_VAL_MSK, + .fun_msk = RK817_GPIOGT_FUNC_MSK, + .dir_msk = RK817_GPIOGT_DIR_MSK + } +}; + /* generic gpio chip */ static int rk805_gpio_get(struct gpio_chip *chip, unsigned int offset) { struct rk805_pctrl_info *pci = gpiochip_get_data(chip); int ret, val; + if (!pci->pin_cfg[offset].val_msk) { + dev_dbg(pci->dev, "getting gpio%d value is not support\n", + offset); + return -1; + } + ret = regmap_read(pci->rk808->regmap, pci->pin_cfg[offset].reg, &val); if (ret) { dev_err(pci->dev, "get gpio%d value failed\n", offset); @@ -158,6 +264,9 @@ static void rk805_gpio_set(struct gpio_chip *chip, struct rk805_pctrl_info *pci = gpiochip_get_data(chip); int ret; + if (!pci->pin_cfg[offset].val_msk) + return; + ret = regmap_update_bits(pci->rk808->regmap, pci->pin_cfg[offset].reg, pci->pin_cfg[offset].val_msk, @@ -215,6 +324,20 @@ static struct gpio_chip rk805_gpio_chip = { .owner = THIS_MODULE, }; +static struct gpio_chip rk817_gpio_chip = { + .label = "rk817-gpio", + .request = gpiochip_generic_request, + .free = gpiochip_generic_free, + .get_direction = rk805_gpio_get_direction, + .get = rk805_gpio_get, + .set = rk805_gpio_set, + .direction_input = rk805_gpio_direction_input, + .direction_output = rk805_gpio_direction_output, + .can_sleep = true, + .base = -1, + .owner = THIS_MODULE, +}; + /* generic pinctrl */ static int rk805_pinctrl_get_groups_count(struct pinctrl_dev *pctldev) { @@ -290,7 +413,7 @@ static int _rk805_pinctrl_set_mux(struct pinctrl_dev *pctldev, if (!pci->pin_cfg[offset].fun_msk) return 0; - if (mux == RK805_PINMUX_GPIO) { + if (mux == RK805_PINMUX_GPIO) { ret = regmap_update_bits(pci->rk808->regmap, pci->pin_cfg[offset].reg, pci->pin_cfg[offset].fun_msk, @@ -307,6 +430,27 @@ static int _rk805_pinctrl_set_mux(struct pinctrl_dev *pctldev, return 0; } +static int _rk817_pinctrl_set_mux(struct pinctrl_dev *pctldev, + unsigned int offset, + int mux) +{ + struct rk805_pctrl_info *pci = pinctrl_dev_get_drvdata(pctldev); + int ret; + + if (!pci->pin_cfg[offset].fun_msk) + return 0; + + mux <<= ffs(pci->pin_cfg[offset].fun_msk) - 1; + ret = regmap_update_bits(pci->rk808->regmap, + pci->pin_cfg[offset].reg, + pci->pin_cfg[offset].fun_msk, mux); + + if (ret) + dev_err(pci->dev, "set gpio%d func%d failed\n", offset, mux); + + return ret; +} + static int rk805_pinctrl_set_mux(struct pinctrl_dev *pctldev, unsigned int function, unsigned int group) @@ -315,7 +459,17 @@ static int rk805_pinctrl_set_mux(struct pinctrl_dev *pctldev, int mux = pci->functions[function].mux_option; int offset = group; - return _rk805_pinctrl_set_mux(pctldev, offset, mux); + switch (pci->rk808->variant) { + case RK805_ID: + return _rk805_pinctrl_set_mux(pctldev, offset, mux); + + case RK809_ID: + case RK817_ID: + return _rk817_pinctrl_set_mux(pctldev, offset, mux); + default: + dev_err(pci->dev, "Couldn't find the variant id\n"); + return -EINVAL; + } } static int rk805_pmx_gpio_set_direction(struct pinctrl_dev *pctldev, @@ -325,13 +479,6 @@ static int rk805_pmx_gpio_set_direction(struct pinctrl_dev *pctldev, struct rk805_pctrl_info *pci = pinctrl_dev_get_drvdata(pctldev); int ret; - /* switch to gpio function */ - ret = _rk805_pinctrl_set_mux(pctldev, offset, RK805_PINMUX_GPIO); - if (ret) { - dev_err(pci->dev, "set gpio%d mux failed\n", offset); - return ret; - } - /* set direction */ if (!pci->pin_cfg[offset].dir_msk) return 0; @@ -391,8 +538,13 @@ static int rk805_pinconf_set(struct pinctrl_dev *pctldev, switch (param) { case PIN_CONFIG_OUTPUT: - rk805_gpio_set(&pci->gpio_chip, pin, arg); rk805_pmx_gpio_set_direction(pctldev, NULL, pin, false); + rk805_gpio_set(&pci->gpio_chip, pin, arg); + break; + case PIN_CONFIG_INPUT_ENABLE: + if (arg) + rk805_pmx_gpio_set_direction(pctldev, NULL, + pin, true); break; default: dev_err(pci->dev, "Properties not supported\n"); @@ -416,9 +568,18 @@ static struct pinctrl_desc rk805_pinctrl_desc = { .owner = THIS_MODULE, }; +static struct pinctrl_desc rk817_pinctrl_desc = { + .name = "rk817-pinctrl", + .pctlops = &rk805_pinctrl_ops, + .pmxops = &rk805_pinmux_ops, + .confops = &rk805_pinconf_ops, + .owner = THIS_MODULE, +}; + static int rk805_pinctrl_probe(struct platform_device *pdev) { struct rk805_pctrl_info *pci; + struct device_node *np; int ret; pci = devm_kzalloc(&pdev->dev, sizeof(*pci), GFP_KERNEL); @@ -426,18 +587,19 @@ static int rk805_pinctrl_probe(struct platform_device *pdev) return -ENOMEM; pci->dev = &pdev->dev; - pci->dev->of_node = pdev->dev.parent->of_node; + np = of_get_child_by_name(pdev->dev.parent->of_node, "pinctrl_rk8xx"); + if (np) + pci->dev->of_node = np; + else + pci->dev->of_node = pdev->dev.parent->of_node; pci->rk808 = dev_get_drvdata(pdev->dev.parent); - pci->pinctrl_desc = rk805_pinctrl_desc; - pci->gpio_chip = rk805_gpio_chip; - pci->gpio_chip.parent = &pdev->dev; - pci->gpio_chip.of_node = pdev->dev.parent->of_node; - platform_set_drvdata(pdev, pci); switch (pci->rk808->variant) { case RK805_ID: + pci->pinctrl_desc = rk805_pinctrl_desc; + pci->gpio_chip = rk805_gpio_chip; pci->pins = rk805_pins_desc; pci->num_pins = ARRAY_SIZE(rk805_pins_desc); pci->functions = rk805_pin_functions; @@ -449,13 +611,42 @@ static int rk805_pinctrl_probe(struct platform_device *pdev) pci->pin_cfg = rk805_gpio_cfgs; pci->gpio_chip.ngpio = ARRAY_SIZE(rk805_gpio_cfgs); break; + case RK809_ID: + case RK817_ID: + pci->pinctrl_desc = rk817_pinctrl_desc; + pci->gpio_chip = rk817_gpio_chip; + pci->pins = rk817_pins_desc; + pci->num_pins = ARRAY_SIZE(rk817_pins_desc); + pci->functions = rk817_pin_functions; + pci->num_functions = ARRAY_SIZE(rk817_pin_functions); + pci->groups = rk817_pin_groups; + pci->num_pin_groups = ARRAY_SIZE(rk817_pin_groups); + pci->pinctrl_desc.pins = rk817_pins_desc; + pci->pinctrl_desc.npins = ARRAY_SIZE(rk817_pins_desc); + pci->pin_cfg = rk817_gpio_cfgs; + pci->gpio_chip.ngpio = ARRAY_SIZE(rk817_gpio_cfgs); + /* for rk809 only a sleep pin */ + if (pci->rk808->variant == RK809_ID) { + pci->pinctrl_desc.npins = 1; + pci->num_pin_groups = 1; + pci->num_pins = 1; + pci->gpio_chip.ngpio = 1; + } + break; default: dev_err(&pdev->dev, "unsupported RK805 ID %lu\n", pci->rk808->variant); return -EINVAL; } - /* Add gpio chip */ + pci->gpio_chip.parent = &pdev->dev; + + if (np) + pci->gpio_chip.of_node = np; + else + pci->gpio_chip.of_node = pdev->dev.parent->of_node; + + /* Add gpiochip */ ret = devm_gpiochip_add_data(&pdev->dev, &pci->gpio_chip, pci); if (ret < 0) { dev_err(&pdev->dev, "Couldn't add gpiochip\n"); @@ -486,7 +677,12 @@ static struct platform_driver rk805_pinctrl_driver = { .name = "rk805-pinctrl", }, }; -module_platform_driver(rk805_pinctrl_driver); + +static int __init rk805_pinctrl_driver_register(void) +{ + return platform_driver_register(&rk805_pinctrl_driver); +} +fs_initcall_sync(rk805_pinctrl_driver_register); MODULE_DESCRIPTION("RK805 pin control and GPIO driver"); MODULE_AUTHOR("Joseph Chen "); diff --git a/include/linux/mfd/rk808.h b/include/linux/mfd/rk808.h index d99916263b0a..0bf203118c45 100644 --- a/include/linux/mfd/rk808.h +++ b/include/linux/mfd/rk808.h @@ -881,6 +881,13 @@ enum { RK818_ID = 0x8181, }; +struct rk808_pin_info { + struct pinctrl *p; + struct pinctrl_state *reset; + struct pinctrl_state *power_off; + struct pinctrl_state *sleep; +}; + struct rk808 { struct i2c_client *i2c; struct regmap_irq_chip_data *irq_data; @@ -891,5 +898,6 @@ struct rk808 { const struct regmap_irq_chip *regmap_irq_chip; void (*pm_pwroff_fn)(void); void (*pm_pwroff_prep_fn)(void); + struct rk808_pin_info *pins; }; #endif /* __LINUX_REGULATOR_RK808_H */