summaryrefslogtreecommitdiff
path: root/drivers/gpio
diff options
context:
space:
mode:
authorAnson Huang <Anson.Huang@nxp.com>2018-07-16 15:11:17 +0800
committerJason Liu <jason.hui.liu@nxp.com>2019-02-12 10:32:42 +0800
commite1380ef3051df612ffc07e223a6841705ad514c1 (patch)
tree7573f01885e212b362a2174b3bd68e26eb5d5df5 /drivers/gpio
parent3ec6d25c77267e757cec764e2170306dc8af2e3a (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.c59
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)
};