diff options
author | Anson Huang <Anson.Huang@nxp.com> | 2018-07-16 15:11:17 +0800 |
---|---|---|
committer | Jason Liu <jason.hui.liu@nxp.com> | 2019-02-12 10:32:42 +0800 |
commit | e1380ef3051df612ffc07e223a6841705ad514c1 (patch) | |
tree | 7573f01885e212b362a2174b3bd68e26eb5d5df5 /drivers/gpio | |
parent | 3ec6d25c77267e757cec764e2170306dc8af2e3a (diff) |
MLK-18919 gpio: mxc: add independent gpio save regs for noirq suspend/resume
In system resume phase, the runtime resume will be called
after noirq resume, and the GPIO could be operated between
the noirq resume phase and the runtime resume phase, current
implementation of noirq suspend/resume shares same save
regs array with runtime suspend/resume, the GPIO operation
will be overwritten by runtime resume using old save regs
array, so adding independent gpio save regs for noirq
suspend/resume ONLY, and use noirq suspend/resume callback
instead of sharing runtime suspend/resume callback.
Signed-off-by: Anson Huang <Anson.Huang@nxp.com>
Reviewed-by: Richard Zhu <hongxing.zhu@nxp.com>
Diffstat (limited to 'drivers/gpio')
-rw-r--r-- | drivers/gpio/gpio-mxc.c | 59 |
1 files changed, 58 insertions, 1 deletions
diff --git a/drivers/gpio/gpio-mxc.c b/drivers/gpio/gpio-mxc.c index a5ac8b9468d4..b67461f3c98f 100644 --- a/drivers/gpio/gpio-mxc.c +++ b/drivers/gpio/gpio-mxc.c @@ -72,6 +72,7 @@ struct mxc_gpio_port { struct device *dev; u32 both_edges; int saved_reg[6]; + int suspend_saved_reg[6]; bool gpio_ranges; }; @@ -652,6 +653,62 @@ static int __maybe_unused mxc_gpio_runtime_resume(struct device *dev) return 0; } +static int __maybe_unused mxc_gpio_noirq_suspend(struct device *dev) +{ + struct platform_device *pdev = to_platform_device(dev); + struct mxc_gpio_port *port = platform_get_drvdata(pdev); + unsigned long flags; + int ret; + + if (mxc_gpio_hwtype == IMX21_GPIO) + return 0; + + ret = clk_prepare_enable(port->clk); + if (ret) + return ret; + + spin_lock_irqsave(&port->gc.bgpio_lock, flags); + port->suspend_saved_reg[0] = readl(port->base + GPIO_ICR1); + port->suspend_saved_reg[1] = readl(port->base + GPIO_ICR2); + port->suspend_saved_reg[2] = readl(port->base + GPIO_IMR); + port->suspend_saved_reg[3] = readl(port->base + GPIO_GDIR); + port->suspend_saved_reg[4] = readl(port->base + GPIO_EDGE_SEL); + port->suspend_saved_reg[5] = readl(port->base + GPIO_DR); + spin_unlock_irqrestore(&port->gc.bgpio_lock, flags); + + clk_disable_unprepare(port->clk); + + return 0; +} + +static int __maybe_unused mxc_gpio_noirq_resume(struct device *dev) +{ + struct platform_device *pdev = to_platform_device(dev); + struct mxc_gpio_port *port = platform_get_drvdata(pdev); + unsigned long flags; + int ret; + + if (mxc_gpio_hwtype == IMX21_GPIO) + return 0; + + ret = clk_prepare_enable(port->clk); + if (ret) + return ret; + + spin_lock_irqsave(&port->gc.bgpio_lock, flags); + writel(port->suspend_saved_reg[0], port->base + GPIO_ICR1); + writel(port->suspend_saved_reg[1], port->base + GPIO_ICR2); + writel(port->suspend_saved_reg[2], port->base + GPIO_IMR); + writel(port->suspend_saved_reg[3], port->base + GPIO_GDIR); + writel(port->suspend_saved_reg[4], port->base + GPIO_EDGE_SEL); + writel(port->suspend_saved_reg[5], port->base + GPIO_DR); + spin_unlock_irqrestore(&port->gc.bgpio_lock, flags); + + clk_disable_unprepare(port->clk); + + return 0; +} + static int __maybe_unused mxc_gpio_suspend(struct device *dev) { struct platform_device *pdev = to_platform_device(dev); @@ -678,7 +735,7 @@ static int __maybe_unused mxc_gpio_resume(struct device *dev) static const struct dev_pm_ops mxc_gpio_dev_pm_ops = { SET_SYSTEM_SLEEP_PM_OPS(mxc_gpio_suspend, mxc_gpio_resume) - SET_NOIRQ_SYSTEM_SLEEP_PM_OPS(mxc_gpio_runtime_suspend, mxc_gpio_runtime_resume) + SET_NOIRQ_SYSTEM_SLEEP_PM_OPS(mxc_gpio_noirq_suspend, mxc_gpio_noirq_resume) SET_RUNTIME_PM_OPS(mxc_gpio_runtime_suspend, mxc_gpio_runtime_resume, NULL) }; |