diff options
author | Rafael J. Wysocki <rjw@sisk.pl> | 2011-07-01 16:13:56 -0400 |
---|---|---|
committer | Rafael J. Wysocki <rjw@sisk.pl> | 2011-07-02 08:29:57 -0400 |
commit | e3e0109138376bb262b8ecf33bad0586fa131925 (patch) | |
tree | 0d078578eecee050041fc5f27976d1b0354712fc /arch/arm/mach-shmobile | |
parent | 3d5c30367cbc0c55c93bb158e824e00badc7ddc4 (diff) |
ARM / shmobile: Support for I/O power domains for SH7372 (v9)
Use the generic power domains support introduced by the previous
patch to implement support for power domains on SH7372.
Signed-off-by: Rafael J. Wysocki <rjw@sisk.pl>
Acked-by: Paul Mundt <lethal@linux-sh.org>
Diffstat (limited to 'arch/arm/mach-shmobile')
-rw-r--r-- | arch/arm/mach-shmobile/board-mackerel.c | 4 | ||||
-rw-r--r-- | arch/arm/mach-shmobile/include/mach/sh7372.h | 24 | ||||
-rw-r--r-- | arch/arm/mach-shmobile/pm-sh7372.c | 102 |
3 files changed, 130 insertions, 0 deletions
diff --git a/arch/arm/mach-shmobile/board-mackerel.c b/arch/arm/mach-shmobile/board-mackerel.c index 3802f2afabef..f93b1cb27fef 100644 --- a/arch/arm/mach-shmobile/board-mackerel.c +++ b/arch/arm/mach-shmobile/board-mackerel.c | |||
@@ -1582,6 +1582,10 @@ static void __init mackerel_init(void) | |||
1582 | 1582 | ||
1583 | platform_add_devices(mackerel_devices, ARRAY_SIZE(mackerel_devices)); | 1583 | platform_add_devices(mackerel_devices, ARRAY_SIZE(mackerel_devices)); |
1584 | 1584 | ||
1585 | sh7372_init_pm_domain(&sh7372_a4lc); | ||
1586 | sh7372_add_device_to_domain(&sh7372_a4lc, &lcdc_device); | ||
1587 | sh7372_add_device_to_domain(&sh7372_a4lc, &hdmi_lcdc_device); | ||
1588 | |||
1585 | hdmi_init_pm_clock(); | 1589 | hdmi_init_pm_clock(); |
1586 | sh7372_pm_init(); | 1590 | sh7372_pm_init(); |
1587 | } | 1591 | } |
diff --git a/arch/arm/mach-shmobile/include/mach/sh7372.h b/arch/arm/mach-shmobile/include/mach/sh7372.h index df20d7670172..495013c75c6b 100644 --- a/arch/arm/mach-shmobile/include/mach/sh7372.h +++ b/arch/arm/mach-shmobile/include/mach/sh7372.h | |||
@@ -12,6 +12,7 @@ | |||
12 | #define __ASM_SH7372_H__ | 12 | #define __ASM_SH7372_H__ |
13 | 13 | ||
14 | #include <linux/sh_clk.h> | 14 | #include <linux/sh_clk.h> |
15 | #include <linux/pm_domain.h> | ||
15 | 16 | ||
16 | /* | 17 | /* |
17 | * Pin Function Controller: | 18 | * Pin Function Controller: |
@@ -470,4 +471,27 @@ extern struct clk sh7372_fsibck_clk; | |||
470 | extern struct clk sh7372_fsidiva_clk; | 471 | extern struct clk sh7372_fsidiva_clk; |
471 | extern struct clk sh7372_fsidivb_clk; | 472 | extern struct clk sh7372_fsidivb_clk; |
472 | 473 | ||
474 | struct platform_device; | ||
475 | |||
476 | struct sh7372_pm_domain { | ||
477 | struct generic_pm_domain genpd; | ||
478 | unsigned int bit_shift; | ||
479 | }; | ||
480 | |||
481 | static inline struct sh7372_pm_domain *to_sh7372_pd(struct generic_pm_domain *d) | ||
482 | { | ||
483 | return container_of(d, struct sh7372_pm_domain, genpd); | ||
484 | } | ||
485 | |||
486 | #ifdef CONFIG_PM | ||
487 | extern struct sh7372_pm_domain sh7372_a4lc; | ||
488 | |||
489 | extern void sh7372_init_pm_domain(struct sh7372_pm_domain *sh7372_pd); | ||
490 | extern void sh7372_add_device_to_domain(struct sh7372_pm_domain *sh7372_pd, | ||
491 | struct platform_device *pdev); | ||
492 | #else | ||
493 | #define sh7372_init_pm_domain(pd) do { } while(0) | ||
494 | #define sh7372_add_device_to_domain(pd, pdev) do { } while(0) | ||
495 | #endif /* CONFIG_PM */ | ||
496 | |||
473 | #endif /* __ASM_SH7372_H__ */ | 497 | #endif /* __ASM_SH7372_H__ */ |
diff --git a/arch/arm/mach-shmobile/pm-sh7372.c b/arch/arm/mach-shmobile/pm-sh7372.c index 8e4aadf14c9f..e17f12424ec7 100644 --- a/arch/arm/mach-shmobile/pm-sh7372.c +++ b/arch/arm/mach-shmobile/pm-sh7372.c | |||
@@ -15,16 +15,118 @@ | |||
15 | #include <linux/list.h> | 15 | #include <linux/list.h> |
16 | #include <linux/err.h> | 16 | #include <linux/err.h> |
17 | #include <linux/slab.h> | 17 | #include <linux/slab.h> |
18 | #include <linux/pm_runtime.h> | ||
19 | #include <linux/platform_device.h> | ||
20 | #include <linux/delay.h> | ||
18 | #include <asm/system.h> | 21 | #include <asm/system.h> |
19 | #include <asm/io.h> | 22 | #include <asm/io.h> |
20 | #include <asm/tlbflush.h> | 23 | #include <asm/tlbflush.h> |
21 | #include <mach/common.h> | 24 | #include <mach/common.h> |
25 | #include <mach/sh7372.h> | ||
22 | 26 | ||
23 | #define SMFRAM 0xe6a70000 | 27 | #define SMFRAM 0xe6a70000 |
24 | #define SYSTBCR 0xe6150024 | 28 | #define SYSTBCR 0xe6150024 |
25 | #define SBAR 0xe6180020 | 29 | #define SBAR 0xe6180020 |
26 | #define APARMBAREA 0xe6f10020 | 30 | #define APARMBAREA 0xe6f10020 |
27 | 31 | ||
32 | #define SPDCR 0xe6180008 | ||
33 | #define SWUCR 0xe6180014 | ||
34 | #define PSTR 0xe6180080 | ||
35 | |||
36 | #define PSTR_RETRIES 100 | ||
37 | #define PSTR_DELAY_US 10 | ||
38 | |||
39 | #ifdef CONFIG_PM | ||
40 | |||
41 | static int pd_power_down(struct generic_pm_domain *genpd) | ||
42 | { | ||
43 | struct sh7372_pm_domain *sh7372_pd = to_sh7372_pd(genpd); | ||
44 | unsigned int mask = 1 << sh7372_pd->bit_shift; | ||
45 | |||
46 | if (__raw_readl(PSTR) & mask) { | ||
47 | unsigned int retry_count; | ||
48 | |||
49 | __raw_writel(mask, SPDCR); | ||
50 | |||
51 | for (retry_count = PSTR_RETRIES; retry_count; retry_count--) { | ||
52 | if (!(__raw_readl(SPDCR) & mask)) | ||
53 | break; | ||
54 | cpu_relax(); | ||
55 | } | ||
56 | } | ||
57 | |||
58 | pr_debug("sh7372 power domain down 0x%08x -> PSTR = 0x%08x\n", | ||
59 | mask, __raw_readl(PSTR)); | ||
60 | |||
61 | return 0; | ||
62 | } | ||
63 | |||
64 | static int pd_power_up(struct generic_pm_domain *genpd) | ||
65 | { | ||
66 | struct sh7372_pm_domain *sh7372_pd = to_sh7372_pd(genpd); | ||
67 | unsigned int mask = 1 << sh7372_pd->bit_shift; | ||
68 | unsigned int retry_count; | ||
69 | int ret = 0; | ||
70 | |||
71 | if (__raw_readl(PSTR) & mask) | ||
72 | goto out; | ||
73 | |||
74 | __raw_writel(mask, SWUCR); | ||
75 | |||
76 | for (retry_count = 2 * PSTR_RETRIES; retry_count; retry_count--) { | ||
77 | if (!(__raw_readl(SWUCR) & mask)) | ||
78 | goto out; | ||
79 | if (retry_count > PSTR_RETRIES) | ||
80 | udelay(PSTR_DELAY_US); | ||
81 | else | ||
82 | cpu_relax(); | ||
83 | } | ||
84 | if (__raw_readl(SWUCR) & mask) | ||
85 | ret = -EIO; | ||
86 | |||
87 | out: | ||
88 | pr_debug("sh7372 power domain up 0x%08x -> PSTR = 0x%08x\n", | ||
89 | mask, __raw_readl(PSTR)); | ||
90 | |||
91 | return ret; | ||
92 | } | ||
93 | |||
94 | static bool pd_active_wakeup(struct device *dev) | ||
95 | { | ||
96 | return true; | ||
97 | } | ||
98 | |||
99 | void sh7372_init_pm_domain(struct sh7372_pm_domain *sh7372_pd) | ||
100 | { | ||
101 | struct generic_pm_domain *genpd = &sh7372_pd->genpd; | ||
102 | |||
103 | pm_genpd_init(genpd, NULL, false); | ||
104 | genpd->stop_device = pm_clk_suspend; | ||
105 | genpd->start_device = pm_clk_resume; | ||
106 | genpd->active_wakeup = pd_active_wakeup; | ||
107 | genpd->power_off = pd_power_down; | ||
108 | genpd->power_on = pd_power_up; | ||
109 | pd_power_up(&sh7372_pd->genpd); | ||
110 | } | ||
111 | |||
112 | void sh7372_add_device_to_domain(struct sh7372_pm_domain *sh7372_pd, | ||
113 | struct platform_device *pdev) | ||
114 | { | ||
115 | struct device *dev = &pdev->dev; | ||
116 | |||
117 | if (!dev->power.subsys_data) { | ||
118 | pm_clk_init(dev); | ||
119 | pm_clk_add(dev, NULL); | ||
120 | } | ||
121 | pm_genpd_add_device(&sh7372_pd->genpd, dev); | ||
122 | } | ||
123 | |||
124 | struct sh7372_pm_domain sh7372_a4lc = { | ||
125 | .bit_shift = 1, | ||
126 | }; | ||
127 | |||
128 | #endif /* CONFIG_PM */ | ||
129 | |||
28 | static void sh7372_enter_core_standby(void) | 130 | static void sh7372_enter_core_standby(void) |
29 | { | 131 | { |
30 | void __iomem *smfram = (void __iomem *)SMFRAM; | 132 | void __iomem *smfram = (void __iomem *)SMFRAM; |