--- /dev/null
+From 73339284cb68f41441768334fd48d259c911182b Mon Sep 17 00:00:00 2001
+From: Anson Huang <anson.huang@nxp.com>
+Date: Sun, 17 Feb 2019 23:05:33 +0100
+Subject: gpio: mxc: move gpio noirq suspend/resume to syscore phase
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+commit 1a5287a3dbc34cd0c02c8f64c9131bd23cdfe2bb upstream.
+
+During noirq suspend/resume phase, GPIO irq could arrive
+and its registers like IMR will be changed by irq handle
+process, to make the GPIO registers exactly when it is
+powered ON after resume, move the GPIO noirq suspend/resume
+callback to syscore suspend/resume phase, local irq is
+disabled at this phase so GPIO registers are atomic.
+
+Fixes: c19fdaeea0aa ("gpio: mxc: add power management support")
+Signed-off-by: Anson Huang <Anson.Huang@nxp.com>
+Signed-off-by: Linus Walleij <linus.walleij@linaro.org>
+Signed-off-by: Martin Hundebøll <martin@geanix.com>
+Cc: <stable@vger.kernel.org> # 4.19.x+
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/gpio/gpio-mxc.c | 41 ++++++++++++++++++++++++-----------------
+ 1 file changed, 24 insertions(+), 17 deletions(-)
+
+diff --git a/drivers/gpio/gpio-mxc.c b/drivers/gpio/gpio-mxc.c
+index 995cf0b9e0b1..2d1dfa1e0745 100644
+--- a/drivers/gpio/gpio-mxc.c
++++ b/drivers/gpio/gpio-mxc.c
+@@ -17,6 +17,7 @@
+ #include <linux/irqchip/chained_irq.h>
+ #include <linux/platform_device.h>
+ #include <linux/slab.h>
++#include <linux/syscore_ops.h>
+ #include <linux/gpio/driver.h>
+ #include <linux/of.h>
+ #include <linux/of_device.h>
+@@ -550,33 +551,38 @@ static void mxc_gpio_restore_regs(struct mxc_gpio_port *port)
+ writel(port->gpio_saved_reg.dr, port->base + GPIO_DR);
+ }
+
+-static int __maybe_unused mxc_gpio_noirq_suspend(struct device *dev)
++static int mxc_gpio_syscore_suspend(void)
+ {
+- struct platform_device *pdev = to_platform_device(dev);
+- struct mxc_gpio_port *port = platform_get_drvdata(pdev);
++ struct mxc_gpio_port *port;
+
+- mxc_gpio_save_regs(port);
+- clk_disable_unprepare(port->clk);
++ /* walk through all ports */
++ list_for_each_entry(port, &mxc_gpio_ports, node) {
++ mxc_gpio_save_regs(port);
++ clk_disable_unprepare(port->clk);
++ }
+
+ return 0;
+ }
+
+-static int __maybe_unused mxc_gpio_noirq_resume(struct device *dev)
++static void mxc_gpio_syscore_resume(void)
+ {
+- struct platform_device *pdev = to_platform_device(dev);
+- struct mxc_gpio_port *port = platform_get_drvdata(pdev);
++ struct mxc_gpio_port *port;
+ int ret;
+
+- ret = clk_prepare_enable(port->clk);
+- if (ret)
+- return ret;
+- mxc_gpio_restore_regs(port);
+-
+- return 0;
++ /* walk through all ports */
++ list_for_each_entry(port, &mxc_gpio_ports, node) {
++ ret = clk_prepare_enable(port->clk);
++ if (ret) {
++ pr_err("mxc: failed to enable gpio clock %d\n", ret);
++ return;
++ }
++ mxc_gpio_restore_regs(port);
++ }
+ }
+
+-static const struct dev_pm_ops mxc_gpio_dev_pm_ops = {
+- SET_NOIRQ_SYSTEM_SLEEP_PM_OPS(mxc_gpio_noirq_suspend, mxc_gpio_noirq_resume)
++static struct syscore_ops mxc_gpio_syscore_ops = {
++ .suspend = mxc_gpio_syscore_suspend,
++ .resume = mxc_gpio_syscore_resume,
+ };
+
+ static struct platform_driver mxc_gpio_driver = {
+@@ -584,7 +590,6 @@ static struct platform_driver mxc_gpio_driver = {
+ .name = "gpio-mxc",
+ .of_match_table = mxc_gpio_dt_ids,
+ .suppress_bind_attrs = true,
+- .pm = &mxc_gpio_dev_pm_ops,
+ },
+ .probe = mxc_gpio_probe,
+ .id_table = mxc_gpio_devtype,
+@@ -592,6 +597,8 @@ static struct platform_driver mxc_gpio_driver = {
+
+ static int __init gpio_mxc_init(void)
+ {
++ register_syscore_ops(&mxc_gpio_syscore_ops);
++
+ return platform_driver_register(&mxc_gpio_driver);
+ }
+ subsys_initcall(gpio_mxc_init);
+--
+2.19.1
+