summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorFugang Duan <fugang.duan@nxp.com>2017-12-25 17:44:28 +0800
committerFugang Duan <fugang.duan@nxp.com>2018-01-08 14:12:02 +0800
commit21a46bbbefffd7a8e2ad2c500e84eb057e2a2cd8 (patch)
treec256f3c5147f62ae2f048b48e64f665a7b0dd389
parent6927b042dfc9ab99d5bbd4374aa2ac299f9f1a14 (diff)
MLK-17290-05 gpio: mxc: save and restore gpio controller registers when power off
Save gpio controller registers before power off, and then restore these registers after power on. There have two cases need to save/restore regs: a. If sub_irqs/sub_gpios are not free/released, device suspend() force runtime suspend and power domain off in suspended stage, it needs to keep the previous registers value after device resume back. b. If some sub_irqs set irq type just one time, then irqchip should restore the registers for correct irq type. Signed-off-by: Fugang Duan <fugang.duan@nxp.com> Tested-by: Guoniu.Zhou <guoniu.zhou@nxp.com> Reviewed-by: Frank Li <Frank.Li@nxp.com> (cherry picked from commit: 764ebc90db18fe6f98bd77921050529ca6dd183e)
-rw-r--r--drivers/gpio/gpio-mxc.c45
1 files changed, 44 insertions, 1 deletions
diff --git a/drivers/gpio/gpio-mxc.c b/drivers/gpio/gpio-mxc.c
index 8c7f2ad897d6..e81bb530cb17 100644
--- a/drivers/gpio/gpio-mxc.c
+++ b/drivers/gpio/gpio-mxc.c
@@ -70,6 +70,7 @@ struct mxc_gpio_port {
struct irq_domain *domain;
struct gpio_chip gc;
u32 both_edges;
+ int saved_reg[6];
bool gpio_ranges;
};
@@ -584,11 +585,46 @@ out_bgio:
return err;
}
+static void mxc_gpio_save_regs(struct mxc_gpio_port *port)
+{
+ unsigned long flags;
+
+ if (mxc_gpio_hwtype == IMX21_GPIO)
+ return;
+
+ spin_lock_irqsave(&port->gc.bgpio_lock, flags);
+ port->saved_reg[0] = readl(port->base + GPIO_ICR1);
+ port->saved_reg[1] = readl(port->base + GPIO_ICR2);
+ port->saved_reg[2] = readl(port->base + GPIO_IMR);
+ port->saved_reg[3] = readl(port->base + GPIO_GDIR);
+ port->saved_reg[4] = readl(port->base + GPIO_EDGE_SEL);
+ port->saved_reg[5] = readl(port->base + GPIO_DR);
+ spin_unlock_irqrestore(&port->gc.bgpio_lock, flags);
+}
+
+static void mxc_gpio_restore_regs(struct mxc_gpio_port *port)
+{
+ unsigned long flags;
+
+ if (mxc_gpio_hwtype == IMX21_GPIO)
+ return;
+
+ spin_lock_irqsave(&port->gc.bgpio_lock, flags);
+ writel(port->saved_reg[0], port->base + GPIO_ICR1);
+ writel(port->saved_reg[1], port->base + GPIO_ICR2);
+ writel(port->saved_reg[2], port->base + GPIO_IMR);
+ writel(port->saved_reg[3], port->base + GPIO_GDIR);
+ writel(port->saved_reg[4], port->base + GPIO_EDGE_SEL);
+ writel(port->saved_reg[5], port->base + GPIO_DR);
+ spin_unlock_irqrestore(&port->gc.bgpio_lock, flags);
+}
+
static int __maybe_unused mxc_gpio_runtime_suspend(struct device *dev)
{
struct platform_device *pdev = to_platform_device(dev);
struct mxc_gpio_port *port = platform_get_drvdata(pdev);
+ mxc_gpio_save_regs(port);
clk_disable_unprepare(port->clk);
return 0;
@@ -598,8 +634,15 @@ static int __maybe_unused mxc_gpio_runtime_resume(struct device *dev)
{
struct platform_device *pdev = to_platform_device(dev);
struct mxc_gpio_port *port = platform_get_drvdata(pdev);
+ int ret;
+
+ ret = clk_prepare_enable(port->clk);
+ if (ret)
+ return ret;
- return clk_prepare_enable(port->clk);
+ mxc_gpio_restore_regs(port);
+
+ return 0;
}
static int __maybe_unused mxc_gpio_suspend(struct device *dev)