Merge branch 'pm-domains'
* pm-domains: PM / shmobile: Make MTU2 driver use pm_genpd_dev_always_on() PM / shmobile: Make CMT driver use pm_genpd_dev_always_on() PM / shmobile: Make TMU driver use pm_genpd_dev_always_on() PM / Domains: Introduce "always on" device flag PM / Domains: Fix hibernation restore of devices, v2 PM / Domains: Fix handling of wakeup devices during system resume
This commit is contained in:
Коммит
62dc7c02c3
|
@ -1043,6 +1043,8 @@ void __init sh7372_add_standard_devices(void)
|
||||||
sh7372_add_device_to_domain(&sh7372_a4r, &veu2_device);
|
sh7372_add_device_to_domain(&sh7372_a4r, &veu2_device);
|
||||||
sh7372_add_device_to_domain(&sh7372_a4r, &veu3_device);
|
sh7372_add_device_to_domain(&sh7372_a4r, &veu3_device);
|
||||||
sh7372_add_device_to_domain(&sh7372_a4r, &jpu_device);
|
sh7372_add_device_to_domain(&sh7372_a4r, &jpu_device);
|
||||||
|
sh7372_add_device_to_domain(&sh7372_a4r, &tmu00_device);
|
||||||
|
sh7372_add_device_to_domain(&sh7372_a4r, &tmu01_device);
|
||||||
}
|
}
|
||||||
|
|
||||||
void __init sh7372_add_early_devices(void)
|
void __init sh7372_add_early_devices(void)
|
||||||
|
|
|
@ -366,7 +366,7 @@ static int pm_genpd_poweroff(struct generic_pm_domain *genpd)
|
||||||
not_suspended = 0;
|
not_suspended = 0;
|
||||||
list_for_each_entry(pdd, &genpd->dev_list, list_node)
|
list_for_each_entry(pdd, &genpd->dev_list, list_node)
|
||||||
if (pdd->dev->driver && (!pm_runtime_suspended(pdd->dev)
|
if (pdd->dev->driver && (!pm_runtime_suspended(pdd->dev)
|
||||||
|| pdd->dev->power.irq_safe))
|
|| pdd->dev->power.irq_safe || to_gpd_data(pdd)->always_on))
|
||||||
not_suspended++;
|
not_suspended++;
|
||||||
|
|
||||||
if (not_suspended > genpd->in_progress)
|
if (not_suspended > genpd->in_progress)
|
||||||
|
@ -503,6 +503,9 @@ static int pm_genpd_runtime_suspend(struct device *dev)
|
||||||
|
|
||||||
might_sleep_if(!genpd->dev_irq_safe);
|
might_sleep_if(!genpd->dev_irq_safe);
|
||||||
|
|
||||||
|
if (dev_gpd_data(dev)->always_on)
|
||||||
|
return -EBUSY;
|
||||||
|
|
||||||
stop_ok = genpd->gov ? genpd->gov->stop_ok : NULL;
|
stop_ok = genpd->gov ? genpd->gov->stop_ok : NULL;
|
||||||
if (stop_ok && !stop_ok(dev))
|
if (stop_ok && !stop_ok(dev))
|
||||||
return -EBUSY;
|
return -EBUSY;
|
||||||
|
@ -764,8 +767,10 @@ static int pm_genpd_prepare(struct device *dev)
|
||||||
|
|
||||||
genpd_acquire_lock(genpd);
|
genpd_acquire_lock(genpd);
|
||||||
|
|
||||||
if (genpd->prepared_count++ == 0)
|
if (genpd->prepared_count++ == 0) {
|
||||||
|
genpd->suspended_count = 0;
|
||||||
genpd->suspend_power_off = genpd->status == GPD_STATE_POWER_OFF;
|
genpd->suspend_power_off = genpd->status == GPD_STATE_POWER_OFF;
|
||||||
|
}
|
||||||
|
|
||||||
genpd_release_lock(genpd);
|
genpd_release_lock(genpd);
|
||||||
|
|
||||||
|
@ -857,7 +862,7 @@ static int pm_genpd_suspend_noirq(struct device *dev)
|
||||||
if (IS_ERR(genpd))
|
if (IS_ERR(genpd))
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
|
||||||
if (genpd->suspend_power_off
|
if (genpd->suspend_power_off || dev_gpd_data(dev)->always_on
|
||||||
|| (dev->power.wakeup_path && genpd_dev_active_wakeup(genpd, dev)))
|
|| (dev->power.wakeup_path && genpd_dev_active_wakeup(genpd, dev)))
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
|
@ -890,7 +895,8 @@ static int pm_genpd_resume_noirq(struct device *dev)
|
||||||
if (IS_ERR(genpd))
|
if (IS_ERR(genpd))
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
|
||||||
if (genpd->suspend_power_off)
|
if (genpd->suspend_power_off || dev_gpd_data(dev)->always_on
|
||||||
|
|| (dev->power.wakeup_path && genpd_dev_active_wakeup(genpd, dev)))
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -1009,7 +1015,8 @@ static int pm_genpd_freeze_noirq(struct device *dev)
|
||||||
if (IS_ERR(genpd))
|
if (IS_ERR(genpd))
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
|
||||||
return genpd->suspend_power_off ? 0 : genpd_stop_dev(genpd, dev);
|
return genpd->suspend_power_off || dev_gpd_data(dev)->always_on ?
|
||||||
|
0 : genpd_stop_dev(genpd, dev);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -1029,7 +1036,8 @@ static int pm_genpd_thaw_noirq(struct device *dev)
|
||||||
if (IS_ERR(genpd))
|
if (IS_ERR(genpd))
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
|
||||||
return genpd->suspend_power_off ? 0 : genpd_start_dev(genpd, dev);
|
return genpd->suspend_power_off || dev_gpd_data(dev)->always_on ?
|
||||||
|
0 : genpd_start_dev(genpd, dev);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -1096,22 +1104,32 @@ static int pm_genpd_restore_noirq(struct device *dev)
|
||||||
* Since all of the "noirq" callbacks are executed sequentially, it is
|
* Since all of the "noirq" callbacks are executed sequentially, it is
|
||||||
* guaranteed that this function will never run twice in parallel for
|
* guaranteed that this function will never run twice in parallel for
|
||||||
* the same PM domain, so it is not necessary to use locking here.
|
* the same PM domain, so it is not necessary to use locking here.
|
||||||
|
*
|
||||||
|
* At this point suspended_count == 0 means we are being run for the
|
||||||
|
* first time for the given domain in the present cycle.
|
||||||
*/
|
*/
|
||||||
genpd->status = GPD_STATE_POWER_OFF;
|
if (genpd->suspended_count++ == 0) {
|
||||||
if (genpd->suspend_power_off) {
|
|
||||||
/*
|
/*
|
||||||
* The boot kernel might put the domain into the power on state,
|
* The boot kernel might put the domain into arbitrary state,
|
||||||
* so make sure it really is powered off.
|
* so make it appear as powered off to pm_genpd_poweron(), so
|
||||||
|
* that it tries to power it on in case it was really off.
|
||||||
*/
|
*/
|
||||||
if (genpd->power_off)
|
genpd->status = GPD_STATE_POWER_OFF;
|
||||||
genpd->power_off(genpd);
|
if (genpd->suspend_power_off) {
|
||||||
return 0;
|
/*
|
||||||
|
* If the domain was off before the hibernation, make
|
||||||
|
* sure it will be off going forward.
|
||||||
|
*/
|
||||||
|
if (genpd->power_off)
|
||||||
|
genpd->power_off(genpd);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pm_genpd_poweron(genpd);
|
pm_genpd_poweron(genpd);
|
||||||
genpd->suspended_count--;
|
|
||||||
|
|
||||||
return genpd_start_dev(genpd, dev);
|
return dev_gpd_data(dev)->always_on ? 0 : genpd_start_dev(genpd, dev);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -1306,6 +1324,26 @@ int pm_genpd_remove_device(struct generic_pm_domain *genpd,
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* pm_genpd_dev_always_on - Set/unset the "always on" flag for a given device.
|
||||||
|
* @dev: Device to set/unset the flag for.
|
||||||
|
* @val: The new value of the device's "always on" flag.
|
||||||
|
*/
|
||||||
|
void pm_genpd_dev_always_on(struct device *dev, bool val)
|
||||||
|
{
|
||||||
|
struct pm_subsys_data *psd;
|
||||||
|
unsigned long flags;
|
||||||
|
|
||||||
|
spin_lock_irqsave(&dev->power.lock, flags);
|
||||||
|
|
||||||
|
psd = dev_to_psd(dev);
|
||||||
|
if (psd && psd->domain_data)
|
||||||
|
to_gpd_data(psd->domain_data)->always_on = val;
|
||||||
|
|
||||||
|
spin_unlock_irqrestore(&dev->power.lock, flags);
|
||||||
|
}
|
||||||
|
EXPORT_SYMBOL_GPL(pm_genpd_dev_always_on);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* pm_genpd_add_subdomain - Add a subdomain to an I/O PM domain.
|
* pm_genpd_add_subdomain - Add a subdomain to an I/O PM domain.
|
||||||
* @genpd: Master PM domain to add the subdomain to.
|
* @genpd: Master PM domain to add the subdomain to.
|
||||||
|
@ -1648,7 +1686,6 @@ void pm_genpd_init(struct generic_pm_domain *genpd,
|
||||||
genpd->poweroff_task = NULL;
|
genpd->poweroff_task = NULL;
|
||||||
genpd->resume_count = 0;
|
genpd->resume_count = 0;
|
||||||
genpd->device_count = 0;
|
genpd->device_count = 0;
|
||||||
genpd->suspended_count = 0;
|
|
||||||
genpd->max_off_time_ns = -1;
|
genpd->max_off_time_ns = -1;
|
||||||
genpd->domain.ops.runtime_suspend = pm_genpd_runtime_suspend;
|
genpd->domain.ops.runtime_suspend = pm_genpd_runtime_suspend;
|
||||||
genpd->domain.ops.runtime_resume = pm_genpd_runtime_resume;
|
genpd->domain.ops.runtime_resume = pm_genpd_runtime_resume;
|
||||||
|
|
|
@ -32,6 +32,7 @@
|
||||||
#include <linux/sh_timer.h>
|
#include <linux/sh_timer.h>
|
||||||
#include <linux/slab.h>
|
#include <linux/slab.h>
|
||||||
#include <linux/module.h>
|
#include <linux/module.h>
|
||||||
|
#include <linux/pm_domain.h>
|
||||||
|
|
||||||
struct sh_cmt_priv {
|
struct sh_cmt_priv {
|
||||||
void __iomem *mapbase;
|
void __iomem *mapbase;
|
||||||
|
@ -689,6 +690,9 @@ static int __devinit sh_cmt_probe(struct platform_device *pdev)
|
||||||
struct sh_cmt_priv *p = platform_get_drvdata(pdev);
|
struct sh_cmt_priv *p = platform_get_drvdata(pdev);
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
|
if (!is_early_platform_device(pdev))
|
||||||
|
pm_genpd_dev_always_on(&pdev->dev, true);
|
||||||
|
|
||||||
if (p) {
|
if (p) {
|
||||||
dev_info(&pdev->dev, "kept as earlytimer\n");
|
dev_info(&pdev->dev, "kept as earlytimer\n");
|
||||||
return 0;
|
return 0;
|
||||||
|
|
|
@ -31,6 +31,7 @@
|
||||||
#include <linux/sh_timer.h>
|
#include <linux/sh_timer.h>
|
||||||
#include <linux/slab.h>
|
#include <linux/slab.h>
|
||||||
#include <linux/module.h>
|
#include <linux/module.h>
|
||||||
|
#include <linux/pm_domain.h>
|
||||||
|
|
||||||
struct sh_mtu2_priv {
|
struct sh_mtu2_priv {
|
||||||
void __iomem *mapbase;
|
void __iomem *mapbase;
|
||||||
|
@ -306,6 +307,9 @@ static int __devinit sh_mtu2_probe(struct platform_device *pdev)
|
||||||
struct sh_mtu2_priv *p = platform_get_drvdata(pdev);
|
struct sh_mtu2_priv *p = platform_get_drvdata(pdev);
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
|
if (!is_early_platform_device(pdev))
|
||||||
|
pm_genpd_dev_always_on(&pdev->dev, true);
|
||||||
|
|
||||||
if (p) {
|
if (p) {
|
||||||
dev_info(&pdev->dev, "kept as earlytimer\n");
|
dev_info(&pdev->dev, "kept as earlytimer\n");
|
||||||
return 0;
|
return 0;
|
||||||
|
|
|
@ -32,6 +32,7 @@
|
||||||
#include <linux/sh_timer.h>
|
#include <linux/sh_timer.h>
|
||||||
#include <linux/slab.h>
|
#include <linux/slab.h>
|
||||||
#include <linux/module.h>
|
#include <linux/module.h>
|
||||||
|
#include <linux/pm_domain.h>
|
||||||
|
|
||||||
struct sh_tmu_priv {
|
struct sh_tmu_priv {
|
||||||
void __iomem *mapbase;
|
void __iomem *mapbase;
|
||||||
|
@ -410,6 +411,9 @@ static int __devinit sh_tmu_probe(struct platform_device *pdev)
|
||||||
struct sh_tmu_priv *p = platform_get_drvdata(pdev);
|
struct sh_tmu_priv *p = platform_get_drvdata(pdev);
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
|
if (!is_early_platform_device(pdev))
|
||||||
|
pm_genpd_dev_always_on(&pdev->dev, true);
|
||||||
|
|
||||||
if (p) {
|
if (p) {
|
||||||
dev_info(&pdev->dev, "kept as earlytimer\n");
|
dev_info(&pdev->dev, "kept as earlytimer\n");
|
||||||
return 0;
|
return 0;
|
||||||
|
|
|
@ -99,6 +99,7 @@ struct generic_pm_domain_data {
|
||||||
struct gpd_dev_ops ops;
|
struct gpd_dev_ops ops;
|
||||||
struct gpd_timing_data td;
|
struct gpd_timing_data td;
|
||||||
bool need_restore;
|
bool need_restore;
|
||||||
|
bool always_on;
|
||||||
};
|
};
|
||||||
|
|
||||||
#ifdef CONFIG_PM_GENERIC_DOMAINS
|
#ifdef CONFIG_PM_GENERIC_DOMAINS
|
||||||
|
@ -137,6 +138,7 @@ static inline int pm_genpd_of_add_device(struct device_node *genpd_node,
|
||||||
|
|
||||||
extern int pm_genpd_remove_device(struct generic_pm_domain *genpd,
|
extern int pm_genpd_remove_device(struct generic_pm_domain *genpd,
|
||||||
struct device *dev);
|
struct device *dev);
|
||||||
|
extern void pm_genpd_dev_always_on(struct device *dev, bool val);
|
||||||
extern int pm_genpd_add_subdomain(struct generic_pm_domain *genpd,
|
extern int pm_genpd_add_subdomain(struct generic_pm_domain *genpd,
|
||||||
struct generic_pm_domain *new_subdomain);
|
struct generic_pm_domain *new_subdomain);
|
||||||
extern int pm_genpd_remove_subdomain(struct generic_pm_domain *genpd,
|
extern int pm_genpd_remove_subdomain(struct generic_pm_domain *genpd,
|
||||||
|
@ -179,6 +181,7 @@ static inline int pm_genpd_remove_device(struct generic_pm_domain *genpd,
|
||||||
{
|
{
|
||||||
return -ENOSYS;
|
return -ENOSYS;
|
||||||
}
|
}
|
||||||
|
static inline void pm_genpd_dev_always_on(struct device *dev, bool val) {}
|
||||||
static inline int pm_genpd_add_subdomain(struct generic_pm_domain *genpd,
|
static inline int pm_genpd_add_subdomain(struct generic_pm_domain *genpd,
|
||||||
struct generic_pm_domain *new_sd)
|
struct generic_pm_domain *new_sd)
|
||||||
{
|
{
|
||||||
|
|
Загрузка…
Ссылка в новой задаче