diff --git a/arch/arm/mach-mvebu/common.h b/arch/arm/mach-mvebu/common.h index 3e0aca1f288a..6b775492cfad 100644 --- a/arch/arm/mach-mvebu/common.h +++ b/arch/arm/mach-mvebu/common.h @@ -25,6 +25,6 @@ int mvebu_system_controller_get_soc_id(u32 *dev, u32 *rev); void __iomem *mvebu_get_scu_base(void); -int mvebu_pm_init(void (*board_pm_enter)(void __iomem *sdram_reg, u32 srcmd)); - +int mvebu_pm_suspend_init(void (*board_pm_enter)(void __iomem *sdram_reg, + u32 srcmd)); #endif diff --git a/arch/arm/mach-mvebu/pm-board.c b/arch/arm/mach-mvebu/pm-board.c index 3ab06e7252c3..db17121d7d63 100644 --- a/arch/arm/mach-mvebu/pm-board.c +++ b/arch/arm/mach-mvebu/pm-board.c @@ -134,11 +134,19 @@ static int __init mvebu_armada_pm_init(void) if (!gpio_ctrl) return -ENOMEM; - mvebu_pm_init(mvebu_armada_pm_enter); + mvebu_pm_suspend_init(mvebu_armada_pm_enter); out: of_node_put(np); return ret; } -late_initcall(mvebu_armada_pm_init); +/* + * Registering the mvebu_board_pm_enter callback must be done before + * the platform_suspend_ops will be registered. In the same time we + * also need to have the gpio devices registered. That's why we use a + * device_initcall_sync which is called after all the device_initcall + * (used by the gpio device) but before the late_initcall (used to + * register the platform_suspend_ops) + */ +device_initcall_sync(mvebu_armada_pm_init); diff --git a/arch/arm/mach-mvebu/pm.c b/arch/arm/mach-mvebu/pm.c index ca94f07407f1..b058307088f3 100644 --- a/arch/arm/mach-mvebu/pm.c +++ b/arch/arm/mach-mvebu/pm.c @@ -163,13 +163,10 @@ static int mvebu_pm_store_bootinfo(void) return 0; } -static int mvebu_pm_enter(suspend_state_t state) +static int mvebu_enter_suspend(void) { int ret; - if (state != PM_SUSPEND_MEM) - return -EINVAL; - ret = mvebu_pm_store_bootinfo(); if (ret) return ret; @@ -185,16 +182,57 @@ static int mvebu_pm_enter(suspend_state_t state) set_cpu_coherent(); cpu_pm_exit(); + return 0; +} + +static int mvebu_pm_enter(suspend_state_t state) +{ + switch (state) { + case PM_SUSPEND_STANDBY: + cpu_do_idle(); + break; + case PM_SUSPEND_MEM: + return mvebu_enter_suspend(); + default: + return -EINVAL; + } + return 0; +} + +static int mvebu_pm_valid(suspend_state_t state) +{ + if (state == PM_SUSPEND_STANDBY) + return 1; + + if (state == PM_SUSPEND_MEM && mvebu_board_pm_enter != NULL) + return 1; return 0; } static const struct platform_suspend_ops mvebu_pm_ops = { .enter = mvebu_pm_enter, - .valid = suspend_valid_only_mem, + .valid = mvebu_pm_valid, }; -int __init mvebu_pm_init(void (*board_pm_enter)(void __iomem *sdram_reg, u32 srcmd)) +static int __init mvebu_pm_init(void) +{ + if (!of_machine_is_compatible("marvell,armadaxp") && + !of_machine_is_compatible("marvell,armada370") && + !of_machine_is_compatible("marvell,armada380") && + !of_machine_is_compatible("marvell,armada390")) + return -ENODEV; + + suspend_set_ops(&mvebu_pm_ops); + + return 0; +} + + +late_initcall(mvebu_pm_init); + +int __init mvebu_pm_suspend_init(void (*board_pm_enter)(void __iomem *sdram_reg, + u32 srcmd)) { struct device_node *np; struct resource res; @@ -226,7 +264,5 @@ int __init mvebu_pm_init(void (*board_pm_enter)(void __iomem *sdram_reg, u32 src mvebu_board_pm_enter = board_pm_enter; - suspend_set_ops(&mvebu_pm_ops); - return 0; }