Merge branch 'pm-domains'
* pm-domains: (32 commits) PM / Domains: Rename cpu_data to cpuidle_data PM / Domains: Move dev_pm_domain_attach|detach() to pm_domain.h PM / Domains: Remove legacy API for adding devices through DT PM / Domains: Add genpd attach/detach callbacks PM / Domains: add debugfs listing of struct generic_pm_domain-s ACPI / PM: Convert acpi_dev_pm_detach() into a static function ARM: exynos: Move to generic PM domain DT bindings amba: Add support for attach/detach of PM domains spi: core: Convert to dev_pm_domain_attach|detach() mmc: sdio: Convert to dev_pm_domain_attach|detach() i2c: core: Convert to dev_pm_domain_attach|detach() drivercore / platform: Convert to dev_pm_domain_attach|detach() PM / Domains: Add APIs to attach/detach a PM domain for a device PM / Domains: Add generic OF-based PM domain look-up ACPI / PM: Assign the ->detach() callback when attaching the PM domain PM / Domains: Add a detach callback to the struct dev_pm_domain PM / domains: Spelling s/domian/domain/ PM / domains: Keep declaration of dev_power_governors together PM / domains: Remove default_stop_ok() API drivers: sh: Leave disabling of unused PM domains to genpd ...
This commit is contained in:
commit
49a09c9ab0
33 changed files with 771 additions and 605 deletions
|
@ -8,6 +8,8 @@ Required Properties:
|
|||
* samsung,exynos4210-pd - for exynos4210 type power domain.
|
||||
- reg: physical base address of the controller and length of memory mapped
|
||||
region.
|
||||
- #power-domain-cells: number of cells in power domain specifier;
|
||||
must be 0.
|
||||
|
||||
Optional Properties:
|
||||
- clocks: List of clock handles. The parent clocks of the input clocks to the
|
||||
|
@ -29,6 +31,7 @@ Example:
|
|||
lcd0: power-domain-lcd0 {
|
||||
compatible = "samsung,exynos4210-pd";
|
||||
reg = <0x10023C00 0x10>;
|
||||
#power-domain-cells = <0>;
|
||||
};
|
||||
|
||||
mfc_pd: power-domain@10044060 {
|
||||
|
@ -37,12 +40,8 @@ Example:
|
|||
clocks = <&clock CLK_FIN_PLL>, <&clock CLK_MOUT_SW_ACLK333>,
|
||||
<&clock CLK_MOUT_USER_ACLK333>;
|
||||
clock-names = "oscclk", "pclk0", "clk0";
|
||||
#power-domain-cells = <0>;
|
||||
};
|
||||
|
||||
Example of the node using power domain:
|
||||
|
||||
node {
|
||||
/* ... */
|
||||
samsung,power-domain = <&lcd0>;
|
||||
/* ... */
|
||||
};
|
||||
See Documentation/devicetree/bindings/power/power_domain.txt for description
|
||||
of consumer-side bindings.
|
||||
|
|
49
Documentation/devicetree/bindings/power/power_domain.txt
Normal file
49
Documentation/devicetree/bindings/power/power_domain.txt
Normal file
|
@ -0,0 +1,49 @@
|
|||
* Generic PM domains
|
||||
|
||||
System on chip designs are often divided into multiple PM domains that can be
|
||||
used for power gating of selected IP blocks for power saving by reduced leakage
|
||||
current.
|
||||
|
||||
This device tree binding can be used to bind PM domain consumer devices with
|
||||
their PM domains provided by PM domain providers. A PM domain provider can be
|
||||
represented by any node in the device tree and can provide one or more PM
|
||||
domains. A consumer node can refer to the provider by a phandle and a set of
|
||||
phandle arguments (so called PM domain specifiers) of length specified by the
|
||||
#power-domain-cells property in the PM domain provider node.
|
||||
|
||||
==PM domain providers==
|
||||
|
||||
Required properties:
|
||||
- #power-domain-cells : Number of cells in a PM domain specifier;
|
||||
Typically 0 for nodes representing a single PM domain and 1 for nodes
|
||||
providing multiple PM domains (e.g. power controllers), but can be any value
|
||||
as specified by device tree binding documentation of particular provider.
|
||||
|
||||
Example:
|
||||
|
||||
power: power-controller@12340000 {
|
||||
compatible = "foo,power-controller";
|
||||
reg = <0x12340000 0x1000>;
|
||||
#power-domain-cells = <1>;
|
||||
};
|
||||
|
||||
The node above defines a power controller that is a PM domain provider and
|
||||
expects one cell as its phandle argument.
|
||||
|
||||
==PM domain consumers==
|
||||
|
||||
Required properties:
|
||||
- power-domains : A phandle and PM domain specifier as defined by bindings of
|
||||
the power controller specified by phandle.
|
||||
|
||||
Example:
|
||||
|
||||
leaky-device@12350000 {
|
||||
compatible = "foo,i-leak-current";
|
||||
reg = <0x12350000 0x1000>;
|
||||
power-domains = <&power 0>;
|
||||
};
|
||||
|
||||
The node above defines a typical PM domain consumer device, which is located
|
||||
inside a PM domain with index 0 of a power controller represented by a node
|
||||
with the label "power".
|
|
@ -193,7 +193,6 @@ static void __init exynos_init_late(void)
|
|||
/* to be supported later */
|
||||
return;
|
||||
|
||||
pm_genpd_poweroff_unused();
|
||||
exynos_pm_init();
|
||||
}
|
||||
|
||||
|
|
|
@ -105,78 +105,6 @@ static int exynos_pd_power_off(struct generic_pm_domain *domain)
|
|||
return exynos_pd_power(domain, false);
|
||||
}
|
||||
|
||||
static void exynos_add_device_to_domain(struct exynos_pm_domain *pd,
|
||||
struct device *dev)
|
||||
{
|
||||
int ret;
|
||||
|
||||
dev_dbg(dev, "adding to power domain %s\n", pd->pd.name);
|
||||
|
||||
while (1) {
|
||||
ret = pm_genpd_add_device(&pd->pd, dev);
|
||||
if (ret != -EAGAIN)
|
||||
break;
|
||||
cond_resched();
|
||||
}
|
||||
|
||||
pm_genpd_dev_need_restore(dev, true);
|
||||
}
|
||||
|
||||
static void exynos_remove_device_from_domain(struct device *dev)
|
||||
{
|
||||
struct generic_pm_domain *genpd = dev_to_genpd(dev);
|
||||
int ret;
|
||||
|
||||
dev_dbg(dev, "removing from power domain %s\n", genpd->name);
|
||||
|
||||
while (1) {
|
||||
ret = pm_genpd_remove_device(genpd, dev);
|
||||
if (ret != -EAGAIN)
|
||||
break;
|
||||
cond_resched();
|
||||
}
|
||||
}
|
||||
|
||||
static void exynos_read_domain_from_dt(struct device *dev)
|
||||
{
|
||||
struct platform_device *pd_pdev;
|
||||
struct exynos_pm_domain *pd;
|
||||
struct device_node *node;
|
||||
|
||||
node = of_parse_phandle(dev->of_node, "samsung,power-domain", 0);
|
||||
if (!node)
|
||||
return;
|
||||
pd_pdev = of_find_device_by_node(node);
|
||||
if (!pd_pdev)
|
||||
return;
|
||||
pd = platform_get_drvdata(pd_pdev);
|
||||
exynos_add_device_to_domain(pd, dev);
|
||||
}
|
||||
|
||||
static int exynos_pm_notifier_call(struct notifier_block *nb,
|
||||
unsigned long event, void *data)
|
||||
{
|
||||
struct device *dev = data;
|
||||
|
||||
switch (event) {
|
||||
case BUS_NOTIFY_BIND_DRIVER:
|
||||
if (dev->of_node)
|
||||
exynos_read_domain_from_dt(dev);
|
||||
|
||||
break;
|
||||
|
||||
case BUS_NOTIFY_UNBOUND_DRIVER:
|
||||
exynos_remove_device_from_domain(dev);
|
||||
|
||||
break;
|
||||
}
|
||||
return NOTIFY_DONE;
|
||||
}
|
||||
|
||||
static struct notifier_block platform_nb = {
|
||||
.notifier_call = exynos_pm_notifier_call,
|
||||
};
|
||||
|
||||
static __init int exynos4_pm_init_power_domain(void)
|
||||
{
|
||||
struct platform_device *pdev;
|
||||
|
@ -202,7 +130,6 @@ static __init int exynos4_pm_init_power_domain(void)
|
|||
pd->base = of_iomap(np, 0);
|
||||
pd->pd.power_off = exynos_pd_power_off;
|
||||
pd->pd.power_on = exynos_pd_power_on;
|
||||
pd->pd.of_node = np;
|
||||
|
||||
pd->oscclk = clk_get(dev, "oscclk");
|
||||
if (IS_ERR(pd->oscclk))
|
||||
|
@ -228,15 +155,12 @@ static __init int exynos4_pm_init_power_domain(void)
|
|||
clk_put(pd->oscclk);
|
||||
|
||||
no_clk:
|
||||
platform_set_drvdata(pdev, pd);
|
||||
|
||||
on = __raw_readl(pd->base + 0x4) & INT_LOCAL_PWR_EN;
|
||||
|
||||
pm_genpd_init(&pd->pd, NULL, !on);
|
||||
of_genpd_add_provider_simple(np, &pd->pd);
|
||||
}
|
||||
|
||||
bus_register_notifier(&platform_bus_type, &platform_nb);
|
||||
|
||||
return 0;
|
||||
}
|
||||
arch_initcall(exynos4_pm_init_power_domain);
|
||||
|
|
|
@ -440,8 +440,3 @@ void s3c64xx_restart(enum reboot_mode mode, const char *cmd)
|
|||
/* if all else fails, or mode was for soft, jump to 0 */
|
||||
soft_restart(0);
|
||||
}
|
||||
|
||||
void __init s3c64xx_init_late(void)
|
||||
{
|
||||
s3c64xx_pm_late_initcall();
|
||||
}
|
||||
|
|
|
@ -23,7 +23,6 @@ void s3c64xx_init_irq(u32 vic0, u32 vic1);
|
|||
void s3c64xx_init_io(struct map_desc *mach_desc, int size);
|
||||
|
||||
void s3c64xx_restart(enum reboot_mode mode, const char *cmd);
|
||||
void s3c64xx_init_late(void);
|
||||
|
||||
void s3c64xx_clk_init(struct device_node *np, unsigned long xtal_f,
|
||||
unsigned long xusbxti_f, bool is_s3c6400, void __iomem *reg_base);
|
||||
|
@ -52,12 +51,6 @@ extern void s3c6410_map_io(void);
|
|||
#define s3c6410_init NULL
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_PM
|
||||
int __init s3c64xx_pm_late_initcall(void);
|
||||
#else
|
||||
static inline int s3c64xx_pm_late_initcall(void) { return 0; }
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_S3C64XX_PL080
|
||||
extern struct pl08x_platform_data s3c64xx_dma0_plat_data;
|
||||
extern struct pl08x_platform_data s3c64xx_dma1_plat_data;
|
||||
|
|
|
@ -233,7 +233,6 @@ MACHINE_START(ANW6410, "A&W6410")
|
|||
.init_irq = s3c6410_init_irq,
|
||||
.map_io = anw6410_map_io,
|
||||
.init_machine = anw6410_machine_init,
|
||||
.init_late = s3c64xx_init_late,
|
||||
.init_time = samsung_timer_init,
|
||||
.restart = s3c64xx_restart,
|
||||
MACHINE_END
|
||||
|
|
|
@ -857,7 +857,6 @@ MACHINE_START(WLF_CRAGG_6410, "Wolfson Cragganmore 6410")
|
|||
.init_irq = s3c6410_init_irq,
|
||||
.map_io = crag6410_map_io,
|
||||
.init_machine = crag6410_machine_init,
|
||||
.init_late = s3c64xx_init_late,
|
||||
.init_time = samsung_timer_init,
|
||||
.restart = s3c64xx_restart,
|
||||
MACHINE_END
|
||||
|
|
|
@ -277,7 +277,6 @@ MACHINE_START(HMT, "Airgoo-HMT")
|
|||
.init_irq = s3c6410_init_irq,
|
||||
.map_io = hmt_map_io,
|
||||
.init_machine = hmt_machine_init,
|
||||
.init_late = s3c64xx_init_late,
|
||||
.init_time = samsung_timer_init,
|
||||
.restart = s3c64xx_restart,
|
||||
MACHINE_END
|
||||
|
|
|
@ -366,7 +366,6 @@ MACHINE_START(MINI6410, "MINI6410")
|
|||
.init_irq = s3c6410_init_irq,
|
||||
.map_io = mini6410_map_io,
|
||||
.init_machine = mini6410_machine_init,
|
||||
.init_late = s3c64xx_init_late,
|
||||
.init_time = samsung_timer_init,
|
||||
.restart = s3c64xx_restart,
|
||||
MACHINE_END
|
||||
|
|
|
@ -103,7 +103,6 @@ MACHINE_START(NCP, "NCP")
|
|||
.init_irq = s3c6410_init_irq,
|
||||
.map_io = ncp_map_io,
|
||||
.init_machine = ncp_machine_init,
|
||||
.init_late = s3c64xx_init_late,
|
||||
.init_time = samsung_timer_init,
|
||||
.restart = s3c64xx_restart,
|
||||
MACHINE_END
|
||||
|
|
|
@ -335,7 +335,6 @@ MACHINE_START(REAL6410, "REAL6410")
|
|||
.init_irq = s3c6410_init_irq,
|
||||
.map_io = real6410_map_io,
|
||||
.init_machine = real6410_machine_init,
|
||||
.init_late = s3c64xx_init_late,
|
||||
.init_time = samsung_timer_init,
|
||||
.restart = s3c64xx_restart,
|
||||
MACHINE_END
|
||||
|
|
|
@ -156,7 +156,6 @@ MACHINE_START(SMARTQ5, "SmartQ 5")
|
|||
.init_irq = s3c6410_init_irq,
|
||||
.map_io = smartq_map_io,
|
||||
.init_machine = smartq5_machine_init,
|
||||
.init_late = s3c64xx_init_late,
|
||||
.init_time = samsung_timer_init,
|
||||
.restart = s3c64xx_restart,
|
||||
MACHINE_END
|
||||
|
|
|
@ -172,7 +172,6 @@ MACHINE_START(SMARTQ7, "SmartQ 7")
|
|||
.init_irq = s3c6410_init_irq,
|
||||
.map_io = smartq_map_io,
|
||||
.init_machine = smartq7_machine_init,
|
||||
.init_late = s3c64xx_init_late,
|
||||
.init_time = samsung_timer_init,
|
||||
.restart = s3c64xx_restart,
|
||||
MACHINE_END
|
||||
|
|
|
@ -92,7 +92,6 @@ MACHINE_START(SMDK6400, "SMDK6400")
|
|||
.init_irq = s3c6400_init_irq,
|
||||
.map_io = smdk6400_map_io,
|
||||
.init_machine = smdk6400_machine_init,
|
||||
.init_late = s3c64xx_init_late,
|
||||
.init_time = samsung_timer_init,
|
||||
.restart = s3c64xx_restart,
|
||||
MACHINE_END
|
||||
|
|
|
@ -705,7 +705,6 @@ MACHINE_START(SMDK6410, "SMDK6410")
|
|||
.init_irq = s3c6410_init_irq,
|
||||
.map_io = smdk6410_map_io,
|
||||
.init_machine = smdk6410_machine_init,
|
||||
.init_late = s3c64xx_init_late,
|
||||
.init_time = samsung_timer_init,
|
||||
.restart = s3c64xx_restart,
|
||||
MACHINE_END
|
||||
|
|
|
@ -347,10 +347,3 @@ static __init int s3c64xx_pm_initcall(void)
|
|||
return 0;
|
||||
}
|
||||
arch_initcall(s3c64xx_pm_initcall);
|
||||
|
||||
int __init s3c64xx_pm_late_initcall(void)
|
||||
{
|
||||
pm_genpd_poweroff_unused();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -87,7 +87,6 @@ static void r8a7779_init_pm_domain(struct r8a7779_pm_domain *r8a7779_pd)
|
|||
genpd->dev_ops.stop = pm_clk_suspend;
|
||||
genpd->dev_ops.start = pm_clk_resume;
|
||||
genpd->dev_ops.active_wakeup = pd_active_wakeup;
|
||||
genpd->dev_irq_safe = true;
|
||||
genpd->power_off = pd_power_down;
|
||||
genpd->power_on = pd_power_up;
|
||||
|
||||
|
|
|
@ -111,7 +111,6 @@ static void rmobile_init_pm_domain(struct rmobile_pm_domain *rmobile_pd)
|
|||
genpd->dev_ops.stop = pm_clk_suspend;
|
||||
genpd->dev_ops.start = pm_clk_resume;
|
||||
genpd->dev_ops.active_wakeup = rmobile_pd_active_wakeup;
|
||||
genpd->dev_irq_safe = true;
|
||||
genpd->power_off = rmobile_pd_power_down;
|
||||
genpd->power_on = rmobile_pd_power_up;
|
||||
__rmobile_pd_power_up(rmobile_pd, false);
|
||||
|
|
|
@ -1040,6 +1040,40 @@ static struct dev_pm_domain acpi_general_pm_domain = {
|
|||
},
|
||||
};
|
||||
|
||||
/**
|
||||
* acpi_dev_pm_detach - Remove ACPI power management from the device.
|
||||
* @dev: Device to take care of.
|
||||
* @power_off: Whether or not to try to remove power from the device.
|
||||
*
|
||||
* Remove the device from the general ACPI PM domain and remove its wakeup
|
||||
* notifier. If @power_off is set, additionally remove power from the device if
|
||||
* possible.
|
||||
*
|
||||
* Callers must ensure proper synchronization of this function with power
|
||||
* management callbacks.
|
||||
*/
|
||||
static void acpi_dev_pm_detach(struct device *dev, bool power_off)
|
||||
{
|
||||
struct acpi_device *adev = ACPI_COMPANION(dev);
|
||||
|
||||
if (adev && dev->pm_domain == &acpi_general_pm_domain) {
|
||||
dev->pm_domain = NULL;
|
||||
acpi_remove_pm_notifier(adev);
|
||||
if (power_off) {
|
||||
/*
|
||||
* If the device's PM QoS resume latency limit or flags
|
||||
* have been exposed to user space, they have to be
|
||||
* hidden at this point, so that they don't affect the
|
||||
* choice of the low-power state to put the device into.
|
||||
*/
|
||||
dev_pm_qos_hide_latency_limit(dev);
|
||||
dev_pm_qos_hide_flags(dev);
|
||||
acpi_device_wakeup(adev, ACPI_STATE_S0, false);
|
||||
acpi_dev_pm_low_power(dev, adev, ACPI_STATE_S0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* acpi_dev_pm_attach - Prepare device for ACPI power management.
|
||||
* @dev: Device to prepare.
|
||||
|
@ -1072,42 +1106,9 @@ int acpi_dev_pm_attach(struct device *dev, bool power_on)
|
|||
acpi_dev_pm_full_power(adev);
|
||||
acpi_device_wakeup(adev, ACPI_STATE_S0, false);
|
||||
}
|
||||
|
||||
dev->pm_domain->detach = acpi_dev_pm_detach;
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(acpi_dev_pm_attach);
|
||||
|
||||
/**
|
||||
* acpi_dev_pm_detach - Remove ACPI power management from the device.
|
||||
* @dev: Device to take care of.
|
||||
* @power_off: Whether or not to try to remove power from the device.
|
||||
*
|
||||
* Remove the device from the general ACPI PM domain and remove its wakeup
|
||||
* notifier. If @power_off is set, additionally remove power from the device if
|
||||
* possible.
|
||||
*
|
||||
* Callers must ensure proper synchronization of this function with power
|
||||
* management callbacks.
|
||||
*/
|
||||
void acpi_dev_pm_detach(struct device *dev, bool power_off)
|
||||
{
|
||||
struct acpi_device *adev = ACPI_COMPANION(dev);
|
||||
|
||||
if (adev && dev->pm_domain == &acpi_general_pm_domain) {
|
||||
dev->pm_domain = NULL;
|
||||
acpi_remove_pm_notifier(adev);
|
||||
if (power_off) {
|
||||
/*
|
||||
* If the device's PM QoS resume latency limit or flags
|
||||
* have been exposed to user space, they have to be
|
||||
* hidden at this point, so that they don't affect the
|
||||
* choice of the low-power state to put the device into.
|
||||
*/
|
||||
dev_pm_qos_hide_latency_limit(dev);
|
||||
dev_pm_qos_hide_flags(dev);
|
||||
acpi_device_wakeup(adev, ACPI_STATE_S0, false);
|
||||
acpi_dev_pm_low_power(dev, adev, ACPI_STATE_S0);
|
||||
}
|
||||
}
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(acpi_dev_pm_detach);
|
||||
#endif /* CONFIG_PM */
|
||||
|
|
|
@ -15,6 +15,7 @@
|
|||
#include <linux/io.h>
|
||||
#include <linux/pm.h>
|
||||
#include <linux/pm_runtime.h>
|
||||
#include <linux/pm_domain.h>
|
||||
#include <linux/amba/bus.h>
|
||||
#include <linux/sizes.h>
|
||||
|
||||
|
@ -182,10 +183,16 @@ static int amba_probe(struct device *dev)
|
|||
int ret;
|
||||
|
||||
do {
|
||||
ret = amba_get_enable_pclk(pcdev);
|
||||
if (ret)
|
||||
ret = dev_pm_domain_attach(dev, true);
|
||||
if (ret == -EPROBE_DEFER)
|
||||
break;
|
||||
|
||||
ret = amba_get_enable_pclk(pcdev);
|
||||
if (ret) {
|
||||
dev_pm_domain_detach(dev, true);
|
||||
break;
|
||||
}
|
||||
|
||||
pm_runtime_get_noresume(dev);
|
||||
pm_runtime_set_active(dev);
|
||||
pm_runtime_enable(dev);
|
||||
|
@ -199,6 +206,7 @@ static int amba_probe(struct device *dev)
|
|||
pm_runtime_put_noidle(dev);
|
||||
|
||||
amba_put_disable_pclk(pcdev);
|
||||
dev_pm_domain_detach(dev, true);
|
||||
} while (0);
|
||||
|
||||
return ret;
|
||||
|
@ -220,6 +228,7 @@ static int amba_remove(struct device *dev)
|
|||
pm_runtime_put_noidle(dev);
|
||||
|
||||
amba_put_disable_pclk(pcdev);
|
||||
dev_pm_domain_detach(dev, true);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
|
|
@ -21,6 +21,7 @@
|
|||
#include <linux/err.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/pm_runtime.h>
|
||||
#include <linux/pm_domain.h>
|
||||
#include <linux/idr.h>
|
||||
#include <linux/acpi.h>
|
||||
#include <linux/clk/clk-conf.h>
|
||||
|
@ -506,11 +507,12 @@ static int platform_drv_probe(struct device *_dev)
|
|||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
acpi_dev_pm_attach(_dev, true);
|
||||
|
||||
ret = drv->probe(dev);
|
||||
if (ret)
|
||||
acpi_dev_pm_detach(_dev, true);
|
||||
ret = dev_pm_domain_attach(_dev, true);
|
||||
if (ret != -EPROBE_DEFER) {
|
||||
ret = drv->probe(dev);
|
||||
if (ret)
|
||||
dev_pm_domain_detach(_dev, true);
|
||||
}
|
||||
|
||||
if (drv->prevent_deferred_probe && ret == -EPROBE_DEFER) {
|
||||
dev_warn(_dev, "probe deferral not supported\n");
|
||||
|
@ -532,7 +534,7 @@ static int platform_drv_remove(struct device *_dev)
|
|||
int ret;
|
||||
|
||||
ret = drv->remove(dev);
|
||||
acpi_dev_pm_detach(_dev, true);
|
||||
dev_pm_domain_detach(_dev, true);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
@ -543,7 +545,7 @@ static void platform_drv_shutdown(struct device *_dev)
|
|||
struct platform_device *dev = to_platform_device(_dev);
|
||||
|
||||
drv->shutdown(dev);
|
||||
acpi_dev_pm_detach(_dev, true);
|
||||
dev_pm_domain_detach(_dev, true);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -11,6 +11,8 @@
|
|||
#include <linux/export.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/pm_clock.h>
|
||||
#include <linux/acpi.h>
|
||||
#include <linux/pm_domain.h>
|
||||
|
||||
/**
|
||||
* dev_pm_get_subsys_data - Create or refcount power.subsys_data for device.
|
||||
|
@ -82,3 +84,53 @@ int dev_pm_put_subsys_data(struct device *dev)
|
|||
return ret;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(dev_pm_put_subsys_data);
|
||||
|
||||
/**
|
||||
* dev_pm_domain_attach - Attach a device to its PM domain.
|
||||
* @dev: Device to attach.
|
||||
* @power_on: Used to indicate whether we should power on the device.
|
||||
*
|
||||
* The @dev may only be attached to a single PM domain. By iterating through
|
||||
* the available alternatives we try to find a valid PM domain for the device.
|
||||
* As attachment succeeds, the ->detach() callback in the struct dev_pm_domain
|
||||
* should be assigned by the corresponding attach function.
|
||||
*
|
||||
* This function should typically be invoked from subsystem level code during
|
||||
* the probe phase. Especially for those that holds devices which requires
|
||||
* power management through PM domains.
|
||||
*
|
||||
* Callers must ensure proper synchronization of this function with power
|
||||
* management callbacks.
|
||||
*
|
||||
* Returns 0 on successfully attached PM domain or negative error code.
|
||||
*/
|
||||
int dev_pm_domain_attach(struct device *dev, bool power_on)
|
||||
{
|
||||
int ret;
|
||||
|
||||
ret = acpi_dev_pm_attach(dev, power_on);
|
||||
if (ret)
|
||||
ret = genpd_dev_pm_attach(dev);
|
||||
|
||||
return ret;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(dev_pm_domain_attach);
|
||||
|
||||
/**
|
||||
* dev_pm_domain_detach - Detach a device from its PM domain.
|
||||
* @dev: Device to attach.
|
||||
* @power_off: Used to indicate whether we should power off the device.
|
||||
*
|
||||
* This functions will reverse the actions from dev_pm_domain_attach() and thus
|
||||
* try to detach the @dev from its PM domain. Typically it should be invoked
|
||||
* from subsystem level code during the remove phase.
|
||||
*
|
||||
* Callers must ensure proper synchronization of this function with power
|
||||
* management callbacks.
|
||||
*/
|
||||
void dev_pm_domain_detach(struct device *dev, bool power_off)
|
||||
{
|
||||
if (dev->pm_domain && dev->pm_domain->detach)
|
||||
dev->pm_domain->detach(dev, power_off);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(dev_pm_domain_detach);
|
||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -42,7 +42,7 @@ static int dev_update_qos_constraint(struct device *dev, void *data)
|
|||
* default_stop_ok - Default PM domain governor routine for stopping devices.
|
||||
* @dev: Device to check.
|
||||
*/
|
||||
bool default_stop_ok(struct device *dev)
|
||||
static bool default_stop_ok(struct device *dev)
|
||||
{
|
||||
struct gpd_timing_data *td = &dev_gpd_data(dev)->td;
|
||||
unsigned long flags;
|
||||
|
@ -229,10 +229,7 @@ static bool always_on_power_down_ok(struct dev_pm_domain *domain)
|
|||
|
||||
#else /* !CONFIG_PM_RUNTIME */
|
||||
|
||||
bool default_stop_ok(struct device *dev)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
static inline bool default_stop_ok(struct device *dev) { return false; }
|
||||
|
||||
#define default_power_down_ok NULL
|
||||
#define always_on_power_down_ok NULL
|
||||
|
|
|
@ -50,6 +50,7 @@
|
|||
#include <linux/irqflags.h>
|
||||
#include <linux/rwsem.h>
|
||||
#include <linux/pm_runtime.h>
|
||||
#include <linux/pm_domain.h>
|
||||
#include <linux/acpi.h>
|
||||
#include <linux/jump_label.h>
|
||||
#include <asm/uaccess.h>
|
||||
|
@ -643,10 +644,13 @@ static int i2c_device_probe(struct device *dev)
|
|||
if (status < 0)
|
||||
return status;
|
||||
|
||||
acpi_dev_pm_attach(&client->dev, true);
|
||||
status = driver->probe(client, i2c_match_id(driver->id_table, client));
|
||||
if (status)
|
||||
acpi_dev_pm_detach(&client->dev, true);
|
||||
status = dev_pm_domain_attach(&client->dev, true);
|
||||
if (status != -EPROBE_DEFER) {
|
||||
status = driver->probe(client, i2c_match_id(driver->id_table,
|
||||
client));
|
||||
if (status)
|
||||
dev_pm_domain_detach(&client->dev, true);
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
|
@ -666,7 +670,7 @@ static int i2c_device_remove(struct device *dev)
|
|||
status = driver->remove(client);
|
||||
}
|
||||
|
||||
acpi_dev_pm_detach(&client->dev, true);
|
||||
dev_pm_domain_detach(&client->dev, true);
|
||||
return status;
|
||||
}
|
||||
|
||||
|
|
|
@ -16,6 +16,7 @@
|
|||
#include <linux/export.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/pm_runtime.h>
|
||||
#include <linux/pm_domain.h>
|
||||
#include <linux/acpi.h>
|
||||
|
||||
#include <linux/mmc/card.h>
|
||||
|
@ -315,7 +316,7 @@ int sdio_add_func(struct sdio_func *func)
|
|||
ret = device_add(&func->dev);
|
||||
if (ret == 0) {
|
||||
sdio_func_set_present(func);
|
||||
acpi_dev_pm_attach(&func->dev, false);
|
||||
dev_pm_domain_attach(&func->dev, false);
|
||||
}
|
||||
|
||||
return ret;
|
||||
|
@ -332,7 +333,7 @@ void sdio_remove_func(struct sdio_func *func)
|
|||
if (!sdio_func_present(func))
|
||||
return;
|
||||
|
||||
acpi_dev_pm_detach(&func->dev, false);
|
||||
dev_pm_domain_detach(&func->dev, false);
|
||||
device_del(&func->dev);
|
||||
put_device(&func->dev);
|
||||
}
|
||||
|
|
|
@ -75,8 +75,6 @@ static struct pm_clk_notifier_block platform_bus_notifier = {
|
|||
.con_ids = { NULL, },
|
||||
};
|
||||
|
||||
static bool default_pm_on;
|
||||
|
||||
static int __init sh_pm_runtime_init(void)
|
||||
{
|
||||
if (IS_ENABLED(CONFIG_ARCH_SHMOBILE_MULTI)) {
|
||||
|
@ -96,16 +94,7 @@ static int __init sh_pm_runtime_init(void)
|
|||
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);
|
||||
|
|
|
@ -35,6 +35,7 @@
|
|||
#include <linux/spi/spi.h>
|
||||
#include <linux/of_gpio.h>
|
||||
#include <linux/pm_runtime.h>
|
||||
#include <linux/pm_domain.h>
|
||||
#include <linux/export.h>
|
||||
#include <linux/sched/rt.h>
|
||||
#include <linux/delay.h>
|
||||
|
@ -264,10 +265,12 @@ static int spi_drv_probe(struct device *dev)
|
|||
if (ret)
|
||||
return ret;
|
||||
|
||||
acpi_dev_pm_attach(dev, true);
|
||||
ret = sdrv->probe(to_spi_device(dev));
|
||||
if (ret)
|
||||
acpi_dev_pm_detach(dev, true);
|
||||
ret = dev_pm_domain_attach(dev, true);
|
||||
if (ret != -EPROBE_DEFER) {
|
||||
ret = sdrv->probe(to_spi_device(dev));
|
||||
if (ret)
|
||||
dev_pm_domain_detach(dev, true);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
@ -278,7 +281,7 @@ static int spi_drv_remove(struct device *dev)
|
|||
int ret;
|
||||
|
||||
ret = sdrv->remove(to_spi_device(dev));
|
||||
acpi_dev_pm_detach(dev, true);
|
||||
dev_pm_domain_detach(dev, true);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
|
|
@ -587,7 +587,6 @@ static inline int acpi_subsys_freeze(struct device *dev) { return 0; }
|
|||
#if defined(CONFIG_ACPI) && defined(CONFIG_PM)
|
||||
struct acpi_device *acpi_dev_pm_get_node(struct device *dev);
|
||||
int acpi_dev_pm_attach(struct device *dev, bool power_on);
|
||||
void acpi_dev_pm_detach(struct device *dev, bool power_off);
|
||||
#else
|
||||
static inline struct acpi_device *acpi_dev_pm_get_node(struct device *dev)
|
||||
{
|
||||
|
@ -597,7 +596,6 @@ static inline int acpi_dev_pm_attach(struct device *dev, bool power_on)
|
|||
{
|
||||
return -ENODEV;
|
||||
}
|
||||
static inline void acpi_dev_pm_detach(struct device *dev, bool power_off) {}
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_ACPI
|
||||
|
|
|
@ -619,6 +619,7 @@ extern int dev_pm_put_subsys_data(struct device *dev);
|
|||
*/
|
||||
struct dev_pm_domain {
|
||||
struct dev_pm_ops ops;
|
||||
void (*detach)(struct device *dev, bool power_off);
|
||||
};
|
||||
|
||||
/*
|
||||
|
|
|
@ -35,18 +35,10 @@ struct gpd_dev_ops {
|
|||
int (*stop)(struct device *dev);
|
||||
int (*save_state)(struct device *dev);
|
||||
int (*restore_state)(struct device *dev);
|
||||
int (*suspend)(struct device *dev);
|
||||
int (*suspend_late)(struct device *dev);
|
||||
int (*resume_early)(struct device *dev);
|
||||
int (*resume)(struct device *dev);
|
||||
int (*freeze)(struct device *dev);
|
||||
int (*freeze_late)(struct device *dev);
|
||||
int (*thaw_early)(struct device *dev);
|
||||
int (*thaw)(struct device *dev);
|
||||
bool (*active_wakeup)(struct device *dev);
|
||||
};
|
||||
|
||||
struct gpd_cpu_data {
|
||||
struct gpd_cpuidle_data {
|
||||
unsigned int saved_exit_latency;
|
||||
struct cpuidle_state *idle_state;
|
||||
};
|
||||
|
@ -71,7 +63,6 @@ struct generic_pm_domain {
|
|||
unsigned int suspended_count; /* System suspend device counter */
|
||||
unsigned int prepared_count; /* Suspend counter of prepared devices */
|
||||
bool suspend_power_off; /* Power status before system suspend */
|
||||
bool dev_irq_safe; /* Device callbacks are IRQ-safe */
|
||||
int (*power_off)(struct generic_pm_domain *domain);
|
||||
s64 power_off_latency_ns;
|
||||
int (*power_on)(struct generic_pm_domain *domain);
|
||||
|
@ -80,8 +71,9 @@ struct generic_pm_domain {
|
|||
s64 max_off_time_ns; /* Maximum allowed "suspended" time. */
|
||||
bool max_off_time_changed;
|
||||
bool cached_power_down_ok;
|
||||
struct device_node *of_node; /* Node in device tree */
|
||||
struct gpd_cpu_data *cpu_data;
|
||||
struct gpd_cpuidle_data *cpuidle_data;
|
||||
void (*attach_dev)(struct device *dev);
|
||||
void (*detach_dev)(struct device *dev);
|
||||
};
|
||||
|
||||
static inline struct generic_pm_domain *pd_to_genpd(struct dev_pm_domain *pd)
|
||||
|
@ -108,7 +100,6 @@ struct gpd_timing_data {
|
|||
|
||||
struct generic_pm_domain_data {
|
||||
struct pm_domain_data base;
|
||||
struct gpd_dev_ops ops;
|
||||
struct gpd_timing_data td;
|
||||
struct notifier_block nb;
|
||||
struct mutex lock;
|
||||
|
@ -127,17 +118,11 @@ static inline struct generic_pm_domain_data *dev_gpd_data(struct device *dev)
|
|||
return to_gpd_data(dev->power.subsys_data->domain_data);
|
||||
}
|
||||
|
||||
extern struct dev_power_governor simple_qos_governor;
|
||||
|
||||
extern struct generic_pm_domain *dev_to_genpd(struct device *dev);
|
||||
extern int __pm_genpd_add_device(struct generic_pm_domain *genpd,
|
||||
struct device *dev,
|
||||
struct gpd_timing_data *td);
|
||||
|
||||
extern int __pm_genpd_of_add_device(struct device_node *genpd_node,
|
||||
struct device *dev,
|
||||
struct gpd_timing_data *td);
|
||||
|
||||
extern int __pm_genpd_name_add_device(const char *domain_name,
|
||||
struct device *dev,
|
||||
struct gpd_timing_data *td);
|
||||
|
@ -151,10 +136,6 @@ extern int pm_genpd_add_subdomain_names(const char *master_name,
|
|||
const char *subdomain_name);
|
||||
extern int pm_genpd_remove_subdomain(struct generic_pm_domain *genpd,
|
||||
struct generic_pm_domain *target);
|
||||
extern int pm_genpd_add_callbacks(struct device *dev,
|
||||
struct gpd_dev_ops *ops,
|
||||
struct gpd_timing_data *td);
|
||||
extern int __pm_genpd_remove_callbacks(struct device *dev, bool clear_td);
|
||||
extern int pm_genpd_attach_cpuidle(struct generic_pm_domain *genpd, int state);
|
||||
extern int pm_genpd_name_attach_cpuidle(const char *name, int state);
|
||||
extern int pm_genpd_detach_cpuidle(struct generic_pm_domain *genpd);
|
||||
|
@ -165,8 +146,7 @@ extern void pm_genpd_init(struct generic_pm_domain *genpd,
|
|||
extern int pm_genpd_poweron(struct generic_pm_domain *genpd);
|
||||
extern int pm_genpd_name_poweron(const char *domain_name);
|
||||
|
||||
extern bool default_stop_ok(struct device *dev);
|
||||
|
||||
extern struct dev_power_governor simple_qos_governor;
|
||||
extern struct dev_power_governor pm_domain_always_on_gov;
|
||||
#else
|
||||
|
||||
|
@ -184,12 +164,6 @@ static inline int __pm_genpd_add_device(struct generic_pm_domain *genpd,
|
|||
{
|
||||
return -ENOSYS;
|
||||
}
|
||||
static inline int __pm_genpd_of_add_device(struct device_node *genpd_node,
|
||||
struct device *dev,
|
||||
struct gpd_timing_data *td)
|
||||
{
|
||||
return -ENOSYS;
|
||||
}
|
||||
static inline int __pm_genpd_name_add_device(const char *domain_name,
|
||||
struct device *dev,
|
||||
struct gpd_timing_data *td)
|
||||
|
@ -217,16 +191,6 @@ static inline int pm_genpd_remove_subdomain(struct generic_pm_domain *genpd,
|
|||
{
|
||||
return -ENOSYS;
|
||||
}
|
||||
static inline int pm_genpd_add_callbacks(struct device *dev,
|
||||
struct gpd_dev_ops *ops,
|
||||
struct gpd_timing_data *td)
|
||||
{
|
||||
return -ENOSYS;
|
||||
}
|
||||
static inline int __pm_genpd_remove_callbacks(struct device *dev, bool clear_td)
|
||||
{
|
||||
return -ENOSYS;
|
||||
}
|
||||
static inline int pm_genpd_attach_cpuidle(struct generic_pm_domain *genpd, int st)
|
||||
{
|
||||
return -ENOSYS;
|
||||
|
@ -255,10 +219,6 @@ static inline int pm_genpd_name_poweron(const char *domain_name)
|
|||
{
|
||||
return -ENOSYS;
|
||||
}
|
||||
static inline bool default_stop_ok(struct device *dev)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
#define simple_qos_governor NULL
|
||||
#define pm_domain_always_on_gov NULL
|
||||
#endif
|
||||
|
@ -269,45 +229,87 @@ static inline int pm_genpd_add_device(struct generic_pm_domain *genpd,
|
|||
return __pm_genpd_add_device(genpd, dev, NULL);
|
||||
}
|
||||
|
||||
static inline int pm_genpd_of_add_device(struct device_node *genpd_node,
|
||||
struct device *dev)
|
||||
{
|
||||
return __pm_genpd_of_add_device(genpd_node, dev, NULL);
|
||||
}
|
||||
|
||||
static inline int pm_genpd_name_add_device(const char *domain_name,
|
||||
struct device *dev)
|
||||
{
|
||||
return __pm_genpd_name_add_device(domain_name, dev, NULL);
|
||||
}
|
||||
|
||||
static inline int pm_genpd_remove_callbacks(struct device *dev)
|
||||
{
|
||||
return __pm_genpd_remove_callbacks(dev, true);
|
||||
}
|
||||
|
||||
#ifdef CONFIG_PM_GENERIC_DOMAINS_RUNTIME
|
||||
extern void genpd_queue_power_off_work(struct generic_pm_domain *genpd);
|
||||
extern void pm_genpd_poweroff_unused(void);
|
||||
#else
|
||||
static inline void genpd_queue_power_off_work(struct generic_pm_domain *gpd) {}
|
||||
static inline void pm_genpd_poweroff_unused(void) {}
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_PM_GENERIC_DOMAINS_SLEEP
|
||||
extern void pm_genpd_syscore_switch(struct device *dev, bool suspend);
|
||||
extern void pm_genpd_syscore_poweroff(struct device *dev);
|
||||
extern void pm_genpd_syscore_poweron(struct device *dev);
|
||||
#else
|
||||
static inline void pm_genpd_syscore_switch(struct device *dev, bool suspend) {}
|
||||
static inline void pm_genpd_syscore_poweroff(struct device *dev) {}
|
||||
static inline void pm_genpd_syscore_poweron(struct device *dev) {}
|
||||
#endif
|
||||
|
||||
static inline void pm_genpd_syscore_poweroff(struct device *dev)
|
||||
/* OF PM domain providers */
|
||||
struct of_device_id;
|
||||
|
||||
struct genpd_onecell_data {
|
||||
struct generic_pm_domain **domains;
|
||||
unsigned int num_domains;
|
||||
};
|
||||
|
||||
typedef struct generic_pm_domain *(*genpd_xlate_t)(struct of_phandle_args *args,
|
||||
void *data);
|
||||
|
||||
#ifdef CONFIG_PM_GENERIC_DOMAINS_OF
|
||||
int __of_genpd_add_provider(struct device_node *np, genpd_xlate_t xlate,
|
||||
void *data);
|
||||
void of_genpd_del_provider(struct device_node *np);
|
||||
|
||||
struct generic_pm_domain *__of_genpd_xlate_simple(
|
||||
struct of_phandle_args *genpdspec,
|
||||
void *data);
|
||||
struct generic_pm_domain *__of_genpd_xlate_onecell(
|
||||
struct of_phandle_args *genpdspec,
|
||||
void *data);
|
||||
|
||||
int genpd_dev_pm_attach(struct device *dev);
|
||||
#else /* !CONFIG_PM_GENERIC_DOMAINS_OF */
|
||||
static inline int __of_genpd_add_provider(struct device_node *np,
|
||||
genpd_xlate_t xlate, void *data)
|
||||
{
|
||||
pm_genpd_syscore_switch(dev, true);
|
||||
return 0;
|
||||
}
|
||||
static inline void of_genpd_del_provider(struct device_node *np) {}
|
||||
|
||||
#define __of_genpd_xlate_simple NULL
|
||||
#define __of_genpd_xlate_onecell NULL
|
||||
|
||||
static inline int genpd_dev_pm_attach(struct device *dev)
|
||||
{
|
||||
return -ENODEV;
|
||||
}
|
||||
#endif /* CONFIG_PM_GENERIC_DOMAINS_OF */
|
||||
|
||||
static inline int of_genpd_add_provider_simple(struct device_node *np,
|
||||
struct generic_pm_domain *genpd)
|
||||
{
|
||||
return __of_genpd_add_provider(np, __of_genpd_xlate_simple, genpd);
|
||||
}
|
||||
static inline int of_genpd_add_provider_onecell(struct device_node *np,
|
||||
struct genpd_onecell_data *data)
|
||||
{
|
||||
return __of_genpd_add_provider(np, __of_genpd_xlate_onecell, data);
|
||||
}
|
||||
|
||||
static inline void pm_genpd_syscore_poweron(struct device *dev)
|
||||
#ifdef CONFIG_PM
|
||||
extern int dev_pm_domain_attach(struct device *dev, bool power_on);
|
||||
extern void dev_pm_domain_detach(struct device *dev, bool power_off);
|
||||
#else
|
||||
static inline int dev_pm_domain_attach(struct device *dev, bool power_on)
|
||||
{
|
||||
pm_genpd_syscore_switch(dev, false);
|
||||
return -ENODEV;
|
||||
}
|
||||
static inline void dev_pm_domain_detach(struct device *dev, bool power_off) {}
|
||||
#endif
|
||||
|
||||
#endif /* _LINUX_PM_DOMAIN_H */
|
||||
|
|
|
@ -302,6 +302,10 @@ config PM_GENERIC_DOMAINS_RUNTIME
|
|||
def_bool y
|
||||
depends on PM_RUNTIME && PM_GENERIC_DOMAINS
|
||||
|
||||
config PM_GENERIC_DOMAINS_OF
|
||||
def_bool y
|
||||
depends on PM_GENERIC_DOMAINS && OF
|
||||
|
||||
config CPU_PM
|
||||
bool
|
||||
depends on SUSPEND || CPU_IDLE
|
||||
|
|
Loading…
Reference in a new issue