summaryrefslogtreecommitdiff
path: root/drivers/gpio
diff options
context:
space:
mode:
authorFugang Duan <fugang.duan@nxp.com>2017-12-25 17:44:28 +0800
committerJason Liu <jason.hui.liu@nxp.com>2019-02-12 10:30:02 +0800
commitcb1a9503aa1bcc475add3be37d9e2d2f04db1854 (patch)
tree35ddc94546d1e05ca19b6f8866bc59d1416ff42a /drivers/gpio
parent963c678e2665b864ebc1df70e5a3b7c20c9759b1 (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>
Diffstat (limited to 'drivers/gpio')
-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 208e67f5b82d..2fc4d316419a 100644
--- a/drivers/gpio/gpio-mxc.c
+++ b/drivers/gpio/gpio-mxc.c
@@ -71,6 +71,7 @@ struct mxc_gpio_port {
struct gpio_chip gc;
struct device *dev;
u32 both_edges;
+ int saved_reg[6];
bool gpio_ranges;
};
@@ -591,11 +592,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;
@@ -605,8 +641,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)