diff options
author | Rafael J. Wysocki <rjw@sisk.pl> | 2011-12-25 17:43:11 -0500 |
---|---|---|
committer | Rafael J. Wysocki <rjw@sisk.pl> | 2011-12-25 17:43:11 -0500 |
commit | 6d10463b2fa1b6b81091661c1917f26436b38c53 (patch) | |
tree | 1fb5be10a08a3178fb644c9eb5a2a31423985cfa | |
parent | 0015afaa1f818d38ea9f8e81a84a6aeeca5fdaf0 (diff) | |
parent | a8cf27bee7adc40d91956cf1b9e44d7001f93aba (diff) |
Merge branch 'pm-domains' into pm-for-linus
* pm-domains:
PM / shmobile: Allow the A4R domain to be turned off at run time
PM / input / touchscreen: Make st1232 use device PM QoS constraints
PM / QoS: Introduce dev_pm_qos_add_ancestor_request()
PM / shmobile: Remove the stay_on flag from SH7372's PM domains
PM / shmobile: Don't include SH7372's INTCS in syscore suspend/resume
PM / shmobile: Add support for the sh7372 A4S power domain / sleep mode
ARM: S3C64XX: Implement basic power domain support
PM / shmobile: Use common always on power domain governor
PM / Domains: Provide an always on power domain governor
PM / Domains: Fix default system suspend/resume operations
PM / Domains: Make it possible to assign names to generic PM domains
PM / Domains: fix compilation failure for CONFIG_PM_GENERIC_DOMAINS unset
PM / Domains: Automatically update overoptimistic latency information
PM / Domains: Add default power off governor function (v4)
PM / Domains: Add device stop governor function (v4)
PM / Domains: Rework system suspend callback routines (v2)
PM / Domains: Introduce "save/restore state" device callbacks
PM / Domains: Make it possible to use per-device domain callbacks
-rw-r--r-- | arch/arm/mach-s3c64xx/Kconfig | 1 | ||||
-rw-r--r-- | arch/arm/mach-s3c64xx/mach-crag6410.c | 2 | ||||
-rw-r--r-- | arch/arm/mach-s3c64xx/pm.c | 176 | ||||
-rw-r--r-- | arch/arm/mach-shmobile/include/mach/common.h | 4 | ||||
-rw-r--r-- | arch/arm/mach-shmobile/include/mach/sh7372.h | 6 | ||||
-rw-r--r-- | arch/arm/mach-shmobile/intc-sh7372.c | 50 | ||||
-rw-r--r-- | arch/arm/mach-shmobile/pm-sh7372.c | 196 | ||||
-rw-r--r-- | arch/arm/mach-shmobile/setup-sh7372.c | 6 | ||||
-rw-r--r-- | arch/arm/mach-shmobile/sleep-sh7372.S | 21 | ||||
-rw-r--r-- | arch/arm/plat-samsung/include/plat/pm.h | 6 | ||||
-rw-r--r-- | drivers/base/power/Makefile | 2 | ||||
-rw-r--r-- | drivers/base/power/domain.c | 539 | ||||
-rw-r--r-- | drivers/base/power/domain_governor.c | 156 | ||||
-rw-r--r-- | drivers/base/power/qos.c | 25 | ||||
-rw-r--r-- | drivers/input/touchscreen/st1232.c | 13 | ||||
-rw-r--r-- | drivers/sh/intc/core.c | 8 | ||||
-rw-r--r-- | drivers/sh/intc/internals.h | 1 | ||||
-rw-r--r-- | include/linux/pm_domain.h | 103 | ||||
-rw-r--r-- | include/linux/pm_qos.h | 5 | ||||
-rw-r--r-- | include/linux/sh_intc.h | 1 |
20 files changed, 1099 insertions, 222 deletions
diff --git a/arch/arm/mach-s3c64xx/Kconfig b/arch/arm/mach-s3c64xx/Kconfig index 5552e048c2be..381586c7b1b2 100644 --- a/arch/arm/mach-s3c64xx/Kconfig +++ b/arch/arm/mach-s3c64xx/Kconfig | |||
@@ -8,6 +8,7 @@ config PLAT_S3C64XX | |||
8 | bool | 8 | bool |
9 | depends on ARCH_S3C64XX | 9 | depends on ARCH_S3C64XX |
10 | select SAMSUNG_WAKEMASK | 10 | select SAMSUNG_WAKEMASK |
11 | select PM_GENERIC_DOMAINS | ||
11 | default y | 12 | default y |
12 | help | 13 | help |
13 | Base platform code for any Samsung S3C64XX device | 14 | Base platform code for any Samsung S3C64XX device |
diff --git a/arch/arm/mach-s3c64xx/mach-crag6410.c b/arch/arm/mach-s3c64xx/mach-crag6410.c index d04b65448510..707b9b22f9fd 100644 --- a/arch/arm/mach-s3c64xx/mach-crag6410.c +++ b/arch/arm/mach-s3c64xx/mach-crag6410.c | |||
@@ -704,7 +704,7 @@ static void __init crag6410_machine_init(void) | |||
704 | 704 | ||
705 | regulator_has_full_constraints(); | 705 | regulator_has_full_constraints(); |
706 | 706 | ||
707 | s3c_pm_init(); | 707 | s3c64xx_pm_init(); |
708 | } | 708 | } |
709 | 709 | ||
710 | MACHINE_START(WLF_CRAGG_6410, "Wolfson Cragganmore 6410") | 710 | MACHINE_START(WLF_CRAGG_6410, "Wolfson Cragganmore 6410") |
diff --git a/arch/arm/mach-s3c64xx/pm.c b/arch/arm/mach-s3c64xx/pm.c index b375cd5c47cb..7d3e81b9dd06 100644 --- a/arch/arm/mach-s3c64xx/pm.c +++ b/arch/arm/mach-s3c64xx/pm.c | |||
@@ -17,10 +17,12 @@ | |||
17 | #include <linux/serial_core.h> | 17 | #include <linux/serial_core.h> |
18 | #include <linux/io.h> | 18 | #include <linux/io.h> |
19 | #include <linux/gpio.h> | 19 | #include <linux/gpio.h> |
20 | #include <linux/pm_domain.h> | ||
20 | 21 | ||
21 | #include <mach/map.h> | 22 | #include <mach/map.h> |
22 | #include <mach/irqs.h> | 23 | #include <mach/irqs.h> |
23 | 24 | ||
25 | #include <plat/devs.h> | ||
24 | #include <plat/pm.h> | 26 | #include <plat/pm.h> |
25 | #include <plat/wakeup-mask.h> | 27 | #include <plat/wakeup-mask.h> |
26 | 28 | ||
@@ -31,6 +33,148 @@ | |||
31 | #include <mach/regs-gpio-memport.h> | 33 | #include <mach/regs-gpio-memport.h> |
32 | #include <mach/regs-modem.h> | 34 | #include <mach/regs-modem.h> |
33 | 35 | ||
36 | struct s3c64xx_pm_domain { | ||
37 | char *const name; | ||
38 | u32 ena; | ||
39 | u32 pwr_stat; | ||
40 | struct generic_pm_domain pd; | ||
41 | }; | ||
42 | |||
43 | static int s3c64xx_pd_off(struct generic_pm_domain *domain) | ||
44 | { | ||
45 | struct s3c64xx_pm_domain *pd; | ||
46 | u32 val; | ||
47 | |||
48 | pd = container_of(domain, struct s3c64xx_pm_domain, pd); | ||
49 | |||
50 | val = __raw_readl(S3C64XX_NORMAL_CFG); | ||
51 | val &= ~(pd->ena); | ||
52 | __raw_writel(val, S3C64XX_NORMAL_CFG); | ||
53 | |||
54 | return 0; | ||
55 | } | ||
56 | |||
57 | static int s3c64xx_pd_on(struct generic_pm_domain *domain) | ||
58 | { | ||
59 | struct s3c64xx_pm_domain *pd; | ||
60 | u32 val; | ||
61 | long retry = 1000000L; | ||
62 | |||
63 | pd = container_of(domain, struct s3c64xx_pm_domain, pd); | ||
64 | |||
65 | val = __raw_readl(S3C64XX_NORMAL_CFG); | ||
66 | val |= pd->ena; | ||
67 | __raw_writel(val, S3C64XX_NORMAL_CFG); | ||
68 | |||
69 | /* Not all domains provide power status readback */ | ||
70 | if (pd->pwr_stat) { | ||
71 | do { | ||
72 | cpu_relax(); | ||
73 | if (__raw_readl(S3C64XX_BLK_PWR_STAT) & pd->pwr_stat) | ||
74 | break; | ||
75 | } while (retry--); | ||
76 | |||
77 | if (!retry) { | ||
78 | pr_err("Failed to start domain %s\n", pd->name); | ||
79 | return -EBUSY; | ||
80 | } | ||
81 | } | ||
82 | |||
83 | return 0; | ||
84 | } | ||
85 | |||
86 | static struct s3c64xx_pm_domain s3c64xx_pm_irom = { | ||
87 | .name = "IROM", | ||
88 | .ena = S3C64XX_NORMALCFG_IROM_ON, | ||
89 | .pd = { | ||
90 | .power_off = s3c64xx_pd_off, | ||
91 | .power_on = s3c64xx_pd_on, | ||
92 | }, | ||
93 | }; | ||
94 | |||
95 | static struct s3c64xx_pm_domain s3c64xx_pm_etm = { | ||
96 | .name = "ETM", | ||
97 | .ena = S3C64XX_NORMALCFG_DOMAIN_ETM_ON, | ||
98 | .pwr_stat = S3C64XX_BLKPWRSTAT_ETM, | ||
99 | .pd = { | ||
100 | .power_off = s3c64xx_pd_off, | ||
101 | .power_on = s3c64xx_pd_on, | ||
102 | }, | ||
103 | }; | ||
104 | |||
105 | static struct s3c64xx_pm_domain s3c64xx_pm_s = { | ||
106 | .name = "S", | ||
107 | .ena = S3C64XX_NORMALCFG_DOMAIN_S_ON, | ||
108 | .pwr_stat = S3C64XX_BLKPWRSTAT_S, | ||
109 | .pd = { | ||
110 | .power_off = s3c64xx_pd_off, | ||
111 | .power_on = s3c64xx_pd_on, | ||
112 | }, | ||
113 | }; | ||
114 | |||
115 | static struct s3c64xx_pm_domain s3c64xx_pm_f = { | ||
116 | .name = "F", | ||
117 | .ena = S3C64XX_NORMALCFG_DOMAIN_F_ON, | ||
118 | .pwr_stat = S3C64XX_BLKPWRSTAT_F, | ||
119 | .pd = { | ||
120 | .power_off = s3c64xx_pd_off, | ||
121 | .power_on = s3c64xx_pd_on, | ||
122 | }, | ||
123 | }; | ||
124 | |||
125 | static struct s3c64xx_pm_domain s3c64xx_pm_p = { | ||
126 | .name = "P", | ||
127 | .ena = S3C64XX_NORMALCFG_DOMAIN_P_ON, | ||
128 | .pwr_stat = S3C64XX_BLKPWRSTAT_P, | ||
129 | .pd = { | ||
130 | .power_off = s3c64xx_pd_off, | ||
131 | .power_on = s3c64xx_pd_on, | ||
132 | }, | ||
133 | }; | ||
134 | |||
135 | static struct s3c64xx_pm_domain s3c64xx_pm_i = { | ||
136 | .name = "I", | ||
137 | .ena = S3C64XX_NORMALCFG_DOMAIN_I_ON, | ||
138 | .pwr_stat = S3C64XX_BLKPWRSTAT_I, | ||
139 | .pd = { | ||
140 | .power_off = s3c64xx_pd_off, | ||
141 | .power_on = s3c64xx_pd_on, | ||
142 | }, | ||
143 | }; | ||
144 | |||
145 | static struct s3c64xx_pm_domain s3c64xx_pm_g = { | ||
146 | .name = "G", | ||
147 | .ena = S3C64XX_NORMALCFG_DOMAIN_G_ON, | ||
148 | .pd = { | ||
149 | .power_off = s3c64xx_pd_off, | ||
150 | .power_on = s3c64xx_pd_on, | ||
151 | }, | ||
152 | }; | ||
153 | |||
154 | static struct s3c64xx_pm_domain s3c64xx_pm_v = { | ||
155 | .name = "V", | ||
156 | .ena = S3C64XX_NORMALCFG_DOMAIN_V_ON, | ||
157 | .pwr_stat = S3C64XX_BLKPWRSTAT_V, | ||
158 | .pd = { | ||
159 | .power_off = s3c64xx_pd_off, | ||
160 | .power_on = s3c64xx_pd_on, | ||
161 | }, | ||
162 | }; | ||
163 | |||
164 | static struct s3c64xx_pm_domain *s3c64xx_always_on_pm_domains[] = { | ||
165 | &s3c64xx_pm_irom, | ||
166 | }; | ||
167 | |||
168 | static struct s3c64xx_pm_domain *s3c64xx_pm_domains[] = { | ||
169 | &s3c64xx_pm_etm, | ||
170 | &s3c64xx_pm_g, | ||
171 | &s3c64xx_pm_v, | ||
172 | &s3c64xx_pm_i, | ||
173 | &s3c64xx_pm_p, | ||
174 | &s3c64xx_pm_s, | ||
175 | &s3c64xx_pm_f, | ||
176 | }; | ||
177 | |||
34 | #ifdef CONFIG_S3C_PM_DEBUG_LED_SMDK | 178 | #ifdef CONFIG_S3C_PM_DEBUG_LED_SMDK |
35 | void s3c_pm_debug_smdkled(u32 set, u32 clear) | 179 | void s3c_pm_debug_smdkled(u32 set, u32 clear) |
36 | { | 180 | { |
@@ -89,6 +233,8 @@ static struct sleep_save misc_save[] = { | |||
89 | 233 | ||
90 | SAVE_ITEM(S3C64XX_SDMA_SEL), | 234 | SAVE_ITEM(S3C64XX_SDMA_SEL), |
91 | SAVE_ITEM(S3C64XX_MODEM_MIFPCON), | 235 | SAVE_ITEM(S3C64XX_MODEM_MIFPCON), |
236 | |||
237 | SAVE_ITEM(S3C64XX_NORMAL_CFG), | ||
92 | }; | 238 | }; |
93 | 239 | ||
94 | void s3c_pm_configure_extint(void) | 240 | void s3c_pm_configure_extint(void) |
@@ -179,7 +325,26 @@ static void s3c64xx_pm_prepare(void) | |||
179 | __raw_writel(__raw_readl(S3C64XX_WAKEUP_STAT), S3C64XX_WAKEUP_STAT); | 325 | __raw_writel(__raw_readl(S3C64XX_WAKEUP_STAT), S3C64XX_WAKEUP_STAT); |
180 | } | 326 | } |
181 | 327 | ||
182 | static int s3c64xx_pm_init(void) | 328 | int __init s3c64xx_pm_init(void) |
329 | { | ||
330 | int i; | ||
331 | |||
332 | s3c_pm_init(); | ||
333 | |||
334 | for (i = 0; i < ARRAY_SIZE(s3c64xx_always_on_pm_domains); i++) | ||
335 | pm_genpd_init(&s3c64xx_always_on_pm_domains[i]->pd, | ||
336 | &pm_domain_always_on_gov, false); | ||
337 | |||
338 | for (i = 0; i < ARRAY_SIZE(s3c64xx_pm_domains); i++) | ||
339 | pm_genpd_init(&s3c64xx_pm_domains[i]->pd, NULL, false); | ||
340 | |||
341 | if (dev_get_platdata(&s3c_device_fb.dev)) | ||
342 | pm_genpd_add_device(&s3c64xx_pm_f.pd, &s3c_device_fb.dev); | ||
343 | |||
344 | return 0; | ||
345 | } | ||
346 | |||
347 | static __init int s3c64xx_pm_initcall(void) | ||
183 | { | 348 | { |
184 | pm_cpu_prep = s3c64xx_pm_prepare; | 349 | pm_cpu_prep = s3c64xx_pm_prepare; |
185 | pm_cpu_sleep = s3c64xx_cpu_suspend; | 350 | pm_cpu_sleep = s3c64xx_cpu_suspend; |
@@ -198,5 +363,12 @@ static int s3c64xx_pm_init(void) | |||
198 | 363 | ||
199 | return 0; | 364 | return 0; |
200 | } | 365 | } |
366 | arch_initcall(s3c64xx_pm_initcall); | ||
367 | |||
368 | static __init int s3c64xx_pm_late_initcall(void) | ||
369 | { | ||
370 | pm_genpd_poweroff_unused(); | ||
201 | 371 | ||
202 | arch_initcall(s3c64xx_pm_init); | 372 | return 0; |
373 | } | ||
374 | late_initcall(s3c64xx_pm_late_initcall); | ||
diff --git a/arch/arm/mach-shmobile/include/mach/common.h b/arch/arm/mach-shmobile/include/mach/common.h index 834bd6cd508f..4807623fb71c 100644 --- a/arch/arm/mach-shmobile/include/mach/common.h +++ b/arch/arm/mach-shmobile/include/mach/common.h | |||
@@ -35,8 +35,8 @@ extern void sh7372_add_standard_devices(void); | |||
35 | extern void sh7372_clock_init(void); | 35 | extern void sh7372_clock_init(void); |
36 | extern void sh7372_pinmux_init(void); | 36 | extern void sh7372_pinmux_init(void); |
37 | extern void sh7372_pm_init(void); | 37 | extern void sh7372_pm_init(void); |
38 | extern void sh7372_resume_core_standby_a3sm(void); | 38 | extern void sh7372_resume_core_standby_sysc(void); |
39 | extern int sh7372_do_idle_a3sm(unsigned long unused); | 39 | extern int sh7372_do_idle_sysc(unsigned long sleep_mode); |
40 | extern struct clk sh7372_extal1_clk; | 40 | extern struct clk sh7372_extal1_clk; |
41 | extern struct clk sh7372_extal2_clk; | 41 | extern struct clk sh7372_extal2_clk; |
42 | 42 | ||
diff --git a/arch/arm/mach-shmobile/include/mach/sh7372.h b/arch/arm/mach-shmobile/include/mach/sh7372.h index 84532f9629b2..8254ab86f6cd 100644 --- a/arch/arm/mach-shmobile/include/mach/sh7372.h +++ b/arch/arm/mach-shmobile/include/mach/sh7372.h | |||
@@ -480,11 +480,10 @@ struct platform_device; | |||
480 | struct sh7372_pm_domain { | 480 | struct sh7372_pm_domain { |
481 | struct generic_pm_domain genpd; | 481 | struct generic_pm_domain genpd; |
482 | struct dev_power_governor *gov; | 482 | struct dev_power_governor *gov; |
483 | void (*suspend)(void); | 483 | int (*suspend)(void); |
484 | void (*resume)(void); | 484 | void (*resume)(void); |
485 | unsigned int bit_shift; | 485 | unsigned int bit_shift; |
486 | bool no_debug; | 486 | bool no_debug; |
487 | bool stay_on; | ||
488 | }; | 487 | }; |
489 | 488 | ||
490 | static inline struct sh7372_pm_domain *to_sh7372_pd(struct generic_pm_domain *d) | 489 | static inline struct sh7372_pm_domain *to_sh7372_pd(struct generic_pm_domain *d) |
@@ -499,6 +498,7 @@ extern struct sh7372_pm_domain sh7372_d4; | |||
499 | extern struct sh7372_pm_domain sh7372_a4r; | 498 | extern struct sh7372_pm_domain sh7372_a4r; |
500 | extern struct sh7372_pm_domain sh7372_a3rv; | 499 | extern struct sh7372_pm_domain sh7372_a3rv; |
501 | extern struct sh7372_pm_domain sh7372_a3ri; | 500 | extern struct sh7372_pm_domain sh7372_a3ri; |
501 | extern struct sh7372_pm_domain sh7372_a4s; | ||
502 | extern struct sh7372_pm_domain sh7372_a3sp; | 502 | extern struct sh7372_pm_domain sh7372_a3sp; |
503 | extern struct sh7372_pm_domain sh7372_a3sg; | 503 | extern struct sh7372_pm_domain sh7372_a3sg; |
504 | 504 | ||
@@ -515,5 +515,7 @@ extern void sh7372_pm_add_subdomain(struct sh7372_pm_domain *sh7372_pd, | |||
515 | 515 | ||
516 | extern void sh7372_intcs_suspend(void); | 516 | extern void sh7372_intcs_suspend(void); |
517 | extern void sh7372_intcs_resume(void); | 517 | extern void sh7372_intcs_resume(void); |
518 | extern void sh7372_intca_suspend(void); | ||
519 | extern void sh7372_intca_resume(void); | ||
518 | 520 | ||
519 | #endif /* __ASM_SH7372_H__ */ | 521 | #endif /* __ASM_SH7372_H__ */ |
diff --git a/arch/arm/mach-shmobile/intc-sh7372.c b/arch/arm/mach-shmobile/intc-sh7372.c index 2d8856df80e2..89afcaba99a1 100644 --- a/arch/arm/mach-shmobile/intc-sh7372.c +++ b/arch/arm/mach-shmobile/intc-sh7372.c | |||
@@ -535,6 +535,7 @@ static struct resource intcs_resources[] __initdata = { | |||
535 | static struct intc_desc intcs_desc __initdata = { | 535 | static struct intc_desc intcs_desc __initdata = { |
536 | .name = "sh7372-intcs", | 536 | .name = "sh7372-intcs", |
537 | .force_enable = ENABLED_INTCS, | 537 | .force_enable = ENABLED_INTCS, |
538 | .skip_syscore_suspend = true, | ||
538 | .resource = intcs_resources, | 539 | .resource = intcs_resources, |
539 | .num_resources = ARRAY_SIZE(intcs_resources), | 540 | .num_resources = ARRAY_SIZE(intcs_resources), |
540 | .hw = INTC_HW_DESC(intcs_vectors, intcs_groups, intcs_mask_registers, | 541 | .hw = INTC_HW_DESC(intcs_vectors, intcs_groups, intcs_mask_registers, |
@@ -611,3 +612,52 @@ void sh7372_intcs_resume(void) | |||
611 | for (k = 0x80; k <= 0x9c; k += 4) | 612 | for (k = 0x80; k <= 0x9c; k += 4) |
612 | __raw_writeb(ffd5[k], intcs_ffd5 + k); | 613 | __raw_writeb(ffd5[k], intcs_ffd5 + k); |
613 | } | 614 | } |
615 | |||
616 | static unsigned short e694[0x200]; | ||
617 | static unsigned short e695[0x200]; | ||
618 | |||
619 | void sh7372_intca_suspend(void) | ||
620 | { | ||
621 | int k; | ||
622 | |||
623 | for (k = 0x00; k <= 0x38; k += 4) | ||
624 | e694[k] = __raw_readw(0xe6940000 + k); | ||
625 | |||
626 | for (k = 0x80; k <= 0xb4; k += 4) | ||
627 | e694[k] = __raw_readb(0xe6940000 + k); | ||
628 | |||
629 | for (k = 0x180; k <= 0x1b4; k += 4) | ||
630 | e694[k] = __raw_readb(0xe6940000 + k); | ||
631 | |||
632 | for (k = 0x00; k <= 0x50; k += 4) | ||
633 | e695[k] = __raw_readw(0xe6950000 + k); | ||
634 | |||
635 | for (k = 0x80; k <= 0xa8; k += 4) | ||
636 | e695[k] = __raw_readb(0xe6950000 + k); | ||
637 | |||
638 | for (k = 0x180; k <= 0x1a8; k += 4) | ||
639 | e695[k] = __raw_readb(0xe6950000 + k); | ||
640 | } | ||
641 | |||
642 | void sh7372_intca_resume(void) | ||
643 | { | ||
644 | int k; | ||
645 | |||
646 | for (k = 0x00; k <= 0x38; k += 4) | ||
647 | __raw_writew(e694[k], 0xe6940000 + k); | ||
648 | |||
649 | for (k = 0x80; k <= 0xb4; k += 4) | ||
650 | __raw_writeb(e694[k], 0xe6940000 + k); | ||
651 | |||
652 | for (k = 0x180; k <= 0x1b4; k += 4) | ||
653 | __raw_writeb(e694[k], 0xe6940000 + k); | ||
654 | |||
655 | for (k = 0x00; k <= 0x50; k += 4) | ||
656 | __raw_writew(e695[k], 0xe6950000 + k); | ||
657 | |||
658 | for (k = 0x80; k <= 0xa8; k += 4) | ||
659 | __raw_writeb(e695[k], 0xe6950000 + k); | ||
660 | |||
661 | for (k = 0x180; k <= 0x1a8; k += 4) | ||
662 | __raw_writeb(e695[k], 0xe6950000 + k); | ||
663 | } | ||
diff --git a/arch/arm/mach-shmobile/pm-sh7372.c b/arch/arm/mach-shmobile/pm-sh7372.c index 34bbcbfb1706..77b8fc12fc2f 100644 --- a/arch/arm/mach-shmobile/pm-sh7372.c +++ b/arch/arm/mach-shmobile/pm-sh7372.c | |||
@@ -82,11 +82,12 @@ static int pd_power_down(struct generic_pm_domain *genpd) | |||
82 | struct sh7372_pm_domain *sh7372_pd = to_sh7372_pd(genpd); | 82 | struct sh7372_pm_domain *sh7372_pd = to_sh7372_pd(genpd); |
83 | unsigned int mask = 1 << sh7372_pd->bit_shift; | 83 | unsigned int mask = 1 << sh7372_pd->bit_shift; |
84 | 84 | ||
85 | if (sh7372_pd->suspend) | 85 | if (sh7372_pd->suspend) { |
86 | sh7372_pd->suspend(); | 86 | int ret = sh7372_pd->suspend(); |
87 | 87 | ||
88 | if (sh7372_pd->stay_on) | 88 | if (ret) |
89 | return 0; | 89 | return ret; |
90 | } | ||
90 | 91 | ||
91 | if (__raw_readl(PSTR) & mask) { | 92 | if (__raw_readl(PSTR) & mask) { |
92 | unsigned int retry_count; | 93 | unsigned int retry_count; |
@@ -101,8 +102,8 @@ static int pd_power_down(struct generic_pm_domain *genpd) | |||
101 | } | 102 | } |
102 | 103 | ||
103 | if (!sh7372_pd->no_debug) | 104 | if (!sh7372_pd->no_debug) |
104 | pr_debug("sh7372 power domain down 0x%08x -> PSTR = 0x%08x\n", | 105 | pr_debug("%s: Power off, 0x%08x -> PSTR = 0x%08x\n", |
105 | mask, __raw_readl(PSTR)); | 106 | genpd->name, mask, __raw_readl(PSTR)); |
106 | 107 | ||
107 | return 0; | 108 | return 0; |
108 | } | 109 | } |
@@ -113,9 +114,6 @@ static int __pd_power_up(struct sh7372_pm_domain *sh7372_pd, bool do_resume) | |||
113 | unsigned int retry_count; | 114 | unsigned int retry_count; |
114 | int ret = 0; | 115 | int ret = 0; |
115 | 116 | ||
116 | if (sh7372_pd->stay_on) | ||
117 | goto out; | ||
118 | |||
119 | if (__raw_readl(PSTR) & mask) | 117 | if (__raw_readl(PSTR) & mask) |
120 | goto out; | 118 | goto out; |
121 | 119 | ||
@@ -133,8 +131,8 @@ static int __pd_power_up(struct sh7372_pm_domain *sh7372_pd, bool do_resume) | |||
133 | ret = -EIO; | 131 | ret = -EIO; |
134 | 132 | ||
135 | if (!sh7372_pd->no_debug) | 133 | if (!sh7372_pd->no_debug) |
136 | pr_debug("sh7372 power domain up 0x%08x -> PSTR = 0x%08x\n", | 134 | pr_debug("%s: Power on, 0x%08x -> PSTR = 0x%08x\n", |
137 | mask, __raw_readl(PSTR)); | 135 | sh7372_pd->genpd.name, mask, __raw_readl(PSTR)); |
138 | 136 | ||
139 | out: | 137 | out: |
140 | if (ret == 0 && sh7372_pd->resume && do_resume) | 138 | if (ret == 0 && sh7372_pd->resume && do_resume) |
@@ -148,35 +146,60 @@ static int pd_power_up(struct generic_pm_domain *genpd) | |||
148 | return __pd_power_up(to_sh7372_pd(genpd), true); | 146 | return __pd_power_up(to_sh7372_pd(genpd), true); |
149 | } | 147 | } |
150 | 148 | ||
151 | static void sh7372_a4r_suspend(void) | 149 | static int sh7372_a4r_suspend(void) |
152 | { | 150 | { |
153 | sh7372_intcs_suspend(); | 151 | sh7372_intcs_suspend(); |
154 | __raw_writel(0x300fffff, WUPRMSK); /* avoid wakeup */ | 152 | __raw_writel(0x300fffff, WUPRMSK); /* avoid wakeup */ |
153 | return 0; | ||
155 | } | 154 | } |
156 | 155 | ||
157 | static bool pd_active_wakeup(struct device *dev) | 156 | static bool pd_active_wakeup(struct device *dev) |
158 | { | 157 | { |
159 | return true; | 158 | bool (*active_wakeup)(struct device *dev); |
159 | |||
160 | active_wakeup = dev_gpd_data(dev)->ops.active_wakeup; | ||
161 | return active_wakeup ? active_wakeup(dev) : true; | ||
160 | } | 162 | } |
161 | 163 | ||
162 | static bool sh7372_power_down_forbidden(struct dev_pm_domain *domain) | 164 | static int sh7372_stop_dev(struct device *dev) |
163 | { | 165 | { |
164 | return false; | 166 | int (*stop)(struct device *dev); |
167 | |||
168 | stop = dev_gpd_data(dev)->ops.stop; | ||
169 | if (stop) { | ||
170 | int ret = stop(dev); | ||
171 | if (ret) | ||
172 | return ret; | ||
173 | } | ||
174 | return pm_clk_suspend(dev); | ||
165 | } | 175 | } |
166 | 176 | ||
167 | struct dev_power_governor sh7372_always_on_gov = { | 177 | static int sh7372_start_dev(struct device *dev) |
168 | .power_down_ok = sh7372_power_down_forbidden, | 178 | { |
169 | }; | 179 | int (*start)(struct device *dev); |
180 | int ret; | ||
181 | |||
182 | ret = pm_clk_resume(dev); | ||
183 | if (ret) | ||
184 | return ret; | ||
185 | |||
186 | start = dev_gpd_data(dev)->ops.start; | ||
187 | if (start) | ||
188 | ret = start(dev); | ||
189 | |||
190 | return ret; | ||
191 | } | ||
170 | 192 | ||
171 | void sh7372_init_pm_domain(struct sh7372_pm_domain *sh7372_pd) | 193 | void sh7372_init_pm_domain(struct sh7372_pm_domain *sh7372_pd) |
172 | { | 194 | { |
173 | struct generic_pm_domain *genpd = &sh7372_pd->genpd; | 195 | struct generic_pm_domain *genpd = &sh7372_pd->genpd; |
196 | struct dev_power_governor *gov = sh7372_pd->gov; | ||
174 | 197 | ||
175 | pm_genpd_init(genpd, sh7372_pd->gov, false); | 198 | pm_genpd_init(genpd, gov ? : &simple_qos_governor, false); |
176 | genpd->stop_device = pm_clk_suspend; | 199 | genpd->dev_ops.stop = sh7372_stop_dev; |
177 | genpd->start_device = pm_clk_resume; | 200 | genpd->dev_ops.start = sh7372_start_dev; |
201 | genpd->dev_ops.active_wakeup = pd_active_wakeup; | ||
178 | genpd->dev_irq_safe = true; | 202 | genpd->dev_irq_safe = true; |
179 | genpd->active_wakeup = pd_active_wakeup; | ||
180 | genpd->power_off = pd_power_down; | 203 | genpd->power_off = pd_power_down; |
181 | genpd->power_on = pd_power_up; | 204 | genpd->power_on = pd_power_up; |
182 | __pd_power_up(sh7372_pd, false); | 205 | __pd_power_up(sh7372_pd, false); |
@@ -199,48 +222,73 @@ void sh7372_pm_add_subdomain(struct sh7372_pm_domain *sh7372_pd, | |||
199 | } | 222 | } |
200 | 223 | ||
201 | struct sh7372_pm_domain sh7372_a4lc = { | 224 | struct sh7372_pm_domain sh7372_a4lc = { |
225 | .genpd.name = "A4LC", | ||
202 | .bit_shift = 1, | 226 | .bit_shift = 1, |
203 | }; | 227 | }; |
204 | 228 | ||
205 | struct sh7372_pm_domain sh7372_a4mp = { | 229 | struct sh7372_pm_domain sh7372_a4mp = { |
230 | .genpd.name = "A4MP", | ||
206 | .bit_shift = 2, | 231 | .bit_shift = 2, |
207 | }; | 232 | }; |
208 | 233 | ||
209 | struct sh7372_pm_domain sh7372_d4 = { | 234 | struct sh7372_pm_domain sh7372_d4 = { |
235 | .genpd.name = "D4", | ||
210 | .bit_shift = 3, | 236 | .bit_shift = 3, |
211 | }; | 237 | }; |
212 | 238 | ||
213 | struct sh7372_pm_domain sh7372_a4r = { | 239 | struct sh7372_pm_domain sh7372_a4r = { |
240 | .genpd.name = "A4R", | ||
214 | .bit_shift = 5, | 241 | .bit_shift = 5, |
215 | .gov = &sh7372_always_on_gov, | ||
216 | .suspend = sh7372_a4r_suspend, | 242 | .suspend = sh7372_a4r_suspend, |
217 | .resume = sh7372_intcs_resume, | 243 | .resume = sh7372_intcs_resume, |
218 | .stay_on = true, | ||
219 | }; | 244 | }; |
220 | 245 | ||
221 | struct sh7372_pm_domain sh7372_a3rv = { | 246 | struct sh7372_pm_domain sh7372_a3rv = { |
247 | .genpd.name = "A3RV", | ||
222 | .bit_shift = 6, | 248 | .bit_shift = 6, |
223 | }; | 249 | }; |
224 | 250 | ||
225 | struct sh7372_pm_domain sh7372_a3ri = { | 251 | struct sh7372_pm_domain sh7372_a3ri = { |
252 | .genpd.name = "A3RI", | ||
226 | .bit_shift = 8, | 253 | .bit_shift = 8, |
227 | }; | 254 | }; |
228 | 255 | ||
229 | struct sh7372_pm_domain sh7372_a3sp = { | 256 | static int sh7372_a4s_suspend(void) |
230 | .bit_shift = 11, | 257 | { |
231 | .gov = &sh7372_always_on_gov, | 258 | /* |
259 | * The A4S domain contains the CPU core and therefore it should | ||
260 | * only be turned off if the CPU is in use. | ||
261 | */ | ||
262 | return -EBUSY; | ||
263 | } | ||
264 | |||
265 | struct sh7372_pm_domain sh7372_a4s = { | ||
266 | .genpd.name = "A4S", | ||
267 | .bit_shift = 10, | ||
268 | .gov = &pm_domain_always_on_gov, | ||
232 | .no_debug = true, | 269 | .no_debug = true, |
270 | .suspend = sh7372_a4s_suspend, | ||
233 | }; | 271 | }; |
234 | 272 | ||
235 | static void sh7372_a3sp_init(void) | 273 | static int sh7372_a3sp_suspend(void) |
236 | { | 274 | { |
237 | /* serial consoles make use of SCIF hardware located in A3SP, | 275 | /* |
276 | * Serial consoles make use of SCIF hardware located in A3SP, | ||
238 | * keep such power domain on if "no_console_suspend" is set. | 277 | * keep such power domain on if "no_console_suspend" is set. |
239 | */ | 278 | */ |
240 | sh7372_a3sp.stay_on = !console_suspend_enabled; | 279 | return console_suspend_enabled ? -EBUSY : 0; |
241 | } | 280 | } |
242 | 281 | ||
282 | struct sh7372_pm_domain sh7372_a3sp = { | ||
283 | .genpd.name = "A3SP", | ||
284 | .bit_shift = 11, | ||
285 | .gov = &pm_domain_always_on_gov, | ||
286 | .no_debug = true, | ||
287 | .suspend = sh7372_a3sp_suspend, | ||
288 | }; | ||
289 | |||
243 | struct sh7372_pm_domain sh7372_a3sg = { | 290 | struct sh7372_pm_domain sh7372_a3sg = { |
291 | .genpd.name = "A3SG", | ||
244 | .bit_shift = 13, | 292 | .bit_shift = 13, |
245 | }; | 293 | }; |
246 | 294 | ||
@@ -257,11 +305,16 @@ static int sh7372_do_idle_core_standby(unsigned long unused) | |||
257 | return 0; | 305 | return 0; |
258 | } | 306 | } |
259 | 307 | ||
260 | static void sh7372_enter_core_standby(void) | 308 | static void sh7372_set_reset_vector(unsigned long address) |
261 | { | 309 | { |
262 | /* set reset vector, translate 4k */ | 310 | /* set reset vector, translate 4k */ |
263 | __raw_writel(__pa(sh7372_resume_core_standby_a3sm), SBAR); | 311 | __raw_writel(address, SBAR); |
264 | __raw_writel(0, APARMBAREA); | 312 | __raw_writel(0, APARMBAREA); |
313 | } | ||
314 | |||
315 | static void sh7372_enter_core_standby(void) | ||
316 | { | ||
317 | sh7372_set_reset_vector(__pa(sh7372_resume_core_standby_sysc)); | ||
265 | 318 | ||
266 | /* enter sleep mode with SYSTBCR to 0x10 */ | 319 | /* enter sleep mode with SYSTBCR to 0x10 */ |
267 | __raw_writel(0x10, SYSTBCR); | 320 | __raw_writel(0x10, SYSTBCR); |
@@ -274,27 +327,22 @@ static void sh7372_enter_core_standby(void) | |||
274 | #endif | 327 | #endif |
275 | 328 | ||
276 | #ifdef CONFIG_SUSPEND | 329 | #ifdef CONFIG_SUSPEND |
277 | static void sh7372_enter_a3sm_common(int pllc0_on) | 330 | static void sh7372_enter_sysc(int pllc0_on, unsigned long sleep_mode) |
278 | { | 331 | { |
279 | /* set reset vector, translate 4k */ | ||
280 | __raw_writel(__pa(sh7372_resume_core_standby_a3sm), SBAR); | ||
281 | __raw_writel(0, APARMBAREA); | ||
282 | |||
283 | if (pllc0_on) | 332 | if (pllc0_on) |
284 | __raw_writel(0, PLLC01STPCR); | 333 | __raw_writel(0, PLLC01STPCR); |
285 | else | 334 | else |
286 | __raw_writel(1 << 28, PLLC01STPCR); | 335 | __raw_writel(1 << 28, PLLC01STPCR); |
287 | 336 | ||
288 | __raw_writel(0, PDNSEL); /* power-down A3SM only, not A4S */ | ||
289 | __raw_readl(WUPSFAC); /* read wakeup int. factor before sleep */ | 337 | __raw_readl(WUPSFAC); /* read wakeup int. factor before sleep */ |
290 | cpu_suspend(0, sh7372_do_idle_a3sm); | 338 | cpu_suspend(sleep_mode, sh7372_do_idle_sysc); |
291 | __raw_readl(WUPSFAC); /* read wakeup int. factor after wakeup */ | 339 | __raw_readl(WUPSFAC); /* read wakeup int. factor after wakeup */ |
292 | 340 | ||
293 | /* disable reset vector translation */ | 341 | /* disable reset vector translation */ |
294 | __raw_writel(0, SBAR); | 342 | __raw_writel(0, SBAR); |
295 | } | 343 | } |
296 | 344 | ||
297 | static int sh7372_a3sm_valid(unsigned long *mskp, unsigned long *msk2p) | 345 | static int sh7372_sysc_valid(unsigned long *mskp, unsigned long *msk2p) |
298 | { | 346 | { |
299 | unsigned long mstpsr0, mstpsr1, mstpsr2, mstpsr3, mstpsr4; | 347 | unsigned long mstpsr0, mstpsr1, mstpsr2, mstpsr3, mstpsr4; |
300 | unsigned long msk, msk2; | 348 | unsigned long msk, msk2; |
@@ -382,7 +430,7 @@ static void sh7372_icr_to_irqcr(unsigned long icr, u16 *irqcr1p, u16 *irqcr2p) | |||
382 | *irqcr2p = irqcr2; | 430 | *irqcr2p = irqcr2; |
383 | } | 431 | } |
384 | 432 | ||
385 | static void sh7372_setup_a3sm(unsigned long msk, unsigned long msk2) | 433 | static void sh7372_setup_sysc(unsigned long msk, unsigned long msk2) |
386 | { | 434 | { |
387 | u16 irqcrx_low, irqcrx_high, irqcry_low, irqcry_high; | 435 | u16 irqcrx_low, irqcrx_high, irqcry_low, irqcry_high; |
388 | unsigned long tmp; | 436 | unsigned long tmp; |
@@ -415,6 +463,22 @@ static void sh7372_setup_a3sm(unsigned long msk, unsigned long msk2) | |||
415 | __raw_writel((irqcrx_high << 16) | irqcrx_low, IRQCR3); | 463 | __raw_writel((irqcrx_high << 16) | irqcrx_low, IRQCR3); |
416 | __raw_writel((irqcry_high << 16) | irqcry_low, IRQCR4); | 464 | __raw_writel((irqcry_high << 16) | irqcry_low, IRQCR4); |
417 | } | 465 | } |
466 | |||
467 | static void sh7372_enter_a3sm_common(int pllc0_on) | ||
468 | { | ||
469 | sh7372_set_reset_vector(__pa(sh7372_resume_core_standby_sysc)); | ||
470 | sh7372_enter_sysc(pllc0_on, 1 << 12); | ||
471 | } | ||
472 | |||
473 | static void sh7372_enter_a4s_common(int pllc0_on) | ||
474 | { | ||
475 | sh7372_intca_suspend(); | ||
476 | memcpy((void *)SMFRAM, sh7372_resume_core_standby_sysc, 0x100); | ||
477 | sh7372_set_reset_vector(SMFRAM); | ||
478 | sh7372_enter_sysc(pllc0_on, 1 << 10); | ||
479 | sh7372_intca_resume(); | ||
480 | } | ||
481 | |||
418 | #endif | 482 | #endif |
419 | 483 | ||
420 | #ifdef CONFIG_CPU_IDLE | 484 | #ifdef CONFIG_CPU_IDLE |
@@ -448,14 +512,20 @@ static int sh7372_enter_suspend(suspend_state_t suspend_state) | |||
448 | unsigned long msk, msk2; | 512 | unsigned long msk, msk2; |
449 | 513 | ||
450 | /* check active clocks to determine potential wakeup sources */ | 514 | /* check active clocks to determine potential wakeup sources */ |
451 | if (sh7372_a3sm_valid(&msk, &msk2)) { | 515 | if (sh7372_sysc_valid(&msk, &msk2)) { |
452 | |||
453 | /* convert INTC mask and sense to SYSC mask and sense */ | 516 | /* convert INTC mask and sense to SYSC mask and sense */ |
454 | sh7372_setup_a3sm(msk, msk2); | 517 | sh7372_setup_sysc(msk, msk2); |
455 | 518 | ||
456 | /* enter A3SM sleep with PLLC0 off */ | 519 | if (!console_suspend_enabled && |
457 | pr_debug("entering A3SM\n"); | 520 | sh7372_a4s.genpd.status == GPD_STATE_POWER_OFF) { |
458 | sh7372_enter_a3sm_common(0); | 521 | /* enter A4S sleep with PLLC0 off */ |
522 | pr_debug("entering A4S\n"); | ||
523 | sh7372_enter_a4s_common(0); | ||
524 | } else { | ||
525 | /* enter A3SM sleep with PLLC0 off */ | ||
526 | pr_debug("entering A3SM\n"); | ||
527 | sh7372_enter_a3sm_common(0); | ||
528 | } | ||
459 | } else { | 529 | } else { |
460 | /* default to Core Standby that supports all wakeup sources */ | 530 | /* default to Core Standby that supports all wakeup sources */ |
461 | pr_debug("entering Core Standby\n"); | 531 | pr_debug("entering Core Standby\n"); |
@@ -464,9 +534,37 @@ static int sh7372_enter_suspend(suspend_state_t suspend_state) | |||
464 | return 0; | 534 | return 0; |
465 | } | 535 | } |
466 | 536 | ||
537 | /** | ||
538 | * sh7372_pm_notifier_fn - SH7372 PM notifier routine. | ||
539 | * @notifier: Unused. | ||
540 | * @pm_event: Event being handled. | ||
541 | * @unused: Unused. | ||
542 | */ | ||
543 | static int sh7372_pm_notifier_fn(struct notifier_block *notifier, | ||
544 | unsigned long pm_event, void *unused) | ||
545 | { | ||
546 | switch (pm_event) { | ||
547 | case PM_SUSPEND_PREPARE: | ||
548 | /* | ||
549 | * This is necessary, because the A4R domain has to be "on" | ||
550 | * when suspend_device_irqs() and resume_device_irqs() are | ||
551 | * executed during system suspend and resume, respectively, so | ||
552 | * that those functions don't crash while accessing the INTCS. | ||
553 | */ | ||
554 | pm_genpd_poweron(&sh7372_a4r.genpd); | ||
555 | break; | ||
556 | case PM_POST_SUSPEND: | ||
557 | pm_genpd_poweroff_unused(); | ||
558 | break; | ||
559 | } | ||
560 | |||
561 | return NOTIFY_DONE; | ||
562 | } | ||
563 | |||
467 | static void sh7372_suspend_init(void) | 564 | static void sh7372_suspend_init(void) |
468 | { | 565 | { |
469 | shmobile_suspend_ops.enter = sh7372_enter_suspend; | 566 | shmobile_suspend_ops.enter = sh7372_enter_suspend; |
567 | pm_notifier(sh7372_pm_notifier_fn, 0); | ||
470 | } | 568 | } |
471 | #else | 569 | #else |
472 | static void sh7372_suspend_init(void) {} | 570 | static void sh7372_suspend_init(void) {} |
@@ -482,8 +580,6 @@ void __init sh7372_pm_init(void) | |||
482 | /* do not convert A3SM, A3SP, A3SG, A4R power down into A4S */ | 580 | /* do not convert A3SM, A3SP, A3SG, A4R power down into A4S */ |
483 | __raw_writel(0, PDNSEL); | 581 | __raw_writel(0, PDNSEL); |
484 | 582 | ||
485 | sh7372_a3sp_init(); | ||
486 | |||
487 | sh7372_suspend_init(); | 583 | sh7372_suspend_init(); |
488 | sh7372_cpuidle_init(); | 584 | sh7372_cpuidle_init(); |
489 | } | 585 | } |
diff --git a/arch/arm/mach-shmobile/setup-sh7372.c b/arch/arm/mach-shmobile/setup-sh7372.c index 2380389e6ac5..c197f9d29d04 100644 --- a/arch/arm/mach-shmobile/setup-sh7372.c +++ b/arch/arm/mach-shmobile/setup-sh7372.c | |||
@@ -994,12 +994,16 @@ void __init sh7372_add_standard_devices(void) | |||
994 | sh7372_init_pm_domain(&sh7372_a4r); | 994 | sh7372_init_pm_domain(&sh7372_a4r); |
995 | sh7372_init_pm_domain(&sh7372_a3rv); | 995 | sh7372_init_pm_domain(&sh7372_a3rv); |
996 | sh7372_init_pm_domain(&sh7372_a3ri); | 996 | sh7372_init_pm_domain(&sh7372_a3ri); |
997 | sh7372_init_pm_domain(&sh7372_a3sg); | 997 | sh7372_init_pm_domain(&sh7372_a4s); |
998 | sh7372_init_pm_domain(&sh7372_a3sp); | 998 | sh7372_init_pm_domain(&sh7372_a3sp); |
999 | sh7372_init_pm_domain(&sh7372_a3sg); | ||
999 | 1000 | ||
1000 | sh7372_pm_add_subdomain(&sh7372_a4lc, &sh7372_a3rv); | 1001 | sh7372_pm_add_subdomain(&sh7372_a4lc, &sh7372_a3rv); |
1001 | sh7372_pm_add_subdomain(&sh7372_a4r, &sh7372_a4lc); | 1002 | sh7372_pm_add_subdomain(&sh7372_a4r, &sh7372_a4lc); |
1002 | 1003 | ||
1004 | sh7372_pm_add_subdomain(&sh7372_a4s, &sh7372_a3sg); | ||
1005 | sh7372_pm_add_subdomain(&sh7372_a4s, &sh7372_a3sp); | ||
1006 | |||
1003 | platform_add_devices(sh7372_early_devices, | 1007 | platform_add_devices(sh7372_early_devices, |
1004 | ARRAY_SIZE(sh7372_early_devices)); | 1008 | ARRAY_SIZE(sh7372_early_devices)); |
1005 | 1009 | ||
diff --git a/arch/arm/mach-shmobile/sleep-sh7372.S b/arch/arm/mach-shmobile/sleep-sh7372.S index f3ab3c5810ea..1d564674451d 100644 --- a/arch/arm/mach-shmobile/sleep-sh7372.S +++ b/arch/arm/mach-shmobile/sleep-sh7372.S | |||
@@ -37,13 +37,18 @@ | |||
37 | #if defined(CONFIG_SUSPEND) || defined(CONFIG_CPU_IDLE) | 37 | #if defined(CONFIG_SUSPEND) || defined(CONFIG_CPU_IDLE) |
38 | .align 12 | 38 | .align 12 |
39 | .text | 39 | .text |
40 | .global sh7372_resume_core_standby_a3sm | 40 | .global sh7372_resume_core_standby_sysc |
41 | sh7372_resume_core_standby_a3sm: | 41 | sh7372_resume_core_standby_sysc: |
42 | ldr pc, 1f | 42 | ldr pc, 1f |
43 | 1: .long cpu_resume - PAGE_OFFSET + PLAT_PHYS_OFFSET | 43 | 1: .long cpu_resume - PAGE_OFFSET + PLAT_PHYS_OFFSET |
44 | 44 | ||
45 | .global sh7372_do_idle_a3sm | 45 | #define SPDCR 0xe6180008 |
46 | sh7372_do_idle_a3sm: | 46 | |
47 | /* A3SM & A4S power down */ | ||
48 | .global sh7372_do_idle_sysc | ||
49 | sh7372_do_idle_sysc: | ||
50 | mov r8, r0 /* sleep mode passed in r0 */ | ||
51 | |||
47 | /* | 52 | /* |
48 | * Clear the SCTLR.C bit to prevent further data cache | 53 | * Clear the SCTLR.C bit to prevent further data cache |
49 | * allocation. Clearing SCTLR.C would make all the data accesses | 54 | * allocation. Clearing SCTLR.C would make all the data accesses |
@@ -80,13 +85,9 @@ sh7372_do_idle_a3sm: | |||
80 | dsb | 85 | dsb |
81 | dmb | 86 | dmb |
82 | 87 | ||
83 | #define SPDCR 0xe6180008 | 88 | /* SYSC power down */ |
84 | #define A3SM (1 << 12) | ||
85 | |||
86 | /* A3SM power down */ | ||
87 | ldr r0, =SPDCR | 89 | ldr r0, =SPDCR |
88 | ldr r1, =A3SM | 90 | str r8, [r0] |
89 | str r1, [r0] | ||
90 | 1: | 91 | 1: |
91 | b 1b | 92 | b 1b |
92 | 93 | ||
diff --git a/arch/arm/plat-samsung/include/plat/pm.h b/arch/arm/plat-samsung/include/plat/pm.h index dcf68709f9cf..a6bdee204f2a 100644 --- a/arch/arm/plat-samsung/include/plat/pm.h +++ b/arch/arm/plat-samsung/include/plat/pm.h | |||
@@ -22,6 +22,7 @@ struct sys_device; | |||
22 | #ifdef CONFIG_PM | 22 | #ifdef CONFIG_PM |
23 | 23 | ||
24 | extern __init int s3c_pm_init(void); | 24 | extern __init int s3c_pm_init(void); |
25 | extern __init int s3c64xx_pm_init(void); | ||
25 | 26 | ||
26 | #else | 27 | #else |
27 | 28 | ||
@@ -29,6 +30,11 @@ static inline int s3c_pm_init(void) | |||
29 | { | 30 | { |
30 | return 0; | 31 | return 0; |
31 | } | 32 | } |
33 | |||
34 | static inline int s3c64xx_pm_init(void) | ||
35 | { | ||
36 | return 0; | ||
37 | } | ||
32 | #endif | 38 | #endif |
33 | 39 | ||
34 | /* configuration for the IRQ mask over sleep */ | 40 | /* configuration for the IRQ mask over sleep */ |
diff --git a/drivers/base/power/Makefile b/drivers/base/power/Makefile index 81676dd17900..2e58ebb1f6c0 100644 --- a/drivers/base/power/Makefile +++ b/drivers/base/power/Makefile | |||
@@ -3,7 +3,7 @@ obj-$(CONFIG_PM_SLEEP) += main.o wakeup.o | |||
3 | obj-$(CONFIG_PM_RUNTIME) += runtime.o | 3 | obj-$(CONFIG_PM_RUNTIME) += runtime.o |
4 | obj-$(CONFIG_PM_TRACE_RTC) += trace.o | 4 | obj-$(CONFIG_PM_TRACE_RTC) += trace.o |
5 | obj-$(CONFIG_PM_OPP) += opp.o | 5 | obj-$(CONFIG_PM_OPP) += opp.o |
6 | obj-$(CONFIG_PM_GENERIC_DOMAINS) += domain.o | 6 | obj-$(CONFIG_PM_GENERIC_DOMAINS) += domain.o domain_governor.o |
7 | obj-$(CONFIG_HAVE_CLK) += clock_ops.o | 7 | obj-$(CONFIG_HAVE_CLK) += clock_ops.o |
8 | 8 | ||
9 | ccflags-$(CONFIG_DEBUG_DRIVER) := -DDEBUG | 9 | ccflags-$(CONFIG_DEBUG_DRIVER) := -DDEBUG |
diff --git a/drivers/base/power/domain.c b/drivers/base/power/domain.c index 6790cf7eba5a..92e6a9048065 100644 --- a/drivers/base/power/domain.c +++ b/drivers/base/power/domain.c | |||
@@ -15,13 +15,44 @@ | |||
15 | #include <linux/err.h> | 15 | #include <linux/err.h> |
16 | #include <linux/sched.h> | 16 | #include <linux/sched.h> |
17 | #include <linux/suspend.h> | 17 | #include <linux/suspend.h> |
18 | #include <linux/export.h> | ||
19 | |||
20 | #define GENPD_DEV_CALLBACK(genpd, type, callback, dev) \ | ||
21 | ({ \ | ||
22 | type (*__routine)(struct device *__d); \ | ||
23 | type __ret = (type)0; \ | ||
24 | \ | ||
25 | __routine = genpd->dev_ops.callback; \ | ||
26 | if (__routine) { \ | ||
27 | __ret = __routine(dev); \ | ||
28 | } else { \ | ||
29 | __routine = dev_gpd_data(dev)->ops.callback; \ | ||
30 | if (__routine) \ | ||
31 | __ret = __routine(dev); \ | ||
32 | } \ | ||
33 | __ret; \ | ||
34 | }) | ||
35 | |||
36 | #define GENPD_DEV_TIMED_CALLBACK(genpd, type, callback, dev, field, name) \ | ||
37 | ({ \ | ||
38 | ktime_t __start = ktime_get(); \ | ||
39 | type __retval = GENPD_DEV_CALLBACK(genpd, type, callback, dev); \ | ||
40 | s64 __elapsed = ktime_to_ns(ktime_sub(ktime_get(), __start)); \ | ||
41 | struct generic_pm_domain_data *__gpd_data = dev_gpd_data(dev); \ | ||
42 | if (__elapsed > __gpd_data->td.field) { \ | ||
43 | __gpd_data->td.field = __elapsed; \ | ||
44 | dev_warn(dev, name " latency exceeded, new value %lld ns\n", \ | ||
45 | __elapsed); \ | ||
46 | } \ | ||
47 | __retval; \ | ||
48 | }) | ||
18 | 49 | ||
19 | static LIST_HEAD(gpd_list); | 50 | static LIST_HEAD(gpd_list); |
20 | static DEFINE_MUTEX(gpd_list_lock); | 51 | static DEFINE_MUTEX(gpd_list_lock); |
21 | 52 | ||
22 | #ifdef CONFIG_PM | 53 | #ifdef CONFIG_PM |
23 | 54 | ||
24 | static struct generic_pm_domain *dev_to_genpd(struct device *dev) | 55 | struct generic_pm_domain *dev_to_genpd(struct device *dev) |
25 | { | 56 | { |
26 | if (IS_ERR_OR_NULL(dev->pm_domain)) | 57 | if (IS_ERR_OR_NULL(dev->pm_domain)) |
27 | return ERR_PTR(-EINVAL); | 58 | return ERR_PTR(-EINVAL); |
@@ -29,6 +60,31 @@ static struct generic_pm_domain *dev_to_genpd(struct device *dev) | |||
29 | return pd_to_genpd(dev->pm_domain); | 60 | return pd_to_genpd(dev->pm_domain); |
30 | } | 61 | } |
31 | 62 | ||
63 | static int genpd_stop_dev(struct generic_pm_domain *genpd, struct device *dev) | ||
64 | { | ||
65 | return GENPD_DEV_TIMED_CALLBACK(genpd, int, stop, dev, | ||
66 | stop_latency_ns, "stop"); | ||
67 | } | ||
68 | |||
69 | static int genpd_start_dev(struct generic_pm_domain *genpd, struct device *dev) | ||
70 | { | ||
71 | return GENPD_DEV_TIMED_CALLBACK(genpd, int, start, dev, | ||
72 | start_latency_ns, "start"); | ||
73 | } | ||
74 | |||
75 | static int genpd_save_dev(struct generic_pm_domain *genpd, struct device *dev) | ||
76 | { | ||
77 | return GENPD_DEV_TIMED_CALLBACK(genpd, int, save_state, dev, | ||
78 | save_state_latency_ns, "state save"); | ||
79 | } | ||
80 | |||
81 | static int genpd_restore_dev(struct generic_pm_domain *genpd, struct device *dev) | ||
82 | { | ||
83 | return GENPD_DEV_TIMED_CALLBACK(genpd, int, restore_state, dev, | ||
84 | restore_state_latency_ns, | ||
85 | "state restore"); | ||
86 | } | ||
87 | |||
32 | static bool genpd_sd_counter_dec(struct generic_pm_domain *genpd) | 88 | static bool genpd_sd_counter_dec(struct generic_pm_domain *genpd) |
33 | { | 89 | { |
34 | bool ret = false; | 90 | bool ret = false; |
@@ -145,9 +201,21 @@ int __pm_genpd_poweron(struct generic_pm_domain *genpd) | |||
145 | } | 201 | } |
146 | 202 | ||
147 | if (genpd->power_on) { | 203 | if (genpd->power_on) { |
204 | ktime_t time_start = ktime_get(); | ||
205 | s64 elapsed_ns; | ||
206 | |||
148 | ret = genpd->power_on(genpd); | 207 | ret = genpd->power_on(genpd); |
149 | if (ret) | 208 | if (ret) |
150 | goto err; | 209 | goto err; |
210 | |||
211 | elapsed_ns = ktime_to_ns(ktime_sub(ktime_get(), time_start)); | ||
212 | if (elapsed_ns > genpd->power_on_latency_ns) { | ||
213 | genpd->power_on_latency_ns = elapsed_ns; | ||
214 | if (genpd->name) | ||
215 | pr_warning("%s: Power-on latency exceeded, " | ||
216 | "new value %lld ns\n", genpd->name, | ||
217 | elapsed_ns); | ||
218 | } | ||
151 | } | 219 | } |
152 | 220 | ||
153 | genpd_set_active(genpd); | 221 | genpd_set_active(genpd); |
@@ -190,7 +258,6 @@ static int __pm_genpd_save_device(struct pm_domain_data *pdd, | |||
190 | { | 258 | { |
191 | struct generic_pm_domain_data *gpd_data = to_gpd_data(pdd); | 259 | struct generic_pm_domain_data *gpd_data = to_gpd_data(pdd); |
192 | struct device *dev = pdd->dev; | 260 | struct device *dev = pdd->dev; |
193 | struct device_driver *drv = dev->driver; | ||
194 | int ret = 0; | 261 | int ret = 0; |
195 | 262 | ||
196 | if (gpd_data->need_restore) | 263 | if (gpd_data->need_restore) |
@@ -198,15 +265,9 @@ static int __pm_genpd_save_device(struct pm_domain_data *pdd, | |||
198 | 265 | ||
199 | mutex_unlock(&genpd->lock); | 266 | mutex_unlock(&genpd->lock); |
200 | 267 | ||
201 | if (drv && drv->pm && drv->pm->runtime_suspend) { | 268 | genpd_start_dev(genpd, dev); |
202 | if (genpd->start_device) | 269 | ret = genpd_save_dev(genpd, dev); |
203 | genpd->start_device(dev); | 270 | genpd_stop_dev(genpd, dev); |
204 | |||
205 | ret = drv->pm->runtime_suspend(dev); | ||
206 | |||
207 | if (genpd->stop_device) | ||
208 | genpd->stop_device(dev); | ||
209 | } | ||
210 | 271 | ||
211 | mutex_lock(&genpd->lock); | 272 | mutex_lock(&genpd->lock); |
212 | 273 | ||
@@ -227,22 +288,15 @@ static void __pm_genpd_restore_device(struct pm_domain_data *pdd, | |||
227 | { | 288 | { |
228 | struct generic_pm_domain_data *gpd_data = to_gpd_data(pdd); | 289 | struct generic_pm_domain_data *gpd_data = to_gpd_data(pdd); |
229 | struct device *dev = pdd->dev; | 290 | struct device *dev = pdd->dev; |
230 | struct device_driver *drv = dev->driver; | ||
231 | 291 | ||
232 | if (!gpd_data->need_restore) | 292 | if (!gpd_data->need_restore) |
233 | return; | 293 | return; |
234 | 294 | ||
235 | mutex_unlock(&genpd->lock); | 295 | mutex_unlock(&genpd->lock); |
236 | 296 | ||
237 | if (drv && drv->pm && drv->pm->runtime_resume) { | 297 | genpd_start_dev(genpd, dev); |
238 | if (genpd->start_device) | 298 | genpd_restore_dev(genpd, dev); |
239 | genpd->start_device(dev); | 299 | genpd_stop_dev(genpd, dev); |
240 | |||
241 | drv->pm->runtime_resume(dev); | ||
242 | |||
243 | if (genpd->stop_device) | ||
244 | genpd->stop_device(dev); | ||
245 | } | ||
246 | 300 | ||
247 | mutex_lock(&genpd->lock); | 301 | mutex_lock(&genpd->lock); |
248 | 302 | ||
@@ -354,11 +408,16 @@ static int pm_genpd_poweroff(struct generic_pm_domain *genpd) | |||
354 | } | 408 | } |
355 | 409 | ||
356 | if (genpd->power_off) { | 410 | if (genpd->power_off) { |
411 | ktime_t time_start; | ||
412 | s64 elapsed_ns; | ||
413 | |||
357 | if (atomic_read(&genpd->sd_count) > 0) { | 414 | if (atomic_read(&genpd->sd_count) > 0) { |
358 | ret = -EBUSY; | 415 | ret = -EBUSY; |
359 | goto out; | 416 | goto out; |
360 | } | 417 | } |
361 | 418 | ||
419 | time_start = ktime_get(); | ||
420 | |||
362 | /* | 421 | /* |
363 | * If sd_count > 0 at this point, one of the subdomains hasn't | 422 | * If sd_count > 0 at this point, one of the subdomains hasn't |
364 | * managed to call pm_genpd_poweron() for the master yet after | 423 | * managed to call pm_genpd_poweron() for the master yet after |
@@ -372,9 +431,29 @@ static int pm_genpd_poweroff(struct generic_pm_domain *genpd) | |||
372 | genpd_set_active(genpd); | 431 | genpd_set_active(genpd); |
373 | goto out; | 432 | goto out; |
374 | } | 433 | } |
434 | |||
435 | elapsed_ns = ktime_to_ns(ktime_sub(ktime_get(), time_start)); | ||
436 | if (elapsed_ns > genpd->power_off_latency_ns) { | ||
437 | genpd->power_off_latency_ns = elapsed_ns; | ||
438 | if (genpd->name) | ||
439 | pr_warning("%s: Power-off latency exceeded, " | ||
440 | "new value %lld ns\n", genpd->name, | ||
441 | elapsed_ns); | ||
442 | } | ||
375 | } | 443 | } |
376 | 444 | ||
377 | genpd->status = GPD_STATE_POWER_OFF; | 445 | genpd->status = GPD_STATE_POWER_OFF; |
446 | genpd->power_off_time = ktime_get(); | ||
447 | |||
448 | /* Update PM QoS information for devices in the domain. */ | ||
449 | list_for_each_entry_reverse(pdd, &genpd->dev_list, list_node) { | ||
450 | struct gpd_timing_data *td = &to_gpd_data(pdd)->td; | ||
451 | |||
452 | pm_runtime_update_max_time_suspended(pdd->dev, | ||
453 | td->start_latency_ns + | ||
454 | td->restore_state_latency_ns + | ||
455 | genpd->power_on_latency_ns); | ||
456 | } | ||
378 | 457 | ||
379 | list_for_each_entry(link, &genpd->slave_links, slave_node) { | 458 | list_for_each_entry(link, &genpd->slave_links, slave_node) { |
380 | genpd_sd_counter_dec(link->master); | 459 | genpd_sd_counter_dec(link->master); |
@@ -413,6 +492,8 @@ static void genpd_power_off_work_fn(struct work_struct *work) | |||
413 | static int pm_genpd_runtime_suspend(struct device *dev) | 492 | static int pm_genpd_runtime_suspend(struct device *dev) |
414 | { | 493 | { |
415 | struct generic_pm_domain *genpd; | 494 | struct generic_pm_domain *genpd; |
495 | bool (*stop_ok)(struct device *__dev); | ||
496 | int ret; | ||
416 | 497 | ||
417 | dev_dbg(dev, "%s()\n", __func__); | 498 | dev_dbg(dev, "%s()\n", __func__); |
418 | 499 | ||
@@ -422,11 +503,16 @@ static int pm_genpd_runtime_suspend(struct device *dev) | |||
422 | 503 | ||
423 | might_sleep_if(!genpd->dev_irq_safe); | 504 | might_sleep_if(!genpd->dev_irq_safe); |
424 | 505 | ||
425 | if (genpd->stop_device) { | 506 | stop_ok = genpd->gov ? genpd->gov->stop_ok : NULL; |
426 | int ret = genpd->stop_device(dev); | 507 | if (stop_ok && !stop_ok(dev)) |
427 | if (ret) | 508 | return -EBUSY; |
428 | return ret; | 509 | |
429 | } | 510 | ret = genpd_stop_dev(genpd, dev); |
511 | if (ret) | ||
512 | return ret; | ||
513 | |||
514 | pm_runtime_update_max_time_suspended(dev, | ||
515 | dev_gpd_data(dev)->td.start_latency_ns); | ||
430 | 516 | ||
431 | /* | 517 | /* |
432 | * If power.irq_safe is set, this routine will be run with interrupts | 518 | * If power.irq_safe is set, this routine will be run with interrupts |
@@ -502,8 +588,7 @@ static int pm_genpd_runtime_resume(struct device *dev) | |||
502 | mutex_unlock(&genpd->lock); | 588 | mutex_unlock(&genpd->lock); |
503 | 589 | ||
504 | out: | 590 | out: |
505 | if (genpd->start_device) | 591 | genpd_start_dev(genpd, dev); |
506 | genpd->start_device(dev); | ||
507 | 592 | ||
508 | return 0; | 593 | return 0; |
509 | } | 594 | } |
@@ -534,6 +619,52 @@ static inline void genpd_power_off_work_fn(struct work_struct *work) {} | |||
534 | 619 | ||
535 | #ifdef CONFIG_PM_SLEEP | 620 | #ifdef CONFIG_PM_SLEEP |
536 | 621 | ||
622 | static bool genpd_dev_active_wakeup(struct generic_pm_domain *genpd, | ||
623 | struct device *dev) | ||
624 | { | ||
625 | return GENPD_DEV_CALLBACK(genpd, bool, active_wakeup, dev); | ||
626 | } | ||
627 | |||
628 | static int genpd_suspend_dev(struct generic_pm_domain *genpd, struct device *dev) | ||
629 | { | ||
630 | return GENPD_DEV_CALLBACK(genpd, int, suspend, dev); | ||
631 | } | ||
632 | |||
633 | static int genpd_suspend_late(struct generic_pm_domain *genpd, struct device *dev) | ||
634 | { | ||
635 | return GENPD_DEV_CALLBACK(genpd, int, suspend_late, dev); | ||
636 | } | ||
637 | |||
638 | static int genpd_resume_early(struct generic_pm_domain *genpd, struct device *dev) | ||
639 | { | ||
640 | return GENPD_DEV_CALLBACK(genpd, int, resume_early, dev); | ||
641 | } | ||
642 | |||
643 | static int genpd_resume_dev(struct generic_pm_domain *genpd, struct device *dev) | ||
644 | { | ||
645 | return GENPD_DEV_CALLBACK(genpd, int, resume, dev); | ||
646 | } | ||
647 | |||
648 | static int genpd_freeze_dev(struct generic_pm_domain *genpd, struct device *dev) | ||
649 | { | ||
650 | return GENPD_DEV_CALLBACK(genpd, int, freeze, dev); | ||
651 | } | ||
652 | |||
653 | static int genpd_freeze_late(struct generic_pm_domain *genpd, struct device *dev) | ||
654 | { | ||
655 | return GENPD_DEV_CALLBACK(genpd, int, freeze_late, dev); | ||
656 | } | ||
657 | |||
658 | static int genpd_thaw_early(struct generic_pm_domain *genpd, struct device *dev) | ||
659 | { | ||
660 | return GENPD_DEV_CALLBACK(genpd, int, thaw_early, dev); | ||
661 | } | ||
662 | |||
663 | static int genpd_thaw_dev(struct generic_pm_domain *genpd, struct device *dev) | ||
664 | { | ||
665 | return GENPD_DEV_CALLBACK(genpd, int, thaw, dev); | ||
666 | } | ||
667 | |||
537 | /** | 668 | /** |
538 | * pm_genpd_sync_poweroff - Synchronously power off a PM domain and its masters. | 669 | * pm_genpd_sync_poweroff - Synchronously power off a PM domain and its masters. |
539 | * @genpd: PM domain to power off, if possible. | 670 | * @genpd: PM domain to power off, if possible. |
@@ -590,7 +721,7 @@ static bool resume_needed(struct device *dev, struct generic_pm_domain *genpd) | |||
590 | if (!device_can_wakeup(dev)) | 721 | if (!device_can_wakeup(dev)) |
591 | return false; | 722 | return false; |
592 | 723 | ||
593 | active_wakeup = genpd->active_wakeup && genpd->active_wakeup(dev); | 724 | active_wakeup = genpd_dev_active_wakeup(genpd, dev); |
594 | return device_may_wakeup(dev) ? active_wakeup : !active_wakeup; | 725 | return device_may_wakeup(dev) ? active_wakeup : !active_wakeup; |
595 | } | 726 | } |
596 | 727 | ||
@@ -646,7 +777,7 @@ static int pm_genpd_prepare(struct device *dev) | |||
646 | /* | 777 | /* |
647 | * The PM domain must be in the GPD_STATE_ACTIVE state at this point, | 778 | * The PM domain must be in the GPD_STATE_ACTIVE state at this point, |
648 | * so pm_genpd_poweron() will return immediately, but if the device | 779 | * so pm_genpd_poweron() will return immediately, but if the device |
649 | * is suspended (e.g. it's been stopped by .stop_device()), we need | 780 | * is suspended (e.g. it's been stopped by genpd_stop_dev()), we need |
650 | * to make it operational. | 781 | * to make it operational. |
651 | */ | 782 | */ |
652 | pm_runtime_resume(dev); | 783 | pm_runtime_resume(dev); |
@@ -685,7 +816,7 @@ static int pm_genpd_suspend(struct device *dev) | |||
685 | if (IS_ERR(genpd)) | 816 | if (IS_ERR(genpd)) |
686 | return -EINVAL; | 817 | return -EINVAL; |
687 | 818 | ||
688 | return genpd->suspend_power_off ? 0 : pm_generic_suspend(dev); | 819 | return genpd->suspend_power_off ? 0 : genpd_suspend_dev(genpd, dev); |
689 | } | 820 | } |
690 | 821 | ||
691 | /** | 822 | /** |
@@ -710,16 +841,14 @@ static int pm_genpd_suspend_noirq(struct device *dev) | |||
710 | if (genpd->suspend_power_off) | 841 | if (genpd->suspend_power_off) |
711 | return 0; | 842 | return 0; |
712 | 843 | ||
713 | ret = pm_generic_suspend_noirq(dev); | 844 | ret = genpd_suspend_late(genpd, dev); |
714 | if (ret) | 845 | if (ret) |
715 | return ret; | 846 | return ret; |
716 | 847 | ||
717 | if (dev->power.wakeup_path | 848 | if (dev->power.wakeup_path && genpd_dev_active_wakeup(genpd, dev)) |
718 | && genpd->active_wakeup && genpd->active_wakeup(dev)) | ||
719 | return 0; | 849 | return 0; |
720 | 850 | ||
721 | if (genpd->stop_device) | 851 | genpd_stop_dev(genpd, dev); |
722 | genpd->stop_device(dev); | ||
723 | 852 | ||
724 | /* | 853 | /* |
725 | * Since all of the "noirq" callbacks are executed sequentially, it is | 854 | * Since all of the "noirq" callbacks are executed sequentially, it is |
@@ -761,10 +890,9 @@ static int pm_genpd_resume_noirq(struct device *dev) | |||
761 | */ | 890 | */ |
762 | pm_genpd_poweron(genpd); | 891 | pm_genpd_poweron(genpd); |
763 | genpd->suspended_count--; | 892 | genpd->suspended_count--; |
764 | if (genpd->start_device) | 893 | genpd_start_dev(genpd, dev); |
765 | genpd->start_device(dev); | ||
766 | 894 | ||
767 | return pm_generic_resume_noirq(dev); | 895 | return genpd_resume_early(genpd, dev); |
768 | } | 896 | } |
769 | 897 | ||
770 | /** | 898 | /** |
@@ -785,7 +913,7 @@ static int pm_genpd_resume(struct device *dev) | |||
785 | if (IS_ERR(genpd)) | 913 | if (IS_ERR(genpd)) |
786 | return -EINVAL; | 914 | return -EINVAL; |
787 | 915 | ||
788 | return genpd->suspend_power_off ? 0 : pm_generic_resume(dev); | 916 | return genpd->suspend_power_off ? 0 : genpd_resume_dev(genpd, dev); |
789 | } | 917 | } |
790 | 918 | ||
791 | /** | 919 | /** |
@@ -806,7 +934,7 @@ static int pm_genpd_freeze(struct device *dev) | |||
806 | if (IS_ERR(genpd)) | 934 | if (IS_ERR(genpd)) |
807 | return -EINVAL; | 935 | return -EINVAL; |
808 | 936 | ||
809 | return genpd->suspend_power_off ? 0 : pm_generic_freeze(dev); | 937 | return genpd->suspend_power_off ? 0 : genpd_freeze_dev(genpd, dev); |
810 | } | 938 | } |
811 | 939 | ||
812 | /** | 940 | /** |
@@ -832,12 +960,11 @@ static int pm_genpd_freeze_noirq(struct device *dev) | |||
832 | if (genpd->suspend_power_off) | 960 | if (genpd->suspend_power_off) |
833 | return 0; | 961 | return 0; |
834 | 962 | ||
835 | ret = pm_generic_freeze_noirq(dev); | 963 | ret = genpd_freeze_late(genpd, dev); |
836 | if (ret) | 964 | if (ret) |
837 | return ret; | 965 | return ret; |
838 | 966 | ||
839 | if (genpd->stop_device) | 967 | genpd_stop_dev(genpd, dev); |
840 | genpd->stop_device(dev); | ||
841 | 968 | ||
842 | return 0; | 969 | return 0; |
843 | } | 970 | } |
@@ -864,10 +991,9 @@ static int pm_genpd_thaw_noirq(struct device *dev) | |||
864 | if (genpd->suspend_power_off) | 991 | if (genpd->suspend_power_off) |
865 | return 0; | 992 | return 0; |
866 | 993 | ||
867 | if (genpd->start_device) | 994 | genpd_start_dev(genpd, dev); |
868 | genpd->start_device(dev); | ||
869 | 995 | ||
870 | return pm_generic_thaw_noirq(dev); | 996 | return genpd_thaw_early(genpd, dev); |
871 | } | 997 | } |
872 | 998 | ||
873 | /** | 999 | /** |
@@ -888,72 +1014,7 @@ static int pm_genpd_thaw(struct device *dev) | |||
888 | if (IS_ERR(genpd)) | 1014 | if (IS_ERR(genpd)) |
889 | return -EINVAL; | 1015 | return -EINVAL; |
890 | 1016 | ||
891 | return genpd->suspend_power_off ? 0 : pm_generic_thaw(dev); | 1017 | return genpd->suspend_power_off ? 0 : genpd_thaw_dev(genpd, dev); |
892 | } | ||
893 | |||
894 | /** | ||
895 | * pm_genpd_dev_poweroff - Power off a device belonging to an I/O PM domain. | ||
896 | * @dev: Device to suspend. | ||
897 | * | ||
898 | * Power off a device under the assumption that its pm_domain field points to | ||
899 | * the domain member of an object of type struct generic_pm_domain representing | ||
900 | * a PM domain consisting of I/O devices. | ||
901 | */ | ||
902 | static int pm_genpd_dev_poweroff(struct device *dev) | ||
903 | { | ||
904 | struct generic_pm_domain *genpd; | ||
905 | |||
906 | dev_dbg(dev, "%s()\n", __func__); | ||
907 | |||
908 | genpd = dev_to_genpd(dev); | ||
909 | if (IS_ERR(genpd)) | ||
910 | return -EINVAL; | ||
911 | |||
912 | return genpd->suspend_power_off ? 0 : pm_generic_poweroff(dev); | ||
913 | } | ||
914 | |||
915 | /** | ||
916 | * pm_genpd_dev_poweroff_noirq - Late power off of a device from a PM domain. | ||
917 | * @dev: Device to suspend. | ||
918 | * | ||
919 | * Carry out a late powering off of a device under the assumption that its | ||
920 | * pm_domain field points to the domain member of an object of type | ||
921 | * struct generic_pm_domain representing a PM domain consisting of I/O devices. | ||
922 | */ | ||
923 | static int pm_genpd_dev_poweroff_noirq(struct device *dev) | ||
924 | { | ||
925 | struct generic_pm_domain *genpd; | ||
926 | int ret; | ||
927 | |||
928 | dev_dbg(dev, "%s()\n", __func__); | ||
929 | |||
930 | genpd = dev_to_genpd(dev); | ||
931 | if (IS_ERR(genpd)) | ||
932 | return -EINVAL; | ||
933 | |||
934 | if (genpd->suspend_power_off) | ||
935 | return 0; | ||
936 | |||
937 | ret = pm_generic_poweroff_noirq(dev); | ||
938 | if (ret) | ||
939 | return ret; | ||
940 | |||
941 | if (dev->power.wakeup_path | ||
942 | && genpd->active_wakeup && genpd->active_wakeup(dev)) | ||
943 | return 0; | ||
944 | |||
945 | if (genpd->stop_device) | ||
946 | genpd->stop_device(dev); | ||
947 | |||
948 | /* | ||
949 | * Since all of the "noirq" callbacks are executed sequentially, it is | ||
950 | * guaranteed that this function will never run twice in parallel for | ||
951 | * the same PM domain, so it is not necessary to use locking here. | ||
952 | */ | ||
953 | genpd->suspended_count++; | ||
954 | pm_genpd_sync_poweroff(genpd); | ||
955 | |||
956 | return 0; | ||
957 | } | 1018 | } |
958 | 1019 | ||
959 | /** | 1020 | /** |
@@ -993,31 +1054,9 @@ static int pm_genpd_restore_noirq(struct device *dev) | |||
993 | 1054 | ||
994 | pm_genpd_poweron(genpd); | 1055 | pm_genpd_poweron(genpd); |
995 | genpd->suspended_count--; | 1056 | genpd->suspended_count--; |
996 | if (genpd->start_device) | 1057 | genpd_start_dev(genpd, dev); |
997 | genpd->start_device(dev); | ||
998 | |||
999 | return pm_generic_restore_noirq(dev); | ||
1000 | } | ||
1001 | |||
1002 | /** | ||
1003 | * pm_genpd_restore - Restore a device belonging to an I/O power domain. | ||
1004 | * @dev: Device to resume. | ||
1005 | * | ||
1006 | * Restore a device under the assumption that its pm_domain field points to the | ||
1007 | * domain member of an object of type struct generic_pm_domain representing | ||
1008 | * a power domain consisting of I/O devices. | ||
1009 | */ | ||
1010 | static int pm_genpd_restore(struct device *dev) | ||
1011 | { | ||
1012 | struct generic_pm_domain *genpd; | ||
1013 | |||
1014 | dev_dbg(dev, "%s()\n", __func__); | ||
1015 | |||
1016 | genpd = dev_to_genpd(dev); | ||
1017 | if (IS_ERR(genpd)) | ||
1018 | return -EINVAL; | ||
1019 | 1058 | ||
1020 | return genpd->suspend_power_off ? 0 : pm_generic_restore(dev); | 1059 | return genpd_resume_early(genpd, dev); |
1021 | } | 1060 | } |
1022 | 1061 | ||
1023 | /** | 1062 | /** |
@@ -1067,20 +1106,19 @@ static void pm_genpd_complete(struct device *dev) | |||
1067 | #define pm_genpd_freeze_noirq NULL | 1106 | #define pm_genpd_freeze_noirq NULL |
1068 | #define pm_genpd_thaw_noirq NULL | 1107 | #define pm_genpd_thaw_noirq NULL |
1069 | #define pm_genpd_thaw NULL | 1108 | #define pm_genpd_thaw NULL |
1070 | #define pm_genpd_dev_poweroff_noirq NULL | ||
1071 | #define pm_genpd_dev_poweroff NULL | ||
1072 | #define pm_genpd_restore_noirq NULL | 1109 | #define pm_genpd_restore_noirq NULL |
1073 | #define pm_genpd_restore NULL | ||
1074 | #define pm_genpd_complete NULL | 1110 | #define pm_genpd_complete NULL |
1075 | 1111 | ||
1076 | #endif /* CONFIG_PM_SLEEP */ | 1112 | #endif /* CONFIG_PM_SLEEP */ |
1077 | 1113 | ||
1078 | /** | 1114 | /** |
1079 | * pm_genpd_add_device - Add a device to an I/O PM domain. | 1115 | * __pm_genpd_add_device - Add a device to an I/O PM domain. |
1080 | * @genpd: PM domain to add the device to. | 1116 | * @genpd: PM domain to add the device to. |
1081 | * @dev: Device to be added. | 1117 | * @dev: Device to be added. |
1118 | * @td: Set of PM QoS timing parameters to attach to the device. | ||
1082 | */ | 1119 | */ |
1083 | int pm_genpd_add_device(struct generic_pm_domain *genpd, struct device *dev) | 1120 | int __pm_genpd_add_device(struct generic_pm_domain *genpd, struct device *dev, |
1121 | struct gpd_timing_data *td) | ||
1084 | { | 1122 | { |
1085 | struct generic_pm_domain_data *gpd_data; | 1123 | struct generic_pm_domain_data *gpd_data; |
1086 | struct pm_domain_data *pdd; | 1124 | struct pm_domain_data *pdd; |
@@ -1123,6 +1161,8 @@ int pm_genpd_add_device(struct generic_pm_domain *genpd, struct device *dev) | |||
1123 | gpd_data->base.dev = dev; | 1161 | gpd_data->base.dev = dev; |
1124 | gpd_data->need_restore = false; | 1162 | gpd_data->need_restore = false; |
1125 | list_add_tail(&gpd_data->base.list_node, &genpd->dev_list); | 1163 | list_add_tail(&gpd_data->base.list_node, &genpd->dev_list); |
1164 | if (td) | ||
1165 | gpd_data->td = *td; | ||
1126 | 1166 | ||
1127 | out: | 1167 | out: |
1128 | genpd_release_lock(genpd); | 1168 | genpd_release_lock(genpd); |
@@ -1280,6 +1320,204 @@ int pm_genpd_remove_subdomain(struct generic_pm_domain *genpd, | |||
1280 | } | 1320 | } |
1281 | 1321 | ||
1282 | /** | 1322 | /** |
1323 | * pm_genpd_add_callbacks - Add PM domain callbacks to a given device. | ||
1324 | * @dev: Device to add the callbacks to. | ||
1325 | * @ops: Set of callbacks to add. | ||
1326 | * @td: Timing data to add to the device along with the callbacks (optional). | ||
1327 | */ | ||
1328 | int pm_genpd_add_callbacks(struct device *dev, struct gpd_dev_ops *ops, | ||
1329 | struct gpd_timing_data *td) | ||
1330 | { | ||
1331 | struct pm_domain_data *pdd; | ||
1332 | int ret = 0; | ||
1333 | |||
1334 | if (!(dev && dev->power.subsys_data && ops)) | ||
1335 | return -EINVAL; | ||
1336 | |||
1337 | pm_runtime_disable(dev); | ||
1338 | device_pm_lock(); | ||
1339 | |||
1340 | pdd = dev->power.subsys_data->domain_data; | ||
1341 | if (pdd) { | ||
1342 | struct generic_pm_domain_data *gpd_data = to_gpd_data(pdd); | ||
1343 | |||
1344 | gpd_data->ops = *ops; | ||
1345 | if (td) | ||
1346 | gpd_data->td = *td; | ||
1347 | } else { | ||
1348 | ret = -EINVAL; | ||
1349 | } | ||
1350 | |||
1351 | device_pm_unlock(); | ||
1352 | pm_runtime_enable(dev); | ||
1353 | |||
1354 | return ret; | ||
1355 | } | ||
1356 | EXPORT_SYMBOL_GPL(pm_genpd_add_callbacks); | ||
1357 | |||
1358 | /** | ||
1359 | * __pm_genpd_remove_callbacks - Remove PM domain callbacks from a given device. | ||
1360 | * @dev: Device to remove the callbacks from. | ||
1361 | * @clear_td: If set, clear the device's timing data too. | ||
1362 | */ | ||
1363 | int __pm_genpd_remove_callbacks(struct device *dev, bool clear_td) | ||
1364 | { | ||
1365 | struct pm_domain_data *pdd; | ||
1366 | int ret = 0; | ||
1367 | |||
1368 | if (!(dev && dev->power.subsys_data)) | ||
1369 | return -EINVAL; | ||
1370 | |||
1371 | pm_runtime_disable(dev); | ||
1372 | device_pm_lock(); | ||
1373 | |||
1374 | pdd = dev->power.subsys_data->domain_data; | ||
1375 | if (pdd) { | ||
1376 | struct generic_pm_domain_data *gpd_data = to_gpd_data(pdd); | ||
1377 | |||
1378 | gpd_data->ops = (struct gpd_dev_ops){ 0 }; | ||
1379 | if (clear_td) | ||
1380 | gpd_data->td = (struct gpd_timing_data){ 0 }; | ||
1381 | } else { | ||
1382 | ret = -EINVAL; | ||
1383 | } | ||
1384 | |||
1385 | device_pm_unlock(); | ||
1386 | pm_runtime_enable(dev); | ||
1387 | |||
1388 | return ret; | ||
1389 | } | ||
1390 | EXPORT_SYMBOL_GPL(__pm_genpd_remove_callbacks); | ||
1391 | |||
1392 | /* Default device callbacks for generic PM domains. */ | ||
1393 | |||
1394 | /** | ||
1395 | * pm_genpd_default_save_state - Default "save device state" for PM domians. | ||
1396 | * @dev: Device to handle. | ||
1397 | */ | ||
1398 | static int pm_genpd_default_save_state(struct device *dev) | ||
1399 | { | ||
1400 | int (*cb)(struct device *__dev); | ||
1401 | struct device_driver *drv = dev->driver; | ||
1402 | |||
1403 | cb = dev_gpd_data(dev)->ops.save_state; | ||
1404 | if (cb) | ||
1405 | return cb(dev); | ||
1406 | |||
1407 | if (drv && drv->pm && drv->pm->runtime_suspend) | ||
1408 | return drv->pm->runtime_suspend(dev); | ||
1409 | |||
1410 | return 0; | ||
1411 | } | ||
1412 | |||
1413 | /** | ||
1414 | * pm_genpd_default_restore_state - Default PM domians "restore device state". | ||
1415 | * @dev: Device to handle. | ||
1416 | */ | ||
1417 | static int pm_genpd_default_restore_state(struct device *dev) | ||
1418 | { | ||
1419 | int (*cb)(struct device *__dev); | ||
1420 | struct device_driver *drv = dev->driver; | ||
1421 | |||
1422 | cb = dev_gpd_data(dev)->ops.restore_state; | ||
1423 | if (cb) | ||
1424 | return cb(dev); | ||
1425 | |||
1426 | if (drv && drv->pm && drv->pm->runtime_resume) | ||
1427 | return drv->pm->runtime_resume(dev); | ||
1428 | |||
1429 | return 0; | ||
1430 | } | ||
1431 | |||
1432 | /** | ||
1433 | * pm_genpd_default_suspend - Default "device suspend" for PM domians. | ||
1434 | * @dev: Device to handle. | ||
1435 | */ | ||
1436 | static int pm_genpd_default_suspend(struct device *dev) | ||
1437 | { | ||
1438 | int (*cb)(struct device *__dev) = dev_gpd_data(dev)->ops.suspend; | ||
1439 | |||
1440 | return cb ? cb(dev) : pm_generic_suspend(dev); | ||
1441 | } | ||
1442 | |||
1443 | /** | ||
1444 | * pm_genpd_default_suspend_late - Default "late device suspend" for PM domians. | ||
1445 | * @dev: Device to handle. | ||
1446 | */ | ||
1447 | static int pm_genpd_default_suspend_late(struct device *dev) | ||
1448 | { | ||
1449 | int (*cb)(struct device *__dev) = dev_gpd_data(dev)->ops.suspend_late; | ||
1450 | |||
1451 | return cb ? cb(dev) : pm_generic_suspend_noirq(dev); | ||
1452 | } | ||
1453 | |||
1454 | /** | ||
1455 | * pm_genpd_default_resume_early - Default "early device resume" for PM domians. | ||
1456 | * @dev: Device to handle. | ||
1457 | */ | ||
1458 | static int pm_genpd_default_resume_early(struct device *dev) | ||
1459 | { | ||
1460 | int (*cb)(struct device *__dev) = dev_gpd_data(dev)->ops.resume_early; | ||
1461 | |||
1462 | return cb ? cb(dev) : pm_generic_resume_noirq(dev); | ||
1463 | } | ||
1464 | |||
1465 | /** | ||
1466 | * pm_genpd_default_resume - Default "device resume" for PM domians. | ||
1467 | * @dev: Device to handle. | ||
1468 | */ | ||
1469 | static int pm_genpd_default_resume(struct device *dev) | ||
1470 | { | ||
1471 | int (*cb)(struct device *__dev) = dev_gpd_data(dev)->ops.resume; | ||
1472 | |||
1473 | return cb ? cb(dev) : pm_generic_resume(dev); | ||
1474 | } | ||
1475 | |||
1476 | /** | ||
1477 | * pm_genpd_default_freeze - Default "device freeze" for PM domians. | ||
1478 | * @dev: Device to handle. | ||
1479 | */ | ||
1480 | static int pm_genpd_default_freeze(struct device *dev) | ||
1481 | { | ||
1482 | int (*cb)(struct device *__dev) = dev_gpd_data(dev)->ops.freeze; | ||
1483 | |||
1484 | return cb ? cb(dev) : pm_generic_freeze(dev); | ||
1485 | } | ||
1486 | |||
1487 | /** | ||
1488 | * pm_genpd_default_freeze_late - Default "late device freeze" for PM domians. | ||
1489 | * @dev: Device to handle. | ||
1490 | */ | ||
1491 | static int pm_genpd_default_freeze_late(struct device *dev) | ||
1492 | { | ||
1493 | int (*cb)(struct device *__dev) = dev_gpd_data(dev)->ops.freeze_late; | ||
1494 | |||
1495 | return cb ? cb(dev) : pm_generic_freeze_noirq(dev); | ||
1496 | } | ||
1497 | |||
1498 | /** | ||
1499 | * pm_genpd_default_thaw_early - Default "early device thaw" for PM domians. | ||
1500 | * @dev: Device to handle. | ||
1501 | */ | ||
1502 | static int pm_genpd_default_thaw_early(struct device *dev) | ||
1503 | { | ||
1504 | int (*cb)(struct device *__dev) = dev_gpd_data(dev)->ops.thaw_early; | ||
1505 | |||
1506 | return cb ? cb(dev) : pm_generic_thaw_noirq(dev); | ||
1507 | } | ||
1508 | |||
1509 | /** | ||
1510 | * pm_genpd_default_thaw - Default "device thaw" for PM domians. | ||
1511 | * @dev: Device to handle. | ||
1512 | */ | ||
1513 | static int pm_genpd_default_thaw(struct device *dev) | ||
1514 | { | ||
1515 | int (*cb)(struct device *__dev) = dev_gpd_data(dev)->ops.thaw; | ||
1516 | |||
1517 | return cb ? cb(dev) : pm_generic_thaw(dev); | ||
1518 | } | ||
1519 | |||
1520 | /** | ||
1283 | * pm_genpd_init - Initialize a generic I/O PM domain object. | 1521 | * pm_genpd_init - Initialize a generic I/O PM domain object. |
1284 | * @genpd: PM domain object to initialize. | 1522 | * @genpd: PM domain object to initialize. |
1285 | * @gov: PM domain governor to associate with the domain (may be NULL). | 1523 | * @gov: PM domain governor to associate with the domain (may be NULL). |
@@ -1305,6 +1543,7 @@ void pm_genpd_init(struct generic_pm_domain *genpd, | |||
1305 | genpd->resume_count = 0; | 1543 | genpd->resume_count = 0; |
1306 | genpd->device_count = 0; | 1544 | genpd->device_count = 0; |
1307 | genpd->suspended_count = 0; | 1545 | genpd->suspended_count = 0; |
1546 | genpd->max_off_time_ns = -1; | ||
1308 | genpd->domain.ops.runtime_suspend = pm_genpd_runtime_suspend; | 1547 | genpd->domain.ops.runtime_suspend = pm_genpd_runtime_suspend; |
1309 | genpd->domain.ops.runtime_resume = pm_genpd_runtime_resume; | 1548 | genpd->domain.ops.runtime_resume = pm_genpd_runtime_resume; |
1310 | genpd->domain.ops.runtime_idle = pm_generic_runtime_idle; | 1549 | genpd->domain.ops.runtime_idle = pm_generic_runtime_idle; |
@@ -1317,11 +1556,21 @@ void pm_genpd_init(struct generic_pm_domain *genpd, | |||
1317 | genpd->domain.ops.freeze_noirq = pm_genpd_freeze_noirq; | 1556 | genpd->domain.ops.freeze_noirq = pm_genpd_freeze_noirq; |
1318 | genpd->domain.ops.thaw_noirq = pm_genpd_thaw_noirq; | 1557 | genpd->domain.ops.thaw_noirq = pm_genpd_thaw_noirq; |
1319 | genpd->domain.ops.thaw = pm_genpd_thaw; | 1558 | genpd->domain.ops.thaw = pm_genpd_thaw; |
1320 | genpd->domain.ops.poweroff = pm_genpd_dev_poweroff; | 1559 | genpd->domain.ops.poweroff = pm_genpd_suspend; |
1321 | genpd->domain.ops.poweroff_noirq = pm_genpd_dev_poweroff_noirq; | 1560 | genpd->domain.ops.poweroff_noirq = pm_genpd_suspend_noirq; |
1322 | genpd->domain.ops.restore_noirq = pm_genpd_restore_noirq; | 1561 | genpd->domain.ops.restore_noirq = pm_genpd_restore_noirq; |
1323 | genpd->domain.ops.restore = pm_genpd_restore; | 1562 | genpd->domain.ops.restore = pm_genpd_resume; |
1324 | genpd->domain.ops.complete = pm_genpd_complete; | 1563 | genpd->domain.ops.complete = pm_genpd_complete; |
1564 | genpd->dev_ops.save_state = pm_genpd_default_save_state; | ||
1565 | genpd->dev_ops.restore_state = pm_genpd_default_restore_state; | ||
1566 | genpd->dev_ops.suspend = pm_genpd_default_suspend; | ||
1567 | genpd->dev_ops.suspend_late = pm_genpd_default_suspend_late; | ||
1568 | genpd->dev_ops.resume_early = pm_genpd_default_resume_early; | ||
1569 | genpd->dev_ops.resume = pm_genpd_default_resume; | ||
1570 | genpd->dev_ops.freeze = pm_genpd_default_freeze; | ||
1571 | genpd->dev_ops.freeze_late = pm_genpd_default_freeze_late; | ||
1572 | genpd->dev_ops.thaw_early = pm_genpd_default_thaw_early; | ||
1573 | genpd->dev_ops.thaw = pm_genpd_default_thaw; | ||
1325 | mutex_lock(&gpd_list_lock); | 1574 | mutex_lock(&gpd_list_lock); |
1326 | list_add(&genpd->gpd_list_node, &gpd_list); | 1575 | list_add(&genpd->gpd_list_node, &gpd_list); |
1327 | mutex_unlock(&gpd_list_lock); | 1576 | mutex_unlock(&gpd_list_lock); |
diff --git a/drivers/base/power/domain_governor.c b/drivers/base/power/domain_governor.c new file mode 100644 index 000000000000..51527ee92d10 --- /dev/null +++ b/drivers/base/power/domain_governor.c | |||
@@ -0,0 +1,156 @@ | |||
1 | /* | ||
2 | * drivers/base/power/domain_governor.c - Governors for device PM domains. | ||
3 | * | ||
4 | * Copyright (C) 2011 Rafael J. Wysocki <rjw@sisk.pl>, Renesas Electronics Corp. | ||
5 | * | ||
6 | * This file is released under the GPLv2. | ||
7 | */ | ||
8 | |||
9 | #include <linux/init.h> | ||
10 | #include <linux/kernel.h> | ||
11 | #include <linux/pm_domain.h> | ||
12 | #include <linux/pm_qos.h> | ||
13 | #include <linux/hrtimer.h> | ||
14 | |||
15 | /** | ||
16 | * default_stop_ok - Default PM domain governor routine for stopping devices. | ||
17 | * @dev: Device to check. | ||
18 | */ | ||
19 | bool default_stop_ok(struct device *dev) | ||
20 | { | ||
21 | struct gpd_timing_data *td = &dev_gpd_data(dev)->td; | ||
22 | |||
23 | dev_dbg(dev, "%s()\n", __func__); | ||
24 | |||
25 | if (dev->power.max_time_suspended_ns < 0 || td->break_even_ns == 0) | ||
26 | return true; | ||
27 | |||
28 | return td->stop_latency_ns + td->start_latency_ns < td->break_even_ns | ||
29 | && td->break_even_ns < dev->power.max_time_suspended_ns; | ||
30 | } | ||
31 | |||
32 | /** | ||
33 | * default_power_down_ok - Default generic PM domain power off governor routine. | ||
34 | * @pd: PM domain to check. | ||
35 | * | ||
36 | * This routine must be executed under the PM domain's lock. | ||
37 | */ | ||
38 | static bool default_power_down_ok(struct dev_pm_domain *pd) | ||
39 | { | ||
40 | struct generic_pm_domain *genpd = pd_to_genpd(pd); | ||
41 | struct gpd_link *link; | ||
42 | struct pm_domain_data *pdd; | ||
43 | s64 min_dev_off_time_ns; | ||
44 | s64 off_on_time_ns; | ||
45 | ktime_t time_now = ktime_get(); | ||
46 | |||
47 | off_on_time_ns = genpd->power_off_latency_ns + | ||
48 | genpd->power_on_latency_ns; | ||
49 | /* | ||
50 | * It doesn't make sense to remove power from the domain if saving | ||
51 | * the state of all devices in it and the power off/power on operations | ||
52 | * take too much time. | ||
53 | * | ||
54 | * All devices in this domain have been stopped already at this point. | ||
55 | */ | ||
56 | list_for_each_entry(pdd, &genpd->dev_list, list_node) { | ||
57 | if (pdd->dev->driver) | ||
58 | off_on_time_ns += | ||
59 | to_gpd_data(pdd)->td.save_state_latency_ns; | ||
60 | } | ||
61 | |||
62 | /* | ||
63 | * Check if subdomains can be off for enough time. | ||
64 | * | ||
65 | * All subdomains have been powered off already at this point. | ||
66 | */ | ||
67 | list_for_each_entry(link, &genpd->master_links, master_node) { | ||
68 | struct generic_pm_domain *sd = link->slave; | ||
69 | s64 sd_max_off_ns = sd->max_off_time_ns; | ||
70 | |||
71 | if (sd_max_off_ns < 0) | ||
72 | continue; | ||
73 | |||
74 | sd_max_off_ns -= ktime_to_ns(ktime_sub(time_now, | ||
75 | sd->power_off_time)); | ||
76 | /* | ||
77 | * Check if the subdomain is allowed to be off long enough for | ||
78 | * the current domain to turn off and on (that's how much time | ||
79 | * it will have to wait worst case). | ||
80 | */ | ||
81 | if (sd_max_off_ns <= off_on_time_ns) | ||
82 | return false; | ||
83 | } | ||
84 | |||
85 | /* | ||
86 | * Check if the devices in the domain can be off enough time. | ||
87 | */ | ||
88 | min_dev_off_time_ns = -1; | ||
89 | list_for_each_entry(pdd, &genpd->dev_list, list_node) { | ||
90 | struct gpd_timing_data *td; | ||
91 | struct device *dev = pdd->dev; | ||
92 | s64 dev_off_time_ns; | ||
93 | |||
94 | if (!dev->driver || dev->power.max_time_suspended_ns < 0) | ||
95 | continue; | ||
96 | |||
97 | td = &to_gpd_data(pdd)->td; | ||
98 | dev_off_time_ns = dev->power.max_time_suspended_ns - | ||
99 | (td->start_latency_ns + td->restore_state_latency_ns + | ||
100 | ktime_to_ns(ktime_sub(time_now, | ||
101 | dev->power.suspend_time))); | ||
102 | if (dev_off_time_ns <= off_on_time_ns) | ||
103 | return false; | ||
104 | |||
105 | if (min_dev_off_time_ns > dev_off_time_ns | ||
106 | || min_dev_off_time_ns < 0) | ||
107 | min_dev_off_time_ns = dev_off_time_ns; | ||
108 | } | ||
109 | |||
110 | if (min_dev_off_time_ns < 0) { | ||
111 | /* | ||
112 | * There are no latency constraints, so the domain can spend | ||
113 | * arbitrary time in the "off" state. | ||
114 | */ | ||
115 | genpd->max_off_time_ns = -1; | ||
116 | return true; | ||
117 | } | ||
118 | |||
119 | /* | ||
120 | * The difference between the computed minimum delta and the time needed | ||
121 | * to turn the domain on is the maximum theoretical time this domain can | ||
122 | * spend in the "off" state. | ||
123 | */ | ||
124 | min_dev_off_time_ns -= genpd->power_on_latency_ns; | ||
125 | |||
126 | /* | ||
127 | * If the difference between the computed minimum delta and the time | ||
128 | * needed to turn the domain off and back on on is smaller than the | ||
129 | * domain's power break even time, removing power from the domain is not | ||
130 | * worth it. | ||
131 | */ | ||
132 | if (genpd->break_even_ns > | ||
133 | min_dev_off_time_ns - genpd->power_off_latency_ns) | ||
134 | return false; | ||
135 | |||
136 | genpd->max_off_time_ns = min_dev_off_time_ns; | ||
137 | return true; | ||
138 | } | ||
139 | |||
140 | struct dev_power_governor simple_qos_governor = { | ||
141 | .stop_ok = default_stop_ok, | ||
142 | .power_down_ok = default_power_down_ok, | ||
143 | }; | ||
144 | |||
145 | static bool always_on_power_down_ok(struct dev_pm_domain *domain) | ||
146 | { | ||
147 | return false; | ||
148 | } | ||
149 | |||
150 | /** | ||
151 | * pm_genpd_gov_always_on - A governor implementing an always-on policy | ||
152 | */ | ||
153 | struct dev_power_governor pm_domain_always_on_gov = { | ||
154 | .power_down_ok = always_on_power_down_ok, | ||
155 | .stop_ok = default_stop_ok, | ||
156 | }; | ||
diff --git a/drivers/base/power/qos.c b/drivers/base/power/qos.c index 03f4bd069ca8..c5d358837461 100644 --- a/drivers/base/power/qos.c +++ b/drivers/base/power/qos.c | |||
@@ -420,3 +420,28 @@ int dev_pm_qos_remove_global_notifier(struct notifier_block *notifier) | |||
420 | return blocking_notifier_chain_unregister(&dev_pm_notifiers, notifier); | 420 | return blocking_notifier_chain_unregister(&dev_pm_notifiers, notifier); |
421 | } | 421 | } |
422 | EXPORT_SYMBOL_GPL(dev_pm_qos_remove_global_notifier); | 422 | EXPORT_SYMBOL_GPL(dev_pm_qos_remove_global_notifier); |
423 | |||
424 | /** | ||
425 | * dev_pm_qos_add_ancestor_request - Add PM QoS request for device's ancestor. | ||
426 | * @dev: Device whose ancestor to add the request for. | ||
427 | * @req: Pointer to the preallocated handle. | ||
428 | * @value: Constraint latency value. | ||
429 | */ | ||
430 | int dev_pm_qos_add_ancestor_request(struct device *dev, | ||
431 | struct dev_pm_qos_request *req, s32 value) | ||
432 | { | ||
433 | struct device *ancestor = dev->parent; | ||
434 | int error = -ENODEV; | ||
435 | |||
436 | while (ancestor && !ancestor->power.ignore_children) | ||
437 | ancestor = ancestor->parent; | ||
438 | |||
439 | if (ancestor) | ||
440 | error = dev_pm_qos_add_request(ancestor, req, value); | ||
441 | |||
442 | if (error) | ||
443 | req->dev = NULL; | ||
444 | |||
445 | return error; | ||
446 | } | ||
447 | EXPORT_SYMBOL_GPL(dev_pm_qos_add_ancestor_request); | ||
diff --git a/drivers/input/touchscreen/st1232.c b/drivers/input/touchscreen/st1232.c index 4ab371358b33..8825fe37d433 100644 --- a/drivers/input/touchscreen/st1232.c +++ b/drivers/input/touchscreen/st1232.c | |||
@@ -23,6 +23,7 @@ | |||
23 | #include <linux/input.h> | 23 | #include <linux/input.h> |
24 | #include <linux/interrupt.h> | 24 | #include <linux/interrupt.h> |
25 | #include <linux/module.h> | 25 | #include <linux/module.h> |
26 | #include <linux/pm_qos.h> | ||
26 | #include <linux/slab.h> | 27 | #include <linux/slab.h> |
27 | #include <linux/types.h> | 28 | #include <linux/types.h> |
28 | 29 | ||
@@ -46,6 +47,7 @@ struct st1232_ts_data { | |||
46 | struct i2c_client *client; | 47 | struct i2c_client *client; |
47 | struct input_dev *input_dev; | 48 | struct input_dev *input_dev; |
48 | struct st1232_ts_finger finger[MAX_FINGERS]; | 49 | struct st1232_ts_finger finger[MAX_FINGERS]; |
50 | struct dev_pm_qos_request low_latency_req; | ||
49 | }; | 51 | }; |
50 | 52 | ||
51 | static int st1232_ts_read_data(struct st1232_ts_data *ts) | 53 | static int st1232_ts_read_data(struct st1232_ts_data *ts) |
@@ -118,8 +120,17 @@ static irqreturn_t st1232_ts_irq_handler(int irq, void *dev_id) | |||
118 | } | 120 | } |
119 | 121 | ||
120 | /* SYN_MT_REPORT only if no contact */ | 122 | /* SYN_MT_REPORT only if no contact */ |
121 | if (!count) | 123 | if (!count) { |
122 | input_mt_sync(input_dev); | 124 | input_mt_sync(input_dev); |
125 | if (ts->low_latency_req.dev) { | ||
126 | dev_pm_qos_remove_request(&ts->low_latency_req); | ||
127 | ts->low_latency_req.dev = NULL; | ||
128 | } | ||
129 | } else if (!ts->low_latency_req.dev) { | ||
130 | /* First contact, request 100 us latency. */ | ||
131 | dev_pm_qos_add_ancestor_request(&ts->client->dev, | ||
132 | &ts->low_latency_req, 100); | ||
133 | } | ||
123 | 134 | ||
124 | /* SYN_REPORT */ | 135 | /* SYN_REPORT */ |
125 | input_sync(input_dev); | 136 | input_sync(input_dev); |
diff --git a/drivers/sh/intc/core.c b/drivers/sh/intc/core.c index 8b7a141ff35e..be5a025eeca3 100644 --- a/drivers/sh/intc/core.c +++ b/drivers/sh/intc/core.c | |||
@@ -354,6 +354,8 @@ int __init register_intc_controller(struct intc_desc *desc) | |||
354 | if (desc->force_enable) | 354 | if (desc->force_enable) |
355 | intc_enable_disable_enum(desc, d, desc->force_enable, 1); | 355 | intc_enable_disable_enum(desc, d, desc->force_enable, 1); |
356 | 356 | ||
357 | d->skip_suspend = desc->skip_syscore_suspend; | ||
358 | |||
357 | nr_intc_controllers++; | 359 | nr_intc_controllers++; |
358 | 360 | ||
359 | return 0; | 361 | return 0; |
@@ -386,6 +388,9 @@ static int intc_suspend(void) | |||
386 | list_for_each_entry(d, &intc_list, list) { | 388 | list_for_each_entry(d, &intc_list, list) { |
387 | int irq; | 389 | int irq; |
388 | 390 | ||
391 | if (d->skip_suspend) | ||
392 | continue; | ||
393 | |||
389 | /* enable wakeup irqs belonging to this intc controller */ | 394 | /* enable wakeup irqs belonging to this intc controller */ |
390 | for_each_active_irq(irq) { | 395 | for_each_active_irq(irq) { |
391 | struct irq_data *data; | 396 | struct irq_data *data; |
@@ -409,6 +414,9 @@ static void intc_resume(void) | |||
409 | list_for_each_entry(d, &intc_list, list) { | 414 | list_for_each_entry(d, &intc_list, list) { |
410 | int irq; | 415 | int irq; |
411 | 416 | ||
417 | if (d->skip_suspend) | ||
418 | continue; | ||
419 | |||
412 | for_each_active_irq(irq) { | 420 | for_each_active_irq(irq) { |
413 | struct irq_data *data; | 421 | struct irq_data *data; |
414 | struct irq_chip *chip; | 422 | struct irq_chip *chip; |
diff --git a/drivers/sh/intc/internals.h b/drivers/sh/intc/internals.h index 5b934851efa8..b3fe1cf25a28 100644 --- a/drivers/sh/intc/internals.h +++ b/drivers/sh/intc/internals.h | |||
@@ -67,6 +67,7 @@ struct intc_desc_int { | |||
67 | struct intc_window *window; | 67 | struct intc_window *window; |
68 | unsigned int nr_windows; | 68 | unsigned int nr_windows; |
69 | struct irq_chip chip; | 69 | struct irq_chip chip; |
70 | bool skip_suspend; | ||
70 | }; | 71 | }; |
71 | 72 | ||
72 | 73 | ||
diff --git a/include/linux/pm_domain.h b/include/linux/pm_domain.h index 65633e5a2bc0..a03a0ad998b8 100644 --- a/include/linux/pm_domain.h +++ b/include/linux/pm_domain.h | |||
@@ -10,6 +10,7 @@ | |||
10 | #define _LINUX_PM_DOMAIN_H | 10 | #define _LINUX_PM_DOMAIN_H |
11 | 11 | ||
12 | #include <linux/device.h> | 12 | #include <linux/device.h> |
13 | #include <linux/err.h> | ||
13 | 14 | ||
14 | enum gpd_status { | 15 | enum gpd_status { |
15 | GPD_STATE_ACTIVE = 0, /* PM domain is active */ | 16 | GPD_STATE_ACTIVE = 0, /* PM domain is active */ |
@@ -21,6 +22,23 @@ enum gpd_status { | |||
21 | 22 | ||
22 | struct dev_power_governor { | 23 | struct dev_power_governor { |
23 | bool (*power_down_ok)(struct dev_pm_domain *domain); | 24 | bool (*power_down_ok)(struct dev_pm_domain *domain); |
25 | bool (*stop_ok)(struct device *dev); | ||
26 | }; | ||
27 | |||
28 | struct gpd_dev_ops { | ||
29 | int (*start)(struct device *dev); | ||
30 | int (*stop)(struct device *dev); | ||
31 | int (*save_state)(struct device *dev); | ||
32 | int (*restore_state)(struct device *dev); | ||
33 | int (*suspend)(struct device *dev); | ||
34 | int (*suspend_late)(struct device *dev); | ||
35 | int (*resume_early)(struct device *dev); | ||
36 | int (*resume)(struct device *dev); | ||
37 | int (*freeze)(struct device *dev); | ||
38 | int (*freeze_late)(struct device *dev); | ||
39 | int (*thaw_early)(struct device *dev); | ||
40 | int (*thaw)(struct device *dev); | ||
41 | bool (*active_wakeup)(struct device *dev); | ||
24 | }; | 42 | }; |
25 | 43 | ||
26 | struct generic_pm_domain { | 44 | struct generic_pm_domain { |
@@ -32,6 +50,7 @@ struct generic_pm_domain { | |||
32 | struct mutex lock; | 50 | struct mutex lock; |
33 | struct dev_power_governor *gov; | 51 | struct dev_power_governor *gov; |
34 | struct work_struct power_off_work; | 52 | struct work_struct power_off_work; |
53 | char *name; | ||
35 | unsigned int in_progress; /* Number of devices being suspended now */ | 54 | unsigned int in_progress; /* Number of devices being suspended now */ |
36 | atomic_t sd_count; /* Number of subdomains with power "on" */ | 55 | atomic_t sd_count; /* Number of subdomains with power "on" */ |
37 | enum gpd_status status; /* Current state of the domain */ | 56 | enum gpd_status status; /* Current state of the domain */ |
@@ -44,10 +63,13 @@ struct generic_pm_domain { | |||
44 | bool suspend_power_off; /* Power status before system suspend */ | 63 | bool suspend_power_off; /* Power status before system suspend */ |
45 | bool dev_irq_safe; /* Device callbacks are IRQ-safe */ | 64 | bool dev_irq_safe; /* Device callbacks are IRQ-safe */ |
46 | int (*power_off)(struct generic_pm_domain *domain); | 65 | int (*power_off)(struct generic_pm_domain *domain); |
66 | s64 power_off_latency_ns; | ||
47 | int (*power_on)(struct generic_pm_domain *domain); | 67 | int (*power_on)(struct generic_pm_domain *domain); |
48 | int (*start_device)(struct device *dev); | 68 | s64 power_on_latency_ns; |
49 | int (*stop_device)(struct device *dev); | 69 | struct gpd_dev_ops dev_ops; |
50 | bool (*active_wakeup)(struct device *dev); | 70 | s64 break_even_ns; /* Power break even for the entire domain. */ |
71 | s64 max_off_time_ns; /* Maximum allowed "suspended" time. */ | ||
72 | ktime_t power_off_time; | ||
51 | }; | 73 | }; |
52 | 74 | ||
53 | static inline struct generic_pm_domain *pd_to_genpd(struct dev_pm_domain *pd) | 75 | static inline struct generic_pm_domain *pd_to_genpd(struct dev_pm_domain *pd) |
@@ -62,8 +84,18 @@ struct gpd_link { | |||
62 | struct list_head slave_node; | 84 | struct list_head slave_node; |
63 | }; | 85 | }; |
64 | 86 | ||
87 | struct gpd_timing_data { | ||
88 | s64 stop_latency_ns; | ||
89 | s64 start_latency_ns; | ||
90 | s64 save_state_latency_ns; | ||
91 | s64 restore_state_latency_ns; | ||
92 | s64 break_even_ns; | ||
93 | }; | ||
94 | |||
65 | struct generic_pm_domain_data { | 95 | struct generic_pm_domain_data { |
66 | struct pm_domain_data base; | 96 | struct pm_domain_data base; |
97 | struct gpd_dev_ops ops; | ||
98 | struct gpd_timing_data td; | ||
67 | bool need_restore; | 99 | bool need_restore; |
68 | }; | 100 | }; |
69 | 101 | ||
@@ -73,18 +105,54 @@ static inline struct generic_pm_domain_data *to_gpd_data(struct pm_domain_data * | |||
73 | } | 105 | } |
74 | 106 | ||
75 | #ifdef CONFIG_PM_GENERIC_DOMAINS | 107 | #ifdef CONFIG_PM_GENERIC_DOMAINS |
76 | extern int pm_genpd_add_device(struct generic_pm_domain *genpd, | 108 | static inline struct generic_pm_domain_data *dev_gpd_data(struct device *dev) |
77 | struct device *dev); | 109 | { |
110 | return to_gpd_data(dev->power.subsys_data->domain_data); | ||
111 | } | ||
112 | |||
113 | extern struct dev_power_governor simple_qos_governor; | ||
114 | |||
115 | extern struct generic_pm_domain *dev_to_genpd(struct device *dev); | ||
116 | extern int __pm_genpd_add_device(struct generic_pm_domain *genpd, | ||
117 | struct device *dev, | ||
118 | struct gpd_timing_data *td); | ||
119 | |||
120 | static inline int pm_genpd_add_device(struct generic_pm_domain *genpd, | ||
121 | struct device *dev) | ||
122 | { | ||
123 | return __pm_genpd_add_device(genpd, dev, NULL); | ||
124 | } | ||
125 | |||
78 | extern int pm_genpd_remove_device(struct generic_pm_domain *genpd, | 126 | extern int pm_genpd_remove_device(struct generic_pm_domain *genpd, |
79 | struct device *dev); | 127 | struct device *dev); |
80 | extern int pm_genpd_add_subdomain(struct generic_pm_domain *genpd, | 128 | extern int pm_genpd_add_subdomain(struct generic_pm_domain *genpd, |
81 | struct generic_pm_domain *new_subdomain); | 129 | struct generic_pm_domain *new_subdomain); |
82 | extern int pm_genpd_remove_subdomain(struct generic_pm_domain *genpd, | 130 | extern int pm_genpd_remove_subdomain(struct generic_pm_domain *genpd, |
83 | struct generic_pm_domain *target); | 131 | struct generic_pm_domain *target); |
132 | extern int pm_genpd_add_callbacks(struct device *dev, | ||
133 | struct gpd_dev_ops *ops, | ||
134 | struct gpd_timing_data *td); | ||
135 | extern int __pm_genpd_remove_callbacks(struct device *dev, bool clear_td); | ||
84 | extern void pm_genpd_init(struct generic_pm_domain *genpd, | 136 | extern void pm_genpd_init(struct generic_pm_domain *genpd, |
85 | struct dev_power_governor *gov, bool is_off); | 137 | struct dev_power_governor *gov, bool is_off); |
138 | |||
86 | extern int pm_genpd_poweron(struct generic_pm_domain *genpd); | 139 | extern int pm_genpd_poweron(struct generic_pm_domain *genpd); |
140 | |||
141 | extern bool default_stop_ok(struct device *dev); | ||
142 | |||
143 | extern struct dev_power_governor pm_domain_always_on_gov; | ||
87 | #else | 144 | #else |
145 | |||
146 | static inline struct generic_pm_domain *dev_to_genpd(struct device *dev) | ||
147 | { | ||
148 | return ERR_PTR(-ENOSYS); | ||
149 | } | ||
150 | static inline int __pm_genpd_add_device(struct generic_pm_domain *genpd, | ||
151 | struct device *dev, | ||
152 | struct gpd_timing_data *td) | ||
153 | { | ||
154 | return -ENOSYS; | ||
155 | } | ||
88 | static inline int pm_genpd_add_device(struct generic_pm_domain *genpd, | 156 | static inline int pm_genpd_add_device(struct generic_pm_domain *genpd, |
89 | struct device *dev) | 157 | struct device *dev) |
90 | { | 158 | { |
@@ -105,14 +173,35 @@ static inline int pm_genpd_remove_subdomain(struct generic_pm_domain *genpd, | |||
105 | { | 173 | { |
106 | return -ENOSYS; | 174 | return -ENOSYS; |
107 | } | 175 | } |
108 | static inline void pm_genpd_init(struct generic_pm_domain *genpd, | 176 | static inline int pm_genpd_add_callbacks(struct device *dev, |
109 | struct dev_power_governor *gov, bool is_off) {} | 177 | struct gpd_dev_ops *ops, |
178 | struct gpd_timing_data *td) | ||
179 | { | ||
180 | return -ENOSYS; | ||
181 | } | ||
182 | static inline int __pm_genpd_remove_callbacks(struct device *dev, bool clear_td) | ||
183 | { | ||
184 | return -ENOSYS; | ||
185 | } | ||
186 | static inline void pm_genpd_init(struct generic_pm_domain *genpd, bool is_off) | ||
187 | { | ||
188 | } | ||
110 | static inline int pm_genpd_poweron(struct generic_pm_domain *genpd) | 189 | static inline int pm_genpd_poweron(struct generic_pm_domain *genpd) |
111 | { | 190 | { |
112 | return -ENOSYS; | 191 | return -ENOSYS; |
113 | } | 192 | } |
193 | static inline bool default_stop_ok(struct device *dev) | ||
194 | { | ||
195 | return false; | ||
196 | } | ||
197 | #define pm_domain_always_on_gov NULL | ||
114 | #endif | 198 | #endif |
115 | 199 | ||
200 | static inline int pm_genpd_remove_callbacks(struct device *dev) | ||
201 | { | ||
202 | return __pm_genpd_remove_callbacks(dev, true); | ||
203 | } | ||
204 | |||
116 | #ifdef CONFIG_PM_GENERIC_DOMAINS_RUNTIME | 205 | #ifdef CONFIG_PM_GENERIC_DOMAINS_RUNTIME |
117 | extern void genpd_queue_power_off_work(struct generic_pm_domain *genpd); | 206 | extern void genpd_queue_power_off_work(struct generic_pm_domain *genpd); |
118 | extern void pm_genpd_poweroff_unused(void); | 207 | extern void pm_genpd_poweroff_unused(void); |
diff --git a/include/linux/pm_qos.h b/include/linux/pm_qos.h index 775a3236343d..e5bbcbaa6f57 100644 --- a/include/linux/pm_qos.h +++ b/include/linux/pm_qos.h | |||
@@ -92,6 +92,8 @@ int dev_pm_qos_add_global_notifier(struct notifier_block *notifier); | |||
92 | int dev_pm_qos_remove_global_notifier(struct notifier_block *notifier); | 92 | int dev_pm_qos_remove_global_notifier(struct notifier_block *notifier); |
93 | void dev_pm_qos_constraints_init(struct device *dev); | 93 | void dev_pm_qos_constraints_init(struct device *dev); |
94 | void dev_pm_qos_constraints_destroy(struct device *dev); | 94 | void dev_pm_qos_constraints_destroy(struct device *dev); |
95 | int dev_pm_qos_add_ancestor_request(struct device *dev, | ||
96 | struct dev_pm_qos_request *req, s32 value); | ||
95 | #else | 97 | #else |
96 | static inline int pm_qos_update_target(struct pm_qos_constraints *c, | 98 | static inline int pm_qos_update_target(struct pm_qos_constraints *c, |
97 | struct plist_node *node, | 99 | struct plist_node *node, |
@@ -153,6 +155,9 @@ static inline void dev_pm_qos_constraints_destroy(struct device *dev) | |||
153 | { | 155 | { |
154 | dev->power.power_state = PMSG_INVALID; | 156 | dev->power.power_state = PMSG_INVALID; |
155 | } | 157 | } |
158 | static inline int dev_pm_qos_add_ancestor_request(struct device *dev, | ||
159 | struct dev_pm_qos_request *req, s32 value) | ||
160 | { return 0; } | ||
156 | #endif | 161 | #endif |
157 | 162 | ||
158 | #endif | 163 | #endif |
diff --git a/include/linux/sh_intc.h b/include/linux/sh_intc.h index 5812fefbcedf..b160645f5599 100644 --- a/include/linux/sh_intc.h +++ b/include/linux/sh_intc.h | |||
@@ -95,6 +95,7 @@ struct intc_desc { | |||
95 | unsigned int num_resources; | 95 | unsigned int num_resources; |
96 | intc_enum force_enable; | 96 | intc_enum force_enable; |
97 | intc_enum force_disable; | 97 | intc_enum force_disable; |
98 | bool skip_syscore_suspend; | ||
98 | struct intc_hw_desc hw; | 99 | struct intc_hw_desc hw; |
99 | }; | 100 | }; |
100 | 101 | ||