From 876d716ba9af205f46b7e911d39482e627aea0e8 Mon Sep 17 00:00:00 2001 From: Doug Anderson Date: Tue, 21 Oct 2014 10:47:32 -0700 Subject: pinctrl: rockchip: Set wake_enabled The rockchip pinctrl driver uses irq_gc_set_wake() but doesn't setup the .wake_enabled member. That means that we can never actually use a pin for wakeup. When "irq_set_irq_wake()" tries to call through it will always get a failure from set_irq_wake_real() and will then set wake_depth to 0. Assuming you can resume you'll later get an error message about "Unbalanced IRQ x wake disable". Signed-off-by: Doug Anderson Tested-by: Chris Zhong Signed-off-by: Heiko Stuebner --- drivers/pinctrl/pinctrl-rockchip.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/pinctrl/pinctrl-rockchip.c b/drivers/pinctrl/pinctrl-rockchip.c index 016f4578e494..230d8f379129 100644 --- a/drivers/pinctrl/pinctrl-rockchip.c +++ b/drivers/pinctrl/pinctrl-rockchip.c @@ -1563,6 +1563,7 @@ static int rockchip_interrupts_register(struct platform_device *pdev, gc->chip_types[0].chip.irq_unmask = irq_gc_mask_set_bit; gc->chip_types[0].chip.irq_set_wake = irq_gc_set_wake; gc->chip_types[0].chip.irq_set_type = rockchip_irq_set_type; + gc->wake_enabled = IRQ_MSK(bank->nr_pins); irq_set_handler_data(bank->irq, bank); irq_set_chained_handler(bank->irq, rockchip_irq_demux); -- cgit v1.2.3 From e5c2c9db0a2cff4d4df4b94f91146b26a0f0adc7 Mon Sep 17 00:00:00 2001 From: Doug Anderson Date: Tue, 21 Oct 2014 10:47:33 -0700 Subject: pinctrl: rockchip: Don't call pinctrl_gpio_direction_output() in pin_config_set() The Rockchip pinctrl driver was calling rockchip_gpio_direction_output() in the pin_config_set() callback. This was just a shortcut for: * rockchip_gpio_set() * pinctrl_gpio_direction_output() Unfortunately it's not so good to call pinctrl_gpio_direction_output() from pin_config_set(). Specifically when initting hogs you'll get an error. Let's refactor a little so we can call _rockchip_pmx_gpio_set_direction() directly. Signed-off-by: Doug Anderson Tested-by: Chris Zhong Signed-off-by: Heiko Stuebner --- drivers/pinctrl/pinctrl-rockchip.c | 41 +++++++++++++++++++++++--------------- 1 file changed, 25 insertions(+), 16 deletions(-) diff --git a/drivers/pinctrl/pinctrl-rockchip.c b/drivers/pinctrl/pinctrl-rockchip.c index 230d8f379129..8a3c582108c5 100644 --- a/drivers/pinctrl/pinctrl-rockchip.c +++ b/drivers/pinctrl/pinctrl-rockchip.c @@ -856,22 +856,14 @@ static int rockchip_pmx_set(struct pinctrl_dev *pctldev, unsigned selector, * leads to this function call (via the pinctrl_gpio_direction_{input|output}() * function called from the gpiolib interface). */ -static int rockchip_pmx_gpio_set_direction(struct pinctrl_dev *pctldev, - struct pinctrl_gpio_range *range, - unsigned offset, bool input) +static int _rockchip_pmx_gpio_set_direction(struct gpio_chip *chip, + int pin, bool input) { - struct rockchip_pinctrl *info = pinctrl_dev_get_drvdata(pctldev); struct rockchip_pin_bank *bank; - struct gpio_chip *chip; - int pin, ret; + int ret; u32 data; - chip = range->gc; bank = gc_to_pin_bank(chip); - pin = offset - chip->base; - - dev_dbg(info->dev, "gpio_direction for pin %u as %s-%d to %s\n", - offset, range->name, pin, input ? "input" : "output"); ret = rockchip_set_mux(bank, pin, RK_FUNC_GPIO); if (ret < 0) @@ -888,6 +880,23 @@ static int rockchip_pmx_gpio_set_direction(struct pinctrl_dev *pctldev, return 0; } +static int rockchip_pmx_gpio_set_direction(struct pinctrl_dev *pctldev, + struct pinctrl_gpio_range *range, + unsigned offset, bool input) +{ + struct rockchip_pinctrl *info = pinctrl_dev_get_drvdata(pctldev); + struct gpio_chip *chip; + int pin; + + chip = range->gc; + pin = offset - chip->base; + dev_dbg(info->dev, "gpio_direction for pin %u as %s-%d to %s\n", + offset, range->name, pin, input ? "input" : "output"); + + return _rockchip_pmx_gpio_set_direction(chip, offset - chip->base, + input); +} + static const struct pinmux_ops rockchip_pmx_ops = { .get_functions_count = rockchip_pmx_get_funcs_count, .get_function_name = rockchip_pmx_get_func_name, @@ -917,8 +926,7 @@ static bool rockchip_pinconf_pull_valid(struct rockchip_pin_ctrl *ctrl, return false; } -static int rockchip_gpio_direction_output(struct gpio_chip *gc, - unsigned offset, int value); +static void rockchip_gpio_set(struct gpio_chip *gc, unsigned offset, int value); static int rockchip_gpio_get(struct gpio_chip *gc, unsigned offset); /* set the pin config settings for a specified pin */ @@ -959,9 +967,10 @@ static int rockchip_pinconf_set(struct pinctrl_dev *pctldev, unsigned int pin, return rc; break; case PIN_CONFIG_OUTPUT: - rc = rockchip_gpio_direction_output(&bank->gpio_chip, - pin - bank->pin_base, - arg); + rockchip_gpio_set(&bank->gpio_chip, + pin - bank->pin_base, arg); + rc = _rockchip_pmx_gpio_set_direction(&bank->gpio_chip, + pin - bank->pin_base, false); if (rc) return rc; break; -- cgit v1.2.3 From 0fb7dcb1b3328e2ec4958b681f2e31dfd8f004fb Mon Sep 17 00:00:00 2001 From: Doug Anderson Date: Tue, 21 Oct 2014 10:47:34 -0700 Subject: pinctrl: rockchip: Parse pin groups before calling pinctrl_register() Just like in (529301c pinctrl: samsung: Parse pin groups before calling pinctrl_register()), Rockchip also needs to parse pin groups earlier to make hogs work. Signed-off-by: Doug Anderson Tested-by: Chris Zhong Signed-off-by: Heiko Stuebner --- drivers/pinctrl/pinctrl-rockchip.c | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/drivers/pinctrl/pinctrl-rockchip.c b/drivers/pinctrl/pinctrl-rockchip.c index 8a3c582108c5..6c14f6c9c455 100644 --- a/drivers/pinctrl/pinctrl-rockchip.c +++ b/drivers/pinctrl/pinctrl-rockchip.c @@ -1262,6 +1262,10 @@ static int rockchip_pinctrl_register(struct platform_device *pdev, } } + ret = rockchip_pinctrl_parse_dt(pdev, info); + if (ret) + return ret; + info->pctl_dev = pinctrl_register(ctrldesc, &pdev->dev, info); if (!info->pctl_dev) { dev_err(&pdev->dev, "could not register pinctrl driver\n"); @@ -1279,12 +1283,6 @@ static int rockchip_pinctrl_register(struct platform_device *pdev, pinctrl_add_gpio_range(info->pctl_dev, &pin_bank->grange); } - ret = rockchip_pinctrl_parse_dt(pdev, info); - if (ret) { - pinctrl_unregister(info->pctl_dev); - return ret; - } - return 0; } -- cgit v1.2.3 From fab262f5000407ce86a010ab5bc683c01c02d1a6 Mon Sep 17 00:00:00 2001 From: Doug Anderson Date: Tue, 21 Oct 2014 10:47:35 -0700 Subject: pinctrl: rockchip: Protect read-modify-write with the spinlock There were a few instances where the rockchip pinctrl driver would do read-modify-write with no spinlock. Add a spinlock for these cases. Signed-off-by: Doug Anderson Signed-off-by: Heiko Stuebner --- drivers/pinctrl/pinctrl-rockchip.c | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/drivers/pinctrl/pinctrl-rockchip.c b/drivers/pinctrl/pinctrl-rockchip.c index 6c14f6c9c455..59a54617bf75 100644 --- a/drivers/pinctrl/pinctrl-rockchip.c +++ b/drivers/pinctrl/pinctrl-rockchip.c @@ -861,6 +861,7 @@ static int _rockchip_pmx_gpio_set_direction(struct gpio_chip *chip, { struct rockchip_pin_bank *bank; int ret; + unsigned long flags; u32 data; bank = gc_to_pin_bank(chip); @@ -869,6 +870,8 @@ static int _rockchip_pmx_gpio_set_direction(struct gpio_chip *chip, if (ret < 0) return ret; + spin_lock_irqsave(&bank->slock, flags); + data = readl_relaxed(bank->reg_base + GPIO_SWPORT_DDR); /* set bit to 1 for output, 0 for input */ if (!input) @@ -877,6 +880,8 @@ static int _rockchip_pmx_gpio_set_direction(struct gpio_chip *chip, data &= ~BIT(pin); writel_relaxed(data, bank->reg_base + GPIO_SWPORT_DDR); + spin_unlock_irqrestore(&bank->slock, flags); + return 0; } @@ -1394,6 +1399,7 @@ static void rockchip_irq_demux(unsigned int irq, struct irq_desc *desc) u32 polarity = 0, data = 0; u32 pend; bool edge_changed = false; + unsigned long flags; dev_dbg(bank->drvdata->dev, "got irq for bank %s\n", bank->name); @@ -1439,10 +1445,14 @@ static void rockchip_irq_demux(unsigned int irq, struct irq_desc *desc) if (bank->toggle_edge_mode && edge_changed) { /* Interrupt params should only be set with ints disabled */ + spin_lock_irqsave(&bank->slock, flags); + data = readl_relaxed(bank->reg_base + GPIO_INTEN); writel_relaxed(0, bank->reg_base + GPIO_INTEN); writel(polarity, bank->reg_base + GPIO_INT_POLARITY); writel(data, bank->reg_base + GPIO_INTEN); + + spin_unlock_irqrestore(&bank->slock, flags); } chained_irq_exit(chip, desc); @@ -1456,6 +1466,7 @@ static int rockchip_irq_set_type(struct irq_data *d, unsigned int type) u32 polarity; u32 level; u32 data; + unsigned long flags; int ret; /* make sure the pin is configured as gpio input */ @@ -1463,15 +1474,20 @@ static int rockchip_irq_set_type(struct irq_data *d, unsigned int type) if (ret < 0) return ret; + spin_lock_irqsave(&bank->slock, flags); + data = readl_relaxed(bank->reg_base + GPIO_SWPORT_DDR); data &= ~mask; writel_relaxed(data, bank->reg_base + GPIO_SWPORT_DDR); + spin_unlock_irqrestore(&bank->slock, flags); + if (type & IRQ_TYPE_EDGE_BOTH) __irq_set_handler_locked(d->irq, handle_edge_irq); else __irq_set_handler_locked(d->irq, handle_level_irq); + spin_lock_irqsave(&bank->slock, flags); irq_gc_lock(gc); level = readl_relaxed(gc->reg_base + GPIO_INTTYPE_LEVEL); @@ -1514,6 +1530,7 @@ static int rockchip_irq_set_type(struct irq_data *d, unsigned int type) break; default: irq_gc_unlock(gc); + spin_unlock_irqrestore(&bank->slock, flags); return -EINVAL; } @@ -1521,6 +1538,7 @@ static int rockchip_irq_set_type(struct irq_data *d, unsigned int type) writel_relaxed(polarity, gc->reg_base + GPIO_INT_POLARITY); irq_gc_unlock(gc); + spin_unlock_irqrestore(&bank->slock, flags); return 0; } -- cgit v1.2.3 From 9198f509c888f1ca8f5a50047d702b1ab29459a5 Mon Sep 17 00:00:00 2001 From: Chris Zhong Date: Wed, 29 Oct 2014 19:51:59 +0800 Subject: pinctrl: rockchip: add suspend/resume functions support suspend/resume of pinctrl, it allows handling sleep mode for hogged pins in pinctrl Signed-off-by: Chris Zhong Tested-by: Doug Anderson Reviewed-by: Doug Anderson Tested-by: Heiko Stuebner Signed-off-by: Heiko Stuebner --- drivers/pinctrl/pinctrl-rockchip.c | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/drivers/pinctrl/pinctrl-rockchip.c b/drivers/pinctrl/pinctrl-rockchip.c index 59a54617bf75..28b12187c2c1 100644 --- a/drivers/pinctrl/pinctrl-rockchip.c +++ b/drivers/pinctrl/pinctrl-rockchip.c @@ -1796,6 +1796,23 @@ static struct rockchip_pin_ctrl *rockchip_pinctrl_get_soc_data( return ctrl; } +static int __maybe_unused rockchip_pinctrl_suspend(struct device *dev) +{ + struct rockchip_pinctrl *info = dev_get_drvdata(dev); + + return pinctrl_force_sleep(info->pctl_dev); +} + +static int __maybe_unused rockchip_pinctrl_resume(struct device *dev) +{ + struct rockchip_pinctrl *info = dev_get_drvdata(dev); + + return pinctrl_force_default(info->pctl_dev); +} + +static SIMPLE_DEV_PM_OPS(rockchip_pinctrl_dev_pm_ops, rockchip_pinctrl_suspend, + rockchip_pinctrl_resume); + static int rockchip_pinctrl_probe(struct platform_device *pdev) { struct rockchip_pinctrl *info; @@ -2009,6 +2026,7 @@ static struct platform_driver rockchip_pinctrl_driver = { .driver = { .name = "rockchip-pinctrl", .owner = THIS_MODULE, + .pm = &rockchip_pinctrl_dev_pm_ops, .of_match_table = rockchip_pinctrl_dt_match, }, }; -- cgit v1.2.3 From 8dca9331270240125fedbe83e0a2cd5750ed9fff Mon Sep 17 00:00:00 2001 From: Chris Zhong Date: Wed, 29 Oct 2014 19:52:00 +0800 Subject: pinctrl: rockchip: save and restore gpio6_c6 pinmux in suspend/resume Save and restore the gpio6_c6 pinmux setting, since Maskrom of RK3288 would modify it to sdmmc0_det, so it need to be restored to the correct setting after resume from Maskrom. Signed-off-by: Chris Zhong Tested-by: Doug Anderson Reviewed-by: Doug Anderson Tested-by: Heiko Stuebner Signed-off-by: Heiko Stuebner --- drivers/pinctrl/pinctrl-rockchip.c | 30 +++++++++++++++++++++++++++++- 1 file changed, 29 insertions(+), 1 deletion(-) diff --git a/drivers/pinctrl/pinctrl-rockchip.c b/drivers/pinctrl/pinctrl-rockchip.c index 28b12187c2c1..40970c305dd0 100644 --- a/drivers/pinctrl/pinctrl-rockchip.c +++ b/drivers/pinctrl/pinctrl-rockchip.c @@ -1796,16 +1796,44 @@ static struct rockchip_pin_ctrl *rockchip_pinctrl_get_soc_data( return ctrl; } +#define RK3288_GRF_GPIO6C_IOMUX 0x64 +#define GPIO6C6_SEL_WRITE_ENABLE BIT(28) + +static u32 rk3288_grf_gpio6c_iomux; + static int __maybe_unused rockchip_pinctrl_suspend(struct device *dev) { struct rockchip_pinctrl *info = dev_get_drvdata(dev); + int ret = pinctrl_force_sleep(info->pctl_dev); + + if (ret) + return ret; + + /* + * RK3288 GPIO6_C6 mux would be modified by Maskrom when resume, so save + * the setting here, and restore it at resume. + */ + if (info->ctrl->type == RK3288) { + ret = regmap_read(info->regmap_base, RK3288_GRF_GPIO6C_IOMUX, + &rk3288_grf_gpio6c_iomux); + if (ret) { + pinctrl_force_default(info->pctl_dev); + return ret; + } + } - return pinctrl_force_sleep(info->pctl_dev); + return 0; } static int __maybe_unused rockchip_pinctrl_resume(struct device *dev) { struct rockchip_pinctrl *info = dev_get_drvdata(dev); + int ret = regmap_write(info->regmap_base, RK3288_GRF_GPIO6C_IOMUX, + rk3288_grf_gpio6c_iomux | + GPIO6C6_SEL_WRITE_ENABLE); + + if (ret) + return ret; return pinctrl_force_default(info->pctl_dev); } -- cgit v1.2.3