MLK-17290-05 gpio: mxc: save and restore gpio controller registers when power off
authorFugang Duan <fugang.duan@nxp.com>
Mon, 25 Dec 2017 09:44:28 +0000 (17:44 +0800)
committerNitin Garg <nitin.garg@nxp.com>
Tue, 20 Mar 2018 19:52:11 +0000 (14:52 -0500)
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>
drivers/gpio/gpio-mxc.c

index 8c7f2ad..e81bb53 100644 (file)
@@ -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)