aboutsummaryrefslogtreecommitdiffstats
path: root/arch/arm
diff options
context:
space:
mode:
Diffstat (limited to 'arch/arm')
-rw-r--r--arch/arm/mach-omap2/Makefile5
-rw-r--r--arch/arm/mach-omap2/clockdomain2xxx_3xxx.c340
-rw-r--r--arch/arm/mach-omap2/clockdomain33xx.c74
-rw-r--r--arch/arm/mach-omap2/clockdomain44xx.c151
-rw-r--r--arch/arm/mach-omap2/cm2xxx.c89
-rw-r--r--arch/arm/mach-omap2/cm2xxx_3xxx.h12
-rw-r--r--arch/arm/mach-omap2/cm33xx.c56
-rw-r--r--arch/arm/mach-omap2/cm3xxx.c174
-rw-r--r--arch/arm/mach-omap2/cminst44xx.c142
-rw-r--r--arch/arm/mach-omap2/prm2xxx.c17
-rw-r--r--arch/arm/mach-omap2/prm2xxx.h6
-rw-r--r--arch/arm/mach-omap2/prm2xxx_3xxx.c43
-rw-r--r--arch/arm/mach-omap2/prm2xxx_3xxx.h8
13 files changed, 543 insertions, 574 deletions
diff --git a/arch/arm/mach-omap2/Makefile b/arch/arm/mach-omap2/Makefile
index 56a33869c8b2..3751d56853ef 100644
--- a/arch/arm/mach-omap2/Makefile
+++ b/arch/arm/mach-omap2/Makefile
@@ -133,22 +133,17 @@ obj-$(CONFIG_SOC_OMAP5) += $(powerdomain-common)
133# PRCM clockdomain control 133# PRCM clockdomain control
134clockdomain-common += clockdomain.o 134clockdomain-common += clockdomain.o
135obj-$(CONFIG_ARCH_OMAP2) += $(clockdomain-common) 135obj-$(CONFIG_ARCH_OMAP2) += $(clockdomain-common)
136obj-$(CONFIG_ARCH_OMAP2) += clockdomain2xxx_3xxx.o
137obj-$(CONFIG_ARCH_OMAP2) += clockdomains2xxx_3xxx_data.o 136obj-$(CONFIG_ARCH_OMAP2) += clockdomains2xxx_3xxx_data.o
138obj-$(CONFIG_SOC_OMAP2420) += clockdomains2420_data.o 137obj-$(CONFIG_SOC_OMAP2420) += clockdomains2420_data.o
139obj-$(CONFIG_SOC_OMAP2430) += clockdomains2430_data.o 138obj-$(CONFIG_SOC_OMAP2430) += clockdomains2430_data.o
140obj-$(CONFIG_ARCH_OMAP3) += $(clockdomain-common) 139obj-$(CONFIG_ARCH_OMAP3) += $(clockdomain-common)
141obj-$(CONFIG_ARCH_OMAP3) += clockdomain2xxx_3xxx.o
142obj-$(CONFIG_ARCH_OMAP3) += clockdomains2xxx_3xxx_data.o 140obj-$(CONFIG_ARCH_OMAP3) += clockdomains2xxx_3xxx_data.o
143obj-$(CONFIG_ARCH_OMAP3) += clockdomains3xxx_data.o 141obj-$(CONFIG_ARCH_OMAP3) += clockdomains3xxx_data.o
144obj-$(CONFIG_ARCH_OMAP4) += $(clockdomain-common) 142obj-$(CONFIG_ARCH_OMAP4) += $(clockdomain-common)
145obj-$(CONFIG_ARCH_OMAP4) += clockdomain44xx.o
146obj-$(CONFIG_ARCH_OMAP4) += clockdomains44xx_data.o 143obj-$(CONFIG_ARCH_OMAP4) += clockdomains44xx_data.o
147obj-$(CONFIG_SOC_AM33XX) += $(clockdomain-common) 144obj-$(CONFIG_SOC_AM33XX) += $(clockdomain-common)
148obj-$(CONFIG_SOC_AM33XX) += clockdomain33xx.o
149obj-$(CONFIG_SOC_AM33XX) += clockdomains33xx_data.o 145obj-$(CONFIG_SOC_AM33XX) += clockdomains33xx_data.o
150obj-$(CONFIG_SOC_OMAP5) += $(clockdomain-common) 146obj-$(CONFIG_SOC_OMAP5) += $(clockdomain-common)
151obj-$(CONFIG_SOC_OMAP5) += clockdomain44xx.o
152 147
153# Clock framework 148# Clock framework
154obj-$(CONFIG_ARCH_OMAP2) += $(clock-common) clock2xxx.o 149obj-$(CONFIG_ARCH_OMAP2) += $(clock-common) clock2xxx.o
diff --git a/arch/arm/mach-omap2/clockdomain2xxx_3xxx.c b/arch/arm/mach-omap2/clockdomain2xxx_3xxx.c
deleted file mode 100644
index 658487c34cb2..000000000000
--- a/arch/arm/mach-omap2/clockdomain2xxx_3xxx.c
+++ /dev/null
@@ -1,340 +0,0 @@
1/*
2 * OMAP2 and OMAP3 clockdomain control
3 *
4 * Copyright (C) 2008-2010 Texas Instruments, Inc.
5 * Copyright (C) 2008-2010 Nokia Corporation
6 *
7 * Derived from mach-omap2/clockdomain.c written by Paul Walmsley
8 * Rajendra Nayak <rnayak@ti.com>
9 *
10 * This program is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU General Public License version 2 as
12 * published by the Free Software Foundation.
13 */
14
15#include <linux/types.h>
16#include <plat/prcm.h>
17#include "prm.h"
18#include "prm2xxx_3xxx.h"
19#include "cm.h"
20#include "cm2xxx.h"
21#include "cm3xxx.h"
22#include "cm-regbits-24xx.h"
23#include "cm-regbits-34xx.h"
24#include "prm-regbits-24xx.h"
25#include "clockdomain.h"
26
27static int omap2_clkdm_add_wkdep(struct clockdomain *clkdm1,
28 struct clockdomain *clkdm2)
29{
30 omap2_prm_set_mod_reg_bits((1 << clkdm2->dep_bit),
31 clkdm1->pwrdm.ptr->prcm_offs, PM_WKDEP);
32 return 0;
33}
34
35static int omap2_clkdm_del_wkdep(struct clockdomain *clkdm1,
36 struct clockdomain *clkdm2)
37{
38 omap2_prm_clear_mod_reg_bits((1 << clkdm2->dep_bit),
39 clkdm1->pwrdm.ptr->prcm_offs, PM_WKDEP);
40 return 0;
41}
42
43static int omap2_clkdm_read_wkdep(struct clockdomain *clkdm1,
44 struct clockdomain *clkdm2)
45{
46 return omap2_prm_read_mod_bits_shift(clkdm1->pwrdm.ptr->prcm_offs,
47 PM_WKDEP, (1 << clkdm2->dep_bit));
48}
49
50static int omap2_clkdm_clear_all_wkdeps(struct clockdomain *clkdm)
51{
52 struct clkdm_dep *cd;
53 u32 mask = 0;
54
55 for (cd = clkdm->wkdep_srcs; cd && cd->clkdm_name; cd++) {
56 if (!cd->clkdm)
57 continue; /* only happens if data is erroneous */
58
59 /* PRM accesses are slow, so minimize them */
60 mask |= 1 << cd->clkdm->dep_bit;
61 atomic_set(&cd->wkdep_usecount, 0);
62 }
63
64 omap2_prm_clear_mod_reg_bits(mask, clkdm->pwrdm.ptr->prcm_offs,
65 PM_WKDEP);
66 return 0;
67}
68
69static int omap3_clkdm_add_sleepdep(struct clockdomain *clkdm1,
70 struct clockdomain *clkdm2)
71{
72 omap2_cm_set_mod_reg_bits((1 << clkdm2->dep_bit),
73 clkdm1->pwrdm.ptr->prcm_offs,
74 OMAP3430_CM_SLEEPDEP);
75 return 0;
76}
77
78static int omap3_clkdm_del_sleepdep(struct clockdomain *clkdm1,
79 struct clockdomain *clkdm2)
80{
81 omap2_cm_clear_mod_reg_bits((1 << clkdm2->dep_bit),
82 clkdm1->pwrdm.ptr->prcm_offs,
83 OMAP3430_CM_SLEEPDEP);
84 return 0;
85}
86
87static int omap3_clkdm_read_sleepdep(struct clockdomain *clkdm1,
88 struct clockdomain *clkdm2)
89{
90 return omap2_prm_read_mod_bits_shift(clkdm1->pwrdm.ptr->prcm_offs,
91 OMAP3430_CM_SLEEPDEP, (1 << clkdm2->dep_bit));
92}
93
94static int omap3_clkdm_clear_all_sleepdeps(struct clockdomain *clkdm)
95{
96 struct clkdm_dep *cd;
97 u32 mask = 0;
98
99 for (cd = clkdm->sleepdep_srcs; cd && cd->clkdm_name; cd++) {
100 if (!cd->clkdm)
101 continue; /* only happens if data is erroneous */
102
103 /* PRM accesses are slow, so minimize them */
104 mask |= 1 << cd->clkdm->dep_bit;
105 atomic_set(&cd->sleepdep_usecount, 0);
106 }
107 omap2_prm_clear_mod_reg_bits(mask, clkdm->pwrdm.ptr->prcm_offs,
108 OMAP3430_CM_SLEEPDEP);
109 return 0;
110}
111
112static int omap2_clkdm_sleep(struct clockdomain *clkdm)
113{
114 omap2_cm_set_mod_reg_bits(OMAP24XX_FORCESTATE_MASK,
115 clkdm->pwrdm.ptr->prcm_offs,
116 OMAP2_PM_PWSTCTRL);
117 return 0;
118}
119
120static int omap2_clkdm_wakeup(struct clockdomain *clkdm)
121{
122 omap2_cm_clear_mod_reg_bits(OMAP24XX_FORCESTATE_MASK,
123 clkdm->pwrdm.ptr->prcm_offs,
124 OMAP2_PM_PWSTCTRL);
125 return 0;
126}
127
128static void omap2_clkdm_allow_idle(struct clockdomain *clkdm)
129{
130 if (atomic_read(&clkdm->usecount) > 0)
131 _clkdm_add_autodeps(clkdm);
132
133 omap2xxx_cm_clkdm_enable_hwsup(clkdm->pwrdm.ptr->prcm_offs,
134 clkdm->clktrctrl_mask);
135}
136
137static void omap2_clkdm_deny_idle(struct clockdomain *clkdm)
138{
139 omap2xxx_cm_clkdm_disable_hwsup(clkdm->pwrdm.ptr->prcm_offs,
140 clkdm->clktrctrl_mask);
141
142 if (atomic_read(&clkdm->usecount) > 0)
143 _clkdm_del_autodeps(clkdm);
144}
145
146static void _enable_hwsup(struct clockdomain *clkdm)
147{
148 if (cpu_is_omap24xx())
149 omap2xxx_cm_clkdm_enable_hwsup(clkdm->pwrdm.ptr->prcm_offs,
150 clkdm->clktrctrl_mask);
151 else if (cpu_is_omap34xx())
152 omap3xxx_cm_clkdm_enable_hwsup(clkdm->pwrdm.ptr->prcm_offs,
153 clkdm->clktrctrl_mask);
154}
155
156static void _disable_hwsup(struct clockdomain *clkdm)
157{
158 if (cpu_is_omap24xx())
159 omap2xxx_cm_clkdm_disable_hwsup(clkdm->pwrdm.ptr->prcm_offs,
160 clkdm->clktrctrl_mask);
161 else if (cpu_is_omap34xx())
162 omap3xxx_cm_clkdm_disable_hwsup(clkdm->pwrdm.ptr->prcm_offs,
163 clkdm->clktrctrl_mask);
164}
165
166static int omap3_clkdm_sleep(struct clockdomain *clkdm)
167{
168 omap3xxx_cm_clkdm_force_sleep(clkdm->pwrdm.ptr->prcm_offs,
169 clkdm->clktrctrl_mask);
170 return 0;
171}
172
173static int omap3_clkdm_wakeup(struct clockdomain *clkdm)
174{
175 omap3xxx_cm_clkdm_force_wakeup(clkdm->pwrdm.ptr->prcm_offs,
176 clkdm->clktrctrl_mask);
177 return 0;
178}
179
180static int omap2xxx_clkdm_clk_enable(struct clockdomain *clkdm)
181{
182 bool hwsup = false;
183
184 if (!clkdm->clktrctrl_mask)
185 return 0;
186
187 hwsup = omap3xxx_cm_is_clkdm_in_hwsup(clkdm->pwrdm.ptr->prcm_offs,
188 clkdm->clktrctrl_mask);
189
190 if (hwsup) {
191 /* Disable HW transitions when we are changing deps */
192 _disable_hwsup(clkdm);
193 _clkdm_add_autodeps(clkdm);
194 _enable_hwsup(clkdm);
195 } else {
196 if (clkdm->flags & CLKDM_CAN_FORCE_WAKEUP)
197 omap2_clkdm_wakeup(clkdm);
198 }
199
200 return 0;
201}
202
203static int omap2xxx_clkdm_clk_disable(struct clockdomain *clkdm)
204{
205 bool hwsup = false;
206
207 if (!clkdm->clktrctrl_mask)
208 return 0;
209
210 hwsup = omap3xxx_cm_is_clkdm_in_hwsup(clkdm->pwrdm.ptr->prcm_offs,
211 clkdm->clktrctrl_mask);
212
213 if (hwsup) {
214 /* Disable HW transitions when we are changing deps */
215 _disable_hwsup(clkdm);
216 _clkdm_del_autodeps(clkdm);
217 _enable_hwsup(clkdm);
218 } else {
219 if (clkdm->flags & CLKDM_CAN_FORCE_SLEEP)
220 omap2_clkdm_sleep(clkdm);
221 }
222
223 return 0;
224}
225
226static void omap3_clkdm_allow_idle(struct clockdomain *clkdm)
227{
228 if (atomic_read(&clkdm->usecount) > 0)
229 _clkdm_add_autodeps(clkdm);
230
231 omap3xxx_cm_clkdm_enable_hwsup(clkdm->pwrdm.ptr->prcm_offs,
232 clkdm->clktrctrl_mask);
233}
234
235static void omap3_clkdm_deny_idle(struct clockdomain *clkdm)
236{
237 omap3xxx_cm_clkdm_disable_hwsup(clkdm->pwrdm.ptr->prcm_offs,
238 clkdm->clktrctrl_mask);
239
240 if (atomic_read(&clkdm->usecount) > 0)
241 _clkdm_del_autodeps(clkdm);
242}
243
244static int omap3xxx_clkdm_clk_enable(struct clockdomain *clkdm)
245{
246 bool hwsup = false;
247
248 if (!clkdm->clktrctrl_mask)
249 return 0;
250
251 /*
252 * The CLKDM_MISSING_IDLE_REPORTING flag documentation has
253 * more details on the unpleasant problem this is working
254 * around
255 */
256 if ((clkdm->flags & CLKDM_MISSING_IDLE_REPORTING) &&
257 (clkdm->flags & CLKDM_CAN_FORCE_WAKEUP)) {
258 omap3_clkdm_wakeup(clkdm);
259 return 0;
260 }
261
262 hwsup = omap2xxx_cm_is_clkdm_in_hwsup(clkdm->pwrdm.ptr->prcm_offs,
263 clkdm->clktrctrl_mask);
264
265 if (hwsup) {
266 /* Disable HW transitions when we are changing deps */
267 _disable_hwsup(clkdm);
268 _clkdm_add_autodeps(clkdm);
269 _enable_hwsup(clkdm);
270 } else {
271 if (clkdm->flags & CLKDM_CAN_FORCE_WAKEUP)
272 omap3_clkdm_wakeup(clkdm);
273 }
274
275 return 0;
276}
277
278static int omap3xxx_clkdm_clk_disable(struct clockdomain *clkdm)
279{
280 bool hwsup = false;
281
282 if (!clkdm->clktrctrl_mask)
283 return 0;
284
285 /*
286 * The CLKDM_MISSING_IDLE_REPORTING flag documentation has
287 * more details on the unpleasant problem this is working
288 * around
289 */
290 if (clkdm->flags & CLKDM_MISSING_IDLE_REPORTING &&
291 !(clkdm->flags & CLKDM_CAN_FORCE_SLEEP)) {
292 _enable_hwsup(clkdm);
293 return 0;
294 }
295
296 hwsup = omap2xxx_cm_is_clkdm_in_hwsup(clkdm->pwrdm.ptr->prcm_offs,
297 clkdm->clktrctrl_mask);
298
299 if (hwsup) {
300 /* Disable HW transitions when we are changing deps */
301 _disable_hwsup(clkdm);
302 _clkdm_del_autodeps(clkdm);
303 _enable_hwsup(clkdm);
304 } else {
305 if (clkdm->flags & CLKDM_CAN_FORCE_SLEEP)
306 omap3_clkdm_sleep(clkdm);
307 }
308
309 return 0;
310}
311
312struct clkdm_ops omap2_clkdm_operations = {
313 .clkdm_add_wkdep = omap2_clkdm_add_wkdep,
314 .clkdm_del_wkdep = omap2_clkdm_del_wkdep,
315 .clkdm_read_wkdep = omap2_clkdm_read_wkdep,
316 .clkdm_clear_all_wkdeps = omap2_clkdm_clear_all_wkdeps,
317 .clkdm_sleep = omap2_clkdm_sleep,
318 .clkdm_wakeup = omap2_clkdm_wakeup,
319 .clkdm_allow_idle = omap2_clkdm_allow_idle,
320 .clkdm_deny_idle = omap2_clkdm_deny_idle,
321 .clkdm_clk_enable = omap2xxx_clkdm_clk_enable,
322 .clkdm_clk_disable = omap2xxx_clkdm_clk_disable,
323};
324
325struct clkdm_ops omap3_clkdm_operations = {
326 .clkdm_add_wkdep = omap2_clkdm_add_wkdep,
327 .clkdm_del_wkdep = omap2_clkdm_del_wkdep,
328 .clkdm_read_wkdep = omap2_clkdm_read_wkdep,
329 .clkdm_clear_all_wkdeps = omap2_clkdm_clear_all_wkdeps,
330 .clkdm_add_sleepdep = omap3_clkdm_add_sleepdep,
331 .clkdm_del_sleepdep = omap3_clkdm_del_sleepdep,
332 .clkdm_read_sleepdep = omap3_clkdm_read_sleepdep,
333 .clkdm_clear_all_sleepdeps = omap3_clkdm_clear_all_sleepdeps,
334 .clkdm_sleep = omap3_clkdm_sleep,
335 .clkdm_wakeup = omap3_clkdm_wakeup,
336 .clkdm_allow_idle = omap3_clkdm_allow_idle,
337 .clkdm_deny_idle = omap3_clkdm_deny_idle,
338 .clkdm_clk_enable = omap3xxx_clkdm_clk_enable,
339 .clkdm_clk_disable = omap3xxx_clkdm_clk_disable,
340};
diff --git a/arch/arm/mach-omap2/clockdomain33xx.c b/arch/arm/mach-omap2/clockdomain33xx.c
deleted file mode 100644
index aca6388fad76..000000000000
--- a/arch/arm/mach-omap2/clockdomain33xx.c
+++ /dev/null
@@ -1,74 +0,0 @@
1/*
2 * AM33XX clockdomain control
3 *
4 * Copyright (C) 2011-2012 Texas Instruments Incorporated - http://www.ti.com/
5 * Vaibhav Hiremath <hvaibhav@ti.com>
6 *
7 * Derived from mach-omap2/clockdomain44xx.c written by Rajendra Nayak
8 *
9 * This program is free software; you can redistribute it and/or
10 * modify it under the terms of the GNU General Public License as
11 * published by the Free Software Foundation version 2.
12 *
13 * This program is distributed "as is" WITHOUT ANY WARRANTY of any
14 * kind, whether express or implied; without even the implied warranty
15 * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
17 */
18
19#include <linux/kernel.h>
20
21#include "clockdomain.h"
22#include "cm33xx.h"
23
24
25static int am33xx_clkdm_sleep(struct clockdomain *clkdm)
26{
27 am33xx_cm_clkdm_force_sleep(clkdm->cm_inst, clkdm->clkdm_offs);
28 return 0;
29}
30
31static int am33xx_clkdm_wakeup(struct clockdomain *clkdm)
32{
33 am33xx_cm_clkdm_force_wakeup(clkdm->cm_inst, clkdm->clkdm_offs);
34 return 0;
35}
36
37static void am33xx_clkdm_allow_idle(struct clockdomain *clkdm)
38{
39 am33xx_cm_clkdm_enable_hwsup(clkdm->cm_inst, clkdm->clkdm_offs);
40}
41
42static void am33xx_clkdm_deny_idle(struct clockdomain *clkdm)
43{
44 am33xx_cm_clkdm_disable_hwsup(clkdm->cm_inst, clkdm->clkdm_offs);
45}
46
47static int am33xx_clkdm_clk_enable(struct clockdomain *clkdm)
48{
49 if (clkdm->flags & CLKDM_CAN_FORCE_WAKEUP)
50 return am33xx_clkdm_wakeup(clkdm);
51
52 return 0;
53}
54
55static int am33xx_clkdm_clk_disable(struct clockdomain *clkdm)
56{
57 bool hwsup = false;
58
59 hwsup = am33xx_cm_is_clkdm_in_hwsup(clkdm->cm_inst, clkdm->clkdm_offs);
60
61 if (!hwsup && (clkdm->flags & CLKDM_CAN_FORCE_SLEEP))
62 am33xx_clkdm_sleep(clkdm);
63
64 return 0;
65}
66
67struct clkdm_ops am33xx_clkdm_operations = {
68 .clkdm_sleep = am33xx_clkdm_sleep,
69 .clkdm_wakeup = am33xx_clkdm_wakeup,
70 .clkdm_allow_idle = am33xx_clkdm_allow_idle,
71 .clkdm_deny_idle = am33xx_clkdm_deny_idle,
72 .clkdm_clk_enable = am33xx_clkdm_clk_enable,
73 .clkdm_clk_disable = am33xx_clkdm_clk_disable,
74};
diff --git a/arch/arm/mach-omap2/clockdomain44xx.c b/arch/arm/mach-omap2/clockdomain44xx.c
deleted file mode 100644
index 6fc6155625bc..000000000000
--- a/arch/arm/mach-omap2/clockdomain44xx.c
+++ /dev/null
@@ -1,151 +0,0 @@
1/*
2 * OMAP4 clockdomain control
3 *
4 * Copyright (C) 2008-2010 Texas Instruments, Inc.
5 * Copyright (C) 2008-2010 Nokia Corporation
6 *
7 * Derived from mach-omap2/clockdomain.c written by Paul Walmsley
8 * Rajendra Nayak <rnayak@ti.com>
9 *
10 * This program is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU General Public License version 2 as
12 * published by the Free Software Foundation.
13 */
14
15#include <linux/kernel.h>
16#include "clockdomain.h"
17#include "cminst44xx.h"
18#include "cm44xx.h"
19
20static int omap4_clkdm_add_wkup_sleep_dep(struct clockdomain *clkdm1,
21 struct clockdomain *clkdm2)
22{
23 omap4_cminst_set_inst_reg_bits((1 << clkdm2->dep_bit),
24 clkdm1->prcm_partition,
25 clkdm1->cm_inst, clkdm1->clkdm_offs +
26 OMAP4_CM_STATICDEP);
27 return 0;
28}
29
30static int omap4_clkdm_del_wkup_sleep_dep(struct clockdomain *clkdm1,
31 struct clockdomain *clkdm2)
32{
33 omap4_cminst_clear_inst_reg_bits((1 << clkdm2->dep_bit),
34 clkdm1->prcm_partition,
35 clkdm1->cm_inst, clkdm1->clkdm_offs +
36 OMAP4_CM_STATICDEP);
37 return 0;
38}
39
40static int omap4_clkdm_read_wkup_sleep_dep(struct clockdomain *clkdm1,
41 struct clockdomain *clkdm2)
42{
43 return omap4_cminst_read_inst_reg_bits(clkdm1->prcm_partition,
44 clkdm1->cm_inst, clkdm1->clkdm_offs +
45 OMAP4_CM_STATICDEP,
46 (1 << clkdm2->dep_bit));
47}
48
49static int omap4_clkdm_clear_all_wkup_sleep_deps(struct clockdomain *clkdm)
50{
51 struct clkdm_dep *cd;
52 u32 mask = 0;
53
54 if (!clkdm->prcm_partition)
55 return 0;
56
57 for (cd = clkdm->wkdep_srcs; cd && cd->clkdm_name; cd++) {
58 if (!cd->clkdm)
59 continue; /* only happens if data is erroneous */
60
61 mask |= 1 << cd->clkdm->dep_bit;
62 atomic_set(&cd->wkdep_usecount, 0);
63 }
64
65 omap4_cminst_clear_inst_reg_bits(mask, clkdm->prcm_partition,
66 clkdm->cm_inst, clkdm->clkdm_offs +
67 OMAP4_CM_STATICDEP);
68 return 0;
69}
70
71static int omap4_clkdm_sleep(struct clockdomain *clkdm)
72{
73 omap4_cminst_clkdm_enable_hwsup(clkdm->prcm_partition,
74 clkdm->cm_inst, clkdm->clkdm_offs);
75 return 0;
76}
77
78static int omap4_clkdm_wakeup(struct clockdomain *clkdm)
79{
80 omap4_cminst_clkdm_force_wakeup(clkdm->prcm_partition,
81 clkdm->cm_inst, clkdm->clkdm_offs);
82 return 0;
83}
84
85static void omap4_clkdm_allow_idle(struct clockdomain *clkdm)
86{
87 omap4_cminst_clkdm_enable_hwsup(clkdm->prcm_partition,
88 clkdm->cm_inst, clkdm->clkdm_offs);
89}
90
91static void omap4_clkdm_deny_idle(struct clockdomain *clkdm)
92{
93 if (clkdm->flags & CLKDM_CAN_FORCE_WAKEUP)
94 omap4_clkdm_wakeup(clkdm);
95 else
96 omap4_cminst_clkdm_disable_hwsup(clkdm->prcm_partition,
97 clkdm->cm_inst,
98 clkdm->clkdm_offs);
99}
100
101static int omap4_clkdm_clk_enable(struct clockdomain *clkdm)
102{
103 if (clkdm->flags & CLKDM_CAN_FORCE_WAKEUP)
104 return omap4_clkdm_wakeup(clkdm);
105
106 return 0;
107}
108
109static int omap4_clkdm_clk_disable(struct clockdomain *clkdm)
110{
111 bool hwsup = false;
112
113 if (!clkdm->prcm_partition)
114 return 0;
115
116 /*
117 * The CLKDM_MISSING_IDLE_REPORTING flag documentation has
118 * more details on the unpleasant problem this is working
119 * around
120 */
121 if (clkdm->flags & CLKDM_MISSING_IDLE_REPORTING &&
122 !(clkdm->flags & CLKDM_CAN_FORCE_SLEEP)) {
123 omap4_clkdm_allow_idle(clkdm);
124 return 0;
125 }
126
127 hwsup = omap4_cminst_is_clkdm_in_hwsup(clkdm->prcm_partition,
128 clkdm->cm_inst, clkdm->clkdm_offs);
129
130 if (!hwsup && (clkdm->flags & CLKDM_CAN_FORCE_SLEEP))
131 omap4_clkdm_sleep(clkdm);
132
133 return 0;
134}
135
136struct clkdm_ops omap4_clkdm_operations = {
137 .clkdm_add_wkdep = omap4_clkdm_add_wkup_sleep_dep,
138 .clkdm_del_wkdep = omap4_clkdm_del_wkup_sleep_dep,
139 .clkdm_read_wkdep = omap4_clkdm_read_wkup_sleep_dep,
140 .clkdm_clear_all_wkdeps = omap4_clkdm_clear_all_wkup_sleep_deps,
141 .clkdm_add_sleepdep = omap4_clkdm_add_wkup_sleep_dep,
142 .clkdm_del_sleepdep = omap4_clkdm_del_wkup_sleep_dep,
143 .clkdm_read_sleepdep = omap4_clkdm_read_wkup_sleep_dep,
144 .clkdm_clear_all_sleepdeps = omap4_clkdm_clear_all_wkup_sleep_deps,
145 .clkdm_sleep = omap4_clkdm_sleep,
146 .clkdm_wakeup = omap4_clkdm_wakeup,
147 .clkdm_allow_idle = omap4_clkdm_allow_idle,
148 .clkdm_deny_idle = omap4_clkdm_deny_idle,
149 .clkdm_clk_enable = omap4_clkdm_clk_enable,
150 .clkdm_clk_disable = omap4_clkdm_clk_disable,
151};
diff --git a/arch/arm/mach-omap2/cm2xxx.c b/arch/arm/mach-omap2/cm2xxx.c
index 051349370711..64165013daf9 100644
--- a/arch/arm/mach-omap2/cm2xxx.c
+++ b/arch/arm/mach-omap2/cm2xxx.c
@@ -2,8 +2,9 @@
2 * OMAP2xxx CM module functions 2 * OMAP2xxx CM module functions
3 * 3 *
4 * Copyright (C) 2009 Nokia Corporation 4 * Copyright (C) 2009 Nokia Corporation
5 * Copyright (C) 2012 Texas Instruments, Inc. 5 * Copyright (C) 2008-2010, 2012 Texas Instruments, Inc.
6 * Paul Walmsley 6 * Paul Walmsley
7 * Rajendra Nayak <rnayak@ti.com>
7 * 8 *
8 * This program is free software; you can redistribute it and/or modify 9 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License version 2 as 10 * it under the terms of the GNU General Public License version 2 as
@@ -20,9 +21,11 @@
20#include "soc.h" 21#include "soc.h"
21#include "iomap.h" 22#include "iomap.h"
22#include "common.h" 23#include "common.h"
24#include "prm2xxx.h"
23#include "cm.h" 25#include "cm.h"
24#include "cm2xxx.h" 26#include "cm2xxx.h"
25#include "cm-regbits-24xx.h" 27#include "cm-regbits-24xx.h"
28#include "clockdomain.h"
26 29
27/* CM_AUTOIDLE_PLL.AUTO_* bit values for DPLLs */ 30/* CM_AUTOIDLE_PLL.AUTO_* bit values for DPLLs */
28#define DPLL_AUTOIDLE_DISABLE 0x0 31#define DPLL_AUTOIDLE_DISABLE 0x0
@@ -166,3 +169,87 @@ int omap2xxx_cm_wait_module_ready(s16 prcm_mod, u8 idlest_id, u8 idlest_shift)
166 169
167 return (i < MAX_MODULE_READY_TIME) ? 0 : -EBUSY; 170 return (i < MAX_MODULE_READY_TIME) ? 0 : -EBUSY;
168} 171}
172
173/* Clockdomain low-level functions */
174
175static void omap2xxx_clkdm_allow_idle(struct clockdomain *clkdm)
176{
177 if (atomic_read(&clkdm->usecount) > 0)
178 _clkdm_add_autodeps(clkdm);
179
180 omap2xxx_cm_clkdm_enable_hwsup(clkdm->pwrdm.ptr->prcm_offs,
181 clkdm->clktrctrl_mask);
182}
183
184static void omap2xxx_clkdm_deny_idle(struct clockdomain *clkdm)
185{
186 omap2xxx_cm_clkdm_disable_hwsup(clkdm->pwrdm.ptr->prcm_offs,
187 clkdm->clktrctrl_mask);
188
189 if (atomic_read(&clkdm->usecount) > 0)
190 _clkdm_del_autodeps(clkdm);
191}
192
193static int omap2xxx_clkdm_clk_enable(struct clockdomain *clkdm)
194{
195 bool hwsup = false;
196
197 if (!clkdm->clktrctrl_mask)
198 return 0;
199
200 hwsup = omap2xxx_cm_is_clkdm_in_hwsup(clkdm->pwrdm.ptr->prcm_offs,
201 clkdm->clktrctrl_mask);
202
203 if (hwsup) {
204 /* Disable HW transitions when we are changing deps */
205 omap2xxx_cm_clkdm_disable_hwsup(clkdm->pwrdm.ptr->prcm_offs,
206 clkdm->clktrctrl_mask);
207 _clkdm_add_autodeps(clkdm);
208 omap2xxx_cm_clkdm_enable_hwsup(clkdm->pwrdm.ptr->prcm_offs,
209 clkdm->clktrctrl_mask);
210 } else {
211 if (clkdm->flags & CLKDM_CAN_FORCE_WAKEUP)
212 omap2xxx_clkdm_wakeup(clkdm);
213 }
214
215 return 0;
216}
217
218static int omap2xxx_clkdm_clk_disable(struct clockdomain *clkdm)
219{
220 bool hwsup = false;
221
222 if (!clkdm->clktrctrl_mask)
223 return 0;
224
225 hwsup = omap2xxx_cm_is_clkdm_in_hwsup(clkdm->pwrdm.ptr->prcm_offs,
226 clkdm->clktrctrl_mask);
227
228 if (hwsup) {
229 /* Disable HW transitions when we are changing deps */
230 omap2xxx_cm_clkdm_disable_hwsup(clkdm->pwrdm.ptr->prcm_offs,
231 clkdm->clktrctrl_mask);
232 _clkdm_del_autodeps(clkdm);
233 omap2xxx_cm_clkdm_enable_hwsup(clkdm->pwrdm.ptr->prcm_offs,
234 clkdm->clktrctrl_mask);
235 } else {
236 if (clkdm->flags & CLKDM_CAN_FORCE_SLEEP)
237 omap2xxx_clkdm_sleep(clkdm);
238 }
239
240 return 0;
241}
242
243struct clkdm_ops omap2_clkdm_operations = {
244 .clkdm_add_wkdep = omap2_clkdm_add_wkdep,
245 .clkdm_del_wkdep = omap2_clkdm_del_wkdep,
246 .clkdm_read_wkdep = omap2_clkdm_read_wkdep,
247 .clkdm_clear_all_wkdeps = omap2_clkdm_clear_all_wkdeps,
248 .clkdm_sleep = omap2xxx_clkdm_sleep,
249 .clkdm_wakeup = omap2xxx_clkdm_wakeup,
250 .clkdm_allow_idle = omap2xxx_clkdm_allow_idle,
251 .clkdm_deny_idle = omap2xxx_clkdm_deny_idle,
252 .clkdm_clk_enable = omap2xxx_clkdm_clk_enable,
253 .clkdm_clk_disable = omap2xxx_clkdm_clk_disable,
254};
255
diff --git a/arch/arm/mach-omap2/cm2xxx_3xxx.h b/arch/arm/mach-omap2/cm2xxx_3xxx.h
index 865d332f6fb1..0e26bb1bf7e2 100644
--- a/arch/arm/mach-omap2/cm2xxx_3xxx.h
+++ b/arch/arm/mach-omap2/cm2xxx_3xxx.h
@@ -74,6 +74,18 @@ static inline u32 omap2_cm_rmw_mod_reg_bits(u32 mask, u32 bits, s16 module,
74 return v; 74 return v;
75} 75}
76 76
77/* Read a CM register, AND it, and shift the result down to bit 0 */
78static inline u32 omap2_cm_read_mod_bits_shift(s16 domain, s16 idx, u32 mask)
79{
80 u32 v;
81
82 v = omap2_cm_read_mod_reg(domain, idx);
83 v &= mask;
84 v >>= __ffs(mask);
85
86 return v;
87}
88
77static inline u32 omap2_cm_set_mod_reg_bits(u32 bits, s16 module, s16 idx) 89static inline u32 omap2_cm_set_mod_reg_bits(u32 bits, s16 module, s16 idx)
78{ 90{
79 return omap2_cm_rmw_mod_reg_bits(bits, bits, module, idx); 91 return omap2_cm_rmw_mod_reg_bits(bits, bits, module, idx);
diff --git a/arch/arm/mach-omap2/cm33xx.c b/arch/arm/mach-omap2/cm33xx.c
index 13f56eafef03..9b3bcff127ff 100644
--- a/arch/arm/mach-omap2/cm33xx.c
+++ b/arch/arm/mach-omap2/cm33xx.c
@@ -24,6 +24,7 @@
24 24
25#include <plat/common.h> 25#include <plat/common.h>
26 26
27#include "clockdomain.h"
27#include "cm.h" 28#include "cm.h"
28#include "cm33xx.h" 29#include "cm33xx.h"
29#include "cm-regbits-34xx.h" 30#include "cm-regbits-34xx.h"
@@ -311,3 +312,58 @@ void am33xx_cm_module_disable(u16 inst, s16 cdoffs, u16 clkctrl_offs)
311 v &= ~AM33XX_MODULEMODE_MASK; 312 v &= ~AM33XX_MODULEMODE_MASK;
312 am33xx_cm_write_reg(v, inst, clkctrl_offs); 313 am33xx_cm_write_reg(v, inst, clkctrl_offs);
313} 314}
315
316/*
317 * Clockdomain low-level functions
318 */
319
320static int am33xx_clkdm_sleep(struct clockdomain *clkdm)
321{
322 am33xx_cm_clkdm_force_sleep(clkdm->cm_inst, clkdm->clkdm_offs);
323 return 0;
324}
325
326static int am33xx_clkdm_wakeup(struct clockdomain *clkdm)
327{
328 am33xx_cm_clkdm_force_wakeup(clkdm->cm_inst, clkdm->clkdm_offs);
329 return 0;
330}
331
332static void am33xx_clkdm_allow_idle(struct clockdomain *clkdm)
333{
334 am33xx_cm_clkdm_enable_hwsup(clkdm->cm_inst, clkdm->clkdm_offs);
335}
336
337static void am33xx_clkdm_deny_idle(struct clockdomain *clkdm)
338{
339 am33xx_cm_clkdm_disable_hwsup(clkdm->cm_inst, clkdm->clkdm_offs);
340}
341
342static int am33xx_clkdm_clk_enable(struct clockdomain *clkdm)
343{
344 if (clkdm->flags & CLKDM_CAN_FORCE_WAKEUP)
345 return am33xx_clkdm_wakeup(clkdm);
346
347 return 0;
348}
349
350static int am33xx_clkdm_clk_disable(struct clockdomain *clkdm)
351{
352 bool hwsup = false;
353
354 hwsup = am33xx_cm_is_clkdm_in_hwsup(clkdm->cm_inst, clkdm->clkdm_offs);
355
356 if (!hwsup && (clkdm->flags & CLKDM_CAN_FORCE_SLEEP))
357 am33xx_clkdm_sleep(clkdm);
358
359 return 0;
360}
361
362struct clkdm_ops am33xx_clkdm_operations = {
363 .clkdm_sleep = am33xx_clkdm_sleep,
364 .clkdm_wakeup = am33xx_clkdm_wakeup,
365 .clkdm_allow_idle = am33xx_clkdm_allow_idle,
366 .clkdm_deny_idle = am33xx_clkdm_deny_idle,
367 .clkdm_clk_enable = am33xx_clkdm_clk_enable,
368 .clkdm_clk_disable = am33xx_clkdm_clk_disable,
369};
diff --git a/arch/arm/mach-omap2/cm3xxx.c b/arch/arm/mach-omap2/cm3xxx.c
index 8f92c56e2254..8b03ec2f4394 100644
--- a/arch/arm/mach-omap2/cm3xxx.c
+++ b/arch/arm/mach-omap2/cm3xxx.c
@@ -1,9 +1,10 @@
1/* 1/*
2 * OMAP2/3 CM module functions 2 * OMAP3xxx CM module functions
3 * 3 *
4 * Copyright (C) 2009 Nokia Corporation 4 * Copyright (C) 2009 Nokia Corporation
5 * Copyright (C) 2012 Texas Instruments, Inc. 5 * Copyright (C) 2008-2010, 2012 Texas Instruments, Inc.
6 * Paul Walmsley 6 * Paul Walmsley
7 * Rajendra Nayak <rnayak@ti.com>
7 * 8 *
8 * This program is free software; you can redistribute it and/or modify 9 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License version 2 as 10 * it under the terms of the GNU General Public License version 2 as
@@ -20,9 +21,11 @@
20#include "soc.h" 21#include "soc.h"
21#include "iomap.h" 22#include "iomap.h"
22#include "common.h" 23#include "common.h"
24#include "prm2xxx_3xxx.h"
23#include "cm.h" 25#include "cm.h"
24#include "cm3xxx.h" 26#include "cm3xxx.h"
25#include "cm-regbits-34xx.h" 27#include "cm-regbits-34xx.h"
28#include "clockdomain.h"
26 29
27static const u8 omap3xxx_cm_idlest_offs[] = { 30static const u8 omap3xxx_cm_idlest_offs[] = {
28 CM_IDLEST1, CM_IDLEST2, OMAP2430_CM_IDLEST3 31 CM_IDLEST1, CM_IDLEST2, OMAP2430_CM_IDLEST3
@@ -107,6 +110,173 @@ int omap3xxx_cm_wait_module_ready(s16 prcm_mod, u8 idlest_id, u8 idlest_shift)
107 return (i < MAX_MODULE_READY_TIME) ? 0 : -EBUSY; 110 return (i < MAX_MODULE_READY_TIME) ? 0 : -EBUSY;
108} 111}
109 112
113/* Clockdomain low-level operations */
114
115static int omap3xxx_clkdm_add_sleepdep(struct clockdomain *clkdm1,
116 struct clockdomain *clkdm2)
117{
118 omap2_cm_set_mod_reg_bits((1 << clkdm2->dep_bit),
119 clkdm1->pwrdm.ptr->prcm_offs,
120 OMAP3430_CM_SLEEPDEP);
121 return 0;
122}
123
124static int omap3xxx_clkdm_del_sleepdep(struct clockdomain *clkdm1,
125 struct clockdomain *clkdm2)
126{
127 omap2_cm_clear_mod_reg_bits((1 << clkdm2->dep_bit),
128 clkdm1->pwrdm.ptr->prcm_offs,
129 OMAP3430_CM_SLEEPDEP);
130 return 0;
131}
132
133static int omap3xxx_clkdm_read_sleepdep(struct clockdomain *clkdm1,
134 struct clockdomain *clkdm2)
135{
136 return omap2_cm_read_mod_bits_shift(clkdm1->pwrdm.ptr->prcm_offs,
137 OMAP3430_CM_SLEEPDEP,
138 (1 << clkdm2->dep_bit));
139}
140
141static int omap3xxx_clkdm_clear_all_sleepdeps(struct clockdomain *clkdm)
142{
143 struct clkdm_dep *cd;
144 u32 mask = 0;
145
146 for (cd = clkdm->sleepdep_srcs; cd && cd->clkdm_name; cd++) {
147 if (!cd->clkdm)
148 continue; /* only happens if data is erroneous */
149
150 mask |= 1 << cd->clkdm->dep_bit;
151 atomic_set(&cd->sleepdep_usecount, 0);
152 }
153 omap2_cm_clear_mod_reg_bits(mask, clkdm->pwrdm.ptr->prcm_offs,
154 OMAP3430_CM_SLEEPDEP);
155 return 0;
156}
157
158static int omap3xxx_clkdm_sleep(struct clockdomain *clkdm)
159{
160 omap3xxx_cm_clkdm_force_sleep(clkdm->pwrdm.ptr->prcm_offs,
161 clkdm->clktrctrl_mask);
162 return 0;
163}
164
165static int omap3xxx_clkdm_wakeup(struct clockdomain *clkdm)
166{
167 omap3xxx_cm_clkdm_force_wakeup(clkdm->pwrdm.ptr->prcm_offs,
168 clkdm->clktrctrl_mask);
169 return 0;
170}
171
172static void omap3xxx_clkdm_allow_idle(struct clockdomain *clkdm)
173{
174 if (atomic_read(&clkdm->usecount) > 0)
175 _clkdm_add_autodeps(clkdm);
176
177 omap3xxx_cm_clkdm_enable_hwsup(clkdm->pwrdm.ptr->prcm_offs,
178 clkdm->clktrctrl_mask);
179}
180
181static void omap3xxx_clkdm_deny_idle(struct clockdomain *clkdm)
182{
183 omap3xxx_cm_clkdm_disable_hwsup(clkdm->pwrdm.ptr->prcm_offs,
184 clkdm->clktrctrl_mask);
185
186 if (atomic_read(&clkdm->usecount) > 0)
187 _clkdm_del_autodeps(clkdm);
188}
189
190static int omap3xxx_clkdm_clk_enable(struct clockdomain *clkdm)
191{
192 bool hwsup = false;
193
194 if (!clkdm->clktrctrl_mask)
195 return 0;
196
197 /*
198 * The CLKDM_MISSING_IDLE_REPORTING flag documentation has
199 * more details on the unpleasant problem this is working
200 * around
201 */
202 if ((clkdm->flags & CLKDM_MISSING_IDLE_REPORTING) &&
203 (clkdm->flags & CLKDM_CAN_FORCE_WAKEUP)) {
204 omap3xxx_clkdm_wakeup(clkdm);
205 return 0;
206 }
207
208 hwsup = omap3xxx_cm_is_clkdm_in_hwsup(clkdm->pwrdm.ptr->prcm_offs,
209 clkdm->clktrctrl_mask);
210
211 if (hwsup) {
212 /* Disable HW transitions when we are changing deps */
213 omap3xxx_cm_clkdm_disable_hwsup(clkdm->pwrdm.ptr->prcm_offs,
214 clkdm->clktrctrl_mask);
215 _clkdm_add_autodeps(clkdm);
216 omap3xxx_cm_clkdm_enable_hwsup(clkdm->pwrdm.ptr->prcm_offs,
217 clkdm->clktrctrl_mask);
218 } else {
219 if (clkdm->flags & CLKDM_CAN_FORCE_WAKEUP)
220 omap3xxx_clkdm_wakeup(clkdm);
221 }
222
223 return 0;
224}
225
226static int omap3xxx_clkdm_clk_disable(struct clockdomain *clkdm)
227{
228 bool hwsup = false;
229
230 if (!clkdm->clktrctrl_mask)
231 return 0;
232
233 /*
234 * The CLKDM_MISSING_IDLE_REPORTING flag documentation has
235 * more details on the unpleasant problem this is working
236 * around
237 */
238 if (clkdm->flags & CLKDM_MISSING_IDLE_REPORTING &&
239 !(clkdm->flags & CLKDM_CAN_FORCE_SLEEP)) {
240 omap3xxx_cm_clkdm_enable_hwsup(clkdm->pwrdm.ptr->prcm_offs,
241 clkdm->clktrctrl_mask);
242 return 0;
243 }
244
245 hwsup = omap3xxx_cm_is_clkdm_in_hwsup(clkdm->pwrdm.ptr->prcm_offs,
246 clkdm->clktrctrl_mask);
247
248 if (hwsup) {
249 /* Disable HW transitions when we are changing deps */
250 omap3xxx_cm_clkdm_disable_hwsup(clkdm->pwrdm.ptr->prcm_offs,
251 clkdm->clktrctrl_mask);
252 _clkdm_del_autodeps(clkdm);
253 omap3xxx_cm_clkdm_enable_hwsup(clkdm->pwrdm.ptr->prcm_offs,
254 clkdm->clktrctrl_mask);
255 } else {
256 if (clkdm->flags & CLKDM_CAN_FORCE_SLEEP)
257 omap3xxx_clkdm_sleep(clkdm);
258 }
259
260 return 0;
261}
262
263struct clkdm_ops omap3_clkdm_operations = {
264 .clkdm_add_wkdep = omap2_clkdm_add_wkdep,
265 .clkdm_del_wkdep = omap2_clkdm_del_wkdep,
266 .clkdm_read_wkdep = omap2_clkdm_read_wkdep,
267 .clkdm_clear_all_wkdeps = omap2_clkdm_clear_all_wkdeps,
268 .clkdm_add_sleepdep = omap3xxx_clkdm_add_sleepdep,
269 .clkdm_del_sleepdep = omap3xxx_clkdm_del_sleepdep,
270 .clkdm_read_sleepdep = omap3xxx_clkdm_read_sleepdep,
271 .clkdm_clear_all_sleepdeps = omap3xxx_clkdm_clear_all_sleepdeps,
272 .clkdm_sleep = omap3xxx_clkdm_sleep,
273 .clkdm_wakeup = omap3xxx_clkdm_wakeup,
274 .clkdm_allow_idle = omap3xxx_clkdm_allow_idle,
275 .clkdm_deny_idle = omap3xxx_clkdm_deny_idle,
276 .clkdm_clk_enable = omap3xxx_clkdm_clk_enable,
277 .clkdm_clk_disable = omap3xxx_clkdm_clk_disable,
278};
279
110/* 280/*
111 * Context save/restore code - OMAP3 only 281 * Context save/restore code - OMAP3 only
112 */ 282 */
diff --git a/arch/arm/mach-omap2/cminst44xx.c b/arch/arm/mach-omap2/cminst44xx.c
index 1894015ff04b..7f9a464f01e9 100644
--- a/arch/arm/mach-omap2/cminst44xx.c
+++ b/arch/arm/mach-omap2/cminst44xx.c
@@ -2,8 +2,9 @@
2 * OMAP4 CM instance functions 2 * OMAP4 CM instance functions
3 * 3 *
4 * Copyright (C) 2009 Nokia Corporation 4 * Copyright (C) 2009 Nokia Corporation
5 * Copyright (C) 2011 Texas Instruments, Inc. 5 * Copyright (C) 2008-2011 Texas Instruments, Inc.
6 * Paul Walmsley 6 * Paul Walmsley
7 * Rajendra Nayak <rnayak@ti.com>
7 * 8 *
8 * This program is free software; you can redistribute it and/or modify 9 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License version 2 as 10 * it under the terms of the GNU General Public License version 2 as
@@ -22,6 +23,7 @@
22 23
23#include "iomap.h" 24#include "iomap.h"
24#include "common.h" 25#include "common.h"
26#include "clockdomain.h"
25#include "cm.h" 27#include "cm.h"
26#include "cm1_44xx.h" 28#include "cm1_44xx.h"
27#include "cm2_44xx.h" 29#include "cm2_44xx.h"
@@ -343,3 +345,141 @@ void omap4_cminst_module_disable(u8 part, u16 inst, s16 cdoffs,
343 v &= ~OMAP4430_MODULEMODE_MASK; 345 v &= ~OMAP4430_MODULEMODE_MASK;
344 omap4_cminst_write_inst_reg(v, part, inst, clkctrl_offs); 346 omap4_cminst_write_inst_reg(v, part, inst, clkctrl_offs);
345} 347}
348
349/*
350 * Clockdomain low-level functions
351 */
352
353static int omap4_clkdm_add_wkup_sleep_dep(struct clockdomain *clkdm1,
354 struct clockdomain *clkdm2)
355{
356 omap4_cminst_set_inst_reg_bits((1 << clkdm2->dep_bit),
357 clkdm1->prcm_partition,
358 clkdm1->cm_inst, clkdm1->clkdm_offs +
359 OMAP4_CM_STATICDEP);
360 return 0;
361}
362
363static int omap4_clkdm_del_wkup_sleep_dep(struct clockdomain *clkdm1,
364 struct clockdomain *clkdm2)
365{
366 omap4_cminst_clear_inst_reg_bits((1 << clkdm2->dep_bit),
367 clkdm1->prcm_partition,
368 clkdm1->cm_inst, clkdm1->clkdm_offs +
369 OMAP4_CM_STATICDEP);
370 return 0;
371}
372
373static int omap4_clkdm_read_wkup_sleep_dep(struct clockdomain *clkdm1,
374 struct clockdomain *clkdm2)
375{
376 return omap4_cminst_read_inst_reg_bits(clkdm1->prcm_partition,
377 clkdm1->cm_inst,
378 clkdm1->clkdm_offs +
379 OMAP4_CM_STATICDEP,
380 (1 << clkdm2->dep_bit));
381}
382
383static int omap4_clkdm_clear_all_wkup_sleep_deps(struct clockdomain *clkdm)
384{
385 struct clkdm_dep *cd;
386 u32 mask = 0;
387
388 if (!clkdm->prcm_partition)
389 return 0;
390
391 for (cd = clkdm->wkdep_srcs; cd && cd->clkdm_name; cd++) {
392 if (!cd->clkdm)
393 continue; /* only happens if data is erroneous */
394
395 mask |= 1 << cd->clkdm->dep_bit;
396 atomic_set(&cd->wkdep_usecount, 0);
397 }
398
399 omap4_cminst_clear_inst_reg_bits(mask, clkdm->prcm_partition,
400 clkdm->cm_inst, clkdm->clkdm_offs +
401 OMAP4_CM_STATICDEP);
402 return 0;
403}
404
405static int omap4_clkdm_sleep(struct clockdomain *clkdm)
406{
407 omap4_cminst_clkdm_enable_hwsup(clkdm->prcm_partition,
408 clkdm->cm_inst, clkdm->clkdm_offs);
409 return 0;
410}
411
412static int omap4_clkdm_wakeup(struct clockdomain *clkdm)
413{
414 omap4_cminst_clkdm_force_wakeup(clkdm->prcm_partition,
415 clkdm->cm_inst, clkdm->clkdm_offs);
416 return 0;
417}
418
419static void omap4_clkdm_allow_idle(struct clockdomain *clkdm)
420{
421 omap4_cminst_clkdm_enable_hwsup(clkdm->prcm_partition,
422 clkdm->cm_inst, clkdm->clkdm_offs);
423}
424
425static void omap4_clkdm_deny_idle(struct clockdomain *clkdm)
426{
427 if (clkdm->flags & CLKDM_CAN_FORCE_WAKEUP)
428 omap4_clkdm_wakeup(clkdm);
429 else
430 omap4_cminst_clkdm_disable_hwsup(clkdm->prcm_partition,
431 clkdm->cm_inst,
432 clkdm->clkdm_offs);
433}
434
435static int omap4_clkdm_clk_enable(struct clockdomain *clkdm)
436{
437 if (clkdm->flags & CLKDM_CAN_FORCE_WAKEUP)
438 return omap4_clkdm_wakeup(clkdm);
439
440 return 0;
441}
442
443static int omap4_clkdm_clk_disable(struct clockdomain *clkdm)
444{
445 bool hwsup = false;
446
447 if (!clkdm->prcm_partition)
448 return 0;
449
450 /*
451 * The CLKDM_MISSING_IDLE_REPORTING flag documentation has
452 * more details on the unpleasant problem this is working
453 * around
454 */
455 if (clkdm->flags & CLKDM_MISSING_IDLE_REPORTING &&
456 !(clkdm->flags & CLKDM_CAN_FORCE_SLEEP)) {
457 omap4_clkdm_allow_idle(clkdm);
458 return 0;
459 }
460
461 hwsup = omap4_cminst_is_clkdm_in_hwsup(clkdm->prcm_partition,
462 clkdm->cm_inst, clkdm->clkdm_offs);
463
464 if (!hwsup && (clkdm->flags & CLKDM_CAN_FORCE_SLEEP))
465 omap4_clkdm_sleep(clkdm);
466
467 return 0;
468}
469
470struct clkdm_ops omap4_clkdm_operations = {
471 .clkdm_add_wkdep = omap4_clkdm_add_wkup_sleep_dep,
472 .clkdm_del_wkdep = omap4_clkdm_del_wkup_sleep_dep,
473 .clkdm_read_wkdep = omap4_clkdm_read_wkup_sleep_dep,
474 .clkdm_clear_all_wkdeps = omap4_clkdm_clear_all_wkup_sleep_deps,
475 .clkdm_add_sleepdep = omap4_clkdm_add_wkup_sleep_dep,
476 .clkdm_del_sleepdep = omap4_clkdm_del_wkup_sleep_dep,
477 .clkdm_read_sleepdep = omap4_clkdm_read_wkup_sleep_dep,
478 .clkdm_clear_all_sleepdeps = omap4_clkdm_clear_all_wkup_sleep_deps,
479 .clkdm_sleep = omap4_clkdm_sleep,
480 .clkdm_wakeup = omap4_clkdm_wakeup,
481 .clkdm_allow_idle = omap4_clkdm_allow_idle,
482 .clkdm_deny_idle = omap4_clkdm_deny_idle,
483 .clkdm_clk_enable = omap4_clkdm_clk_enable,
484 .clkdm_clk_disable = omap4_clkdm_clk_disable,
485};
diff --git a/arch/arm/mach-omap2/prm2xxx.c b/arch/arm/mach-omap2/prm2xxx.c
index 218ef6a1f11e..9cdb4e5e3d80 100644
--- a/arch/arm/mach-omap2/prm2xxx.c
+++ b/arch/arm/mach-omap2/prm2xxx.c
@@ -24,10 +24,27 @@
24 24
25#include "vp.h" 25#include "vp.h"
26#include "powerdomain.h" 26#include "powerdomain.h"
27#include "clockdomain.h"
27#include "prm2xxx.h" 28#include "prm2xxx.h"
28#include "cm2xxx_3xxx.h" 29#include "cm2xxx_3xxx.h"
29#include "prm-regbits-24xx.h" 30#include "prm-regbits-24xx.h"
30 31
32int omap2xxx_clkdm_sleep(struct clockdomain *clkdm)
33{
34 omap2_prm_set_mod_reg_bits(OMAP24XX_FORCESTATE_MASK,
35 clkdm->pwrdm.ptr->prcm_offs,
36 OMAP2_PM_PWSTCTRL);
37 return 0;
38}
39
40int omap2xxx_clkdm_wakeup(struct clockdomain *clkdm)
41{
42 omap2_prm_clear_mod_reg_bits(OMAP24XX_FORCESTATE_MASK,
43 clkdm->pwrdm.ptr->prcm_offs,
44 OMAP2_PM_PWSTCTRL);
45 return 0;
46}
47
31struct pwrdm_ops omap2_pwrdm_operations = { 48struct pwrdm_ops omap2_pwrdm_operations = {
32 .pwrdm_set_next_pwrst = omap2_pwrdm_set_next_pwrst, 49 .pwrdm_set_next_pwrst = omap2_pwrdm_set_next_pwrst,
33 .pwrdm_read_next_pwrst = omap2_pwrdm_read_next_pwrst, 50 .pwrdm_read_next_pwrst = omap2_pwrdm_read_next_pwrst,
diff --git a/arch/arm/mach-omap2/prm2xxx.h b/arch/arm/mach-omap2/prm2xxx.h
index 6490e1a580e8..6d76716a1ea5 100644
--- a/arch/arm/mach-omap2/prm2xxx.h
+++ b/arch/arm/mach-omap2/prm2xxx.h
@@ -119,4 +119,10 @@
119#define OMAP24XX_PRCM_IRQSTATUS_IVA 0x00f8 119#define OMAP24XX_PRCM_IRQSTATUS_IVA 0x00f8
120#define OMAP24XX_PRCM_IRQENABLE_IVA 0x00fc 120#define OMAP24XX_PRCM_IRQENABLE_IVA 0x00fc
121 121
122#ifndef __ASSEMBLER__
123/* Function prototypes */
124extern int omap2xxx_clkdm_sleep(struct clockdomain *clkdm);
125extern int omap2xxx_clkdm_wakeup(struct clockdomain *clkdm);
126#endif
127
122#endif 128#endif
diff --git a/arch/arm/mach-omap2/prm2xxx_3xxx.c b/arch/arm/mach-omap2/prm2xxx_3xxx.c
index bdddf5ca67c4..30517f5af707 100644
--- a/arch/arm/mach-omap2/prm2xxx_3xxx.c
+++ b/arch/arm/mach-omap2/prm2xxx_3xxx.c
@@ -20,6 +20,7 @@
20#include "powerdomain.h" 20#include "powerdomain.h"
21#include "prm2xxx_3xxx.h" 21#include "prm2xxx_3xxx.h"
22#include "prm-regbits-24xx.h" 22#include "prm-regbits-24xx.h"
23#include "clockdomain.h"
23 24
24/** 25/**
25 * omap2_prm_is_hardreset_asserted - read the HW reset line state of 26 * omap2_prm_is_hardreset_asserted - read the HW reset line state of
@@ -208,3 +209,45 @@ int omap2_pwrdm_wait_transition(struct powerdomain *pwrdm)
208 return 0; 209 return 0;
209} 210}
210 211
212int omap2_clkdm_add_wkdep(struct clockdomain *clkdm1,
213 struct clockdomain *clkdm2)
214{
215 omap2_prm_set_mod_reg_bits((1 << clkdm2->dep_bit),
216 clkdm1->pwrdm.ptr->prcm_offs, PM_WKDEP);
217 return 0;
218}
219
220int omap2_clkdm_del_wkdep(struct clockdomain *clkdm1,
221 struct clockdomain *clkdm2)
222{
223 omap2_prm_clear_mod_reg_bits((1 << clkdm2->dep_bit),
224 clkdm1->pwrdm.ptr->prcm_offs, PM_WKDEP);
225 return 0;
226}
227
228int omap2_clkdm_read_wkdep(struct clockdomain *clkdm1,
229 struct clockdomain *clkdm2)
230{
231 return omap2_prm_read_mod_bits_shift(clkdm1->pwrdm.ptr->prcm_offs,
232 PM_WKDEP, (1 << clkdm2->dep_bit));
233}
234
235int omap2_clkdm_clear_all_wkdeps(struct clockdomain *clkdm)
236{
237 struct clkdm_dep *cd;
238 u32 mask = 0;
239
240 for (cd = clkdm->wkdep_srcs; cd && cd->clkdm_name; cd++) {
241 if (!cd->clkdm)
242 continue; /* only happens if data is erroneous */
243
244 /* PRM accesses are slow, so minimize them */
245 mask |= 1 << cd->clkdm->dep_bit;
246 atomic_set(&cd->wkdep_usecount, 0);
247 }
248
249 omap2_prm_clear_mod_reg_bits(mask, clkdm->pwrdm.ptr->prcm_offs,
250 PM_WKDEP);
251 return 0;
252}
253
diff --git a/arch/arm/mach-omap2/prm2xxx_3xxx.h b/arch/arm/mach-omap2/prm2xxx_3xxx.h
index 706b0262f3f0..22a405a1543b 100644
--- a/arch/arm/mach-omap2/prm2xxx_3xxx.h
+++ b/arch/arm/mach-omap2/prm2xxx_3xxx.h
@@ -116,6 +116,14 @@ extern int omap2_pwrdm_read_mem_retst(struct powerdomain *pwrdm, u8 bank);
116extern int omap2_pwrdm_set_logic_retst(struct powerdomain *pwrdm, u8 pwrst); 116extern int omap2_pwrdm_set_logic_retst(struct powerdomain *pwrdm, u8 pwrst);
117extern int omap2_pwrdm_wait_transition(struct powerdomain *pwrdm); 117extern int omap2_pwrdm_wait_transition(struct powerdomain *pwrdm);
118 118
119extern int omap2_clkdm_add_wkdep(struct clockdomain *clkdm1,
120 struct clockdomain *clkdm2);
121extern int omap2_clkdm_del_wkdep(struct clockdomain *clkdm1,
122 struct clockdomain *clkdm2);
123extern int omap2_clkdm_read_wkdep(struct clockdomain *clkdm1,
124 struct clockdomain *clkdm2);
125extern int omap2_clkdm_clear_all_wkdeps(struct clockdomain *clkdm);
126
119#endif /* __ASSEMBLER */ 127#endif /* __ASSEMBLER */
120 128
121/* 129/*