gpio: mxc: move gpio noirq suspend/resume to syscore phase
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. Signed-off-by: Anson Huang <Anson.Huang@nxp.com> Signed-off-by: Linus Walleij <linus.walleij@linaro.org>
This commit is contained in:
parent
eee3919c5f
commit
1a5287a3db
|
@ -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,31 +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 mxc_gpio_port *port = dev_get_drvdata(dev);
|
||||
struct mxc_gpio_port *port;
|
||||
|
||||
/* 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 mxc_gpio_port *port = dev_get_drvdata(dev);
|
||||
struct mxc_gpio_port *port;
|
||||
int ret;
|
||||
|
||||
/* walk through all ports */
|
||||
list_for_each_entry(port, &mxc_gpio_ports, node) {
|
||||
ret = clk_prepare_enable(port->clk);
|
||||
if (ret)
|
||||
return ret;
|
||||
if (ret) {
|
||||
pr_err("mxc: failed to enable gpio clock %d\n", ret);
|
||||
return;
|
||||
}
|
||||
mxc_gpio_restore_regs(port);
|
||||
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
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 = {
|
||||
|
@ -582,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,
|
||||
|
@ -590,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);
|
||||
|
|
Loading…
Reference in New Issue