If we override the platform bus calls for pm_runtime then we end up with the calls to the devices' suspend and resume methods ignored in favour of the bus ones. Change to calling the pm_runtime calls to suspend and resume the devices specifically in the drivers/sh/pm_runtime.c implementation to allow any device that may want to run power management to do so. Note, all the current sh driver implementations do not use their own power management code so this is not a major implementation issues. This also brings the implementation into line with the versions used by the Davinci and Keystone PM domain code, so once fully tested these implementations could be merged together. Signed-off-by: Ben Dooks <ben.dooks@codethink.co.uk> Signed-off-by: Geert Uytterhoeven <geert+renesas@glider.be> Reviewed-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com> Signed-off-by: Simon Horman <horms+renesas@verge.net.au>
109 lines
2.5 KiB
C
109 lines
2.5 KiB
C
/*
|
|
* Runtime PM support code
|
|
*
|
|
* Copyright (C) 2009-2010 Magnus Damm
|
|
*
|
|
* This file is subject to the terms and conditions of the GNU General Public
|
|
* License. See the file "COPYING" in the main directory of this archive
|
|
* for more details.
|
|
*/
|
|
|
|
#include <linux/init.h>
|
|
#include <linux/kernel.h>
|
|
#include <linux/io.h>
|
|
#include <linux/pm_runtime.h>
|
|
#include <linux/pm_domain.h>
|
|
#include <linux/pm_clock.h>
|
|
#include <linux/platform_device.h>
|
|
#include <linux/clk.h>
|
|
#include <linux/sh_clk.h>
|
|
#include <linux/bitmap.h>
|
|
#include <linux/slab.h>
|
|
|
|
#ifdef CONFIG_PM_RUNTIME
|
|
static int sh_pm_runtime_suspend(struct device *dev)
|
|
{
|
|
int ret;
|
|
|
|
ret = pm_generic_runtime_suspend(dev);
|
|
if (ret) {
|
|
dev_err(dev, "failed to suspend device\n");
|
|
return ret;
|
|
}
|
|
|
|
ret = pm_clk_suspend(dev);
|
|
if (ret) {
|
|
dev_err(dev, "failed to suspend clock\n");
|
|
pm_generic_runtime_resume(dev);
|
|
return ret;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int sh_pm_runtime_resume(struct device *dev)
|
|
{
|
|
int ret;
|
|
|
|
ret = pm_clk_resume(dev);
|
|
if (ret) {
|
|
dev_err(dev, "failed to resume clock\n");
|
|
return ret;
|
|
}
|
|
|
|
return pm_generic_runtime_resume(dev);
|
|
}
|
|
|
|
static struct dev_pm_domain default_pm_domain = {
|
|
.ops = {
|
|
.runtime_suspend = sh_pm_runtime_suspend,
|
|
.runtime_resume = sh_pm_runtime_resume,
|
|
USE_PLATFORM_PM_SLEEP_OPS
|
|
},
|
|
};
|
|
|
|
#define DEFAULT_PM_DOMAIN_PTR (&default_pm_domain)
|
|
|
|
#else
|
|
|
|
#define DEFAULT_PM_DOMAIN_PTR NULL
|
|
|
|
#endif /* CONFIG_PM_RUNTIME */
|
|
|
|
static struct pm_clk_notifier_block platform_bus_notifier = {
|
|
.pm_domain = DEFAULT_PM_DOMAIN_PTR,
|
|
.con_ids = { NULL, },
|
|
};
|
|
|
|
static bool default_pm_on;
|
|
|
|
static int __init sh_pm_runtime_init(void)
|
|
{
|
|
if (IS_ENABLED(CONFIG_ARCH_SHMOBILE_MULTI)) {
|
|
if (!of_machine_is_compatible("renesas,emev2") &&
|
|
!of_machine_is_compatible("renesas,r7s72100") &&
|
|
!of_machine_is_compatible("renesas,r8a73a4") &&
|
|
!of_machine_is_compatible("renesas,r8a7740") &&
|
|
!of_machine_is_compatible("renesas,r8a7778") &&
|
|
!of_machine_is_compatible("renesas,r8a7779") &&
|
|
!of_machine_is_compatible("renesas,r8a7790") &&
|
|
!of_machine_is_compatible("renesas,r8a7791") &&
|
|
!of_machine_is_compatible("renesas,sh7372") &&
|
|
!of_machine_is_compatible("renesas,sh73a0"))
|
|
return 0;
|
|
}
|
|
|
|
default_pm_on = true;
|
|
pm_clk_add_notifier(&platform_bus_type, &platform_bus_notifier);
|
|
return 0;
|
|
}
|
|
core_initcall(sh_pm_runtime_init);
|
|
|
|
static int __init sh_pm_runtime_late_init(void)
|
|
{
|
|
if (default_pm_on)
|
|
pm_genpd_poweroff_unused();
|
|
return 0;
|
|
}
|
|
late_initcall(sh_pm_runtime_late_init);
|