ARM: OMAP: Split plat/cpu.h into local soc.h for mach-omap1 and mach-omap2
[deliverable/linux.git] / arch / arm / mach-omap2 / clockdomain2xxx_3xxx.c
CommitLineData
4aef7a2a
RN
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>
e4c060db
TL
17
18#include "soc.h"
4aef7a2a
RN
19#include "prm.h"
20#include "prm2xxx_3xxx.h"
21#include "cm.h"
22#include "cm2xxx_3xxx.h"
23#include "cm-regbits-24xx.h"
24#include "cm-regbits-34xx.h"
68b921ad 25#include "prm-regbits-24xx.h"
4aef7a2a
RN
26#include "clockdomain.h"
27
28static int omap2_clkdm_add_wkdep(struct clockdomain *clkdm1,
29 struct clockdomain *clkdm2)
30{
31 omap2_prm_set_mod_reg_bits((1 << clkdm2->dep_bit),
32 clkdm1->pwrdm.ptr->prcm_offs, PM_WKDEP);
33 return 0;
34}
35
36static int omap2_clkdm_del_wkdep(struct clockdomain *clkdm1,
37 struct clockdomain *clkdm2)
38{
39 omap2_prm_clear_mod_reg_bits((1 << clkdm2->dep_bit),
40 clkdm1->pwrdm.ptr->prcm_offs, PM_WKDEP);
41 return 0;
42}
43
44static int omap2_clkdm_read_wkdep(struct clockdomain *clkdm1,
45 struct clockdomain *clkdm2)
46{
47 return omap2_prm_read_mod_bits_shift(clkdm1->pwrdm.ptr->prcm_offs,
48 PM_WKDEP, (1 << clkdm2->dep_bit));
49}
50
51static int omap2_clkdm_clear_all_wkdeps(struct clockdomain *clkdm)
52{
53 struct clkdm_dep *cd;
54 u32 mask = 0;
55
56 for (cd = clkdm->wkdep_srcs; cd && cd->clkdm_name; cd++) {
4aef7a2a
RN
57 if (!cd->clkdm)
58 continue; /* only happens if data is erroneous */
59
60 /* PRM accesses are slow, so minimize them */
61 mask |= 1 << cd->clkdm->dep_bit;
62 atomic_set(&cd->wkdep_usecount, 0);
63 }
64
65 omap2_prm_clear_mod_reg_bits(mask, clkdm->pwrdm.ptr->prcm_offs,
66 PM_WKDEP);
67 return 0;
68}
69
70static int omap3_clkdm_add_sleepdep(struct clockdomain *clkdm1,
71 struct clockdomain *clkdm2)
72{
73 omap2_cm_set_mod_reg_bits((1 << clkdm2->dep_bit),
74 clkdm1->pwrdm.ptr->prcm_offs,
75 OMAP3430_CM_SLEEPDEP);
76 return 0;
77}
78
79static int omap3_clkdm_del_sleepdep(struct clockdomain *clkdm1,
80 struct clockdomain *clkdm2)
81{
82 omap2_cm_clear_mod_reg_bits((1 << clkdm2->dep_bit),
83 clkdm1->pwrdm.ptr->prcm_offs,
84 OMAP3430_CM_SLEEPDEP);
85 return 0;
86}
87
88static int omap3_clkdm_read_sleepdep(struct clockdomain *clkdm1,
89 struct clockdomain *clkdm2)
90{
91 return omap2_prm_read_mod_bits_shift(clkdm1->pwrdm.ptr->prcm_offs,
92 OMAP3430_CM_SLEEPDEP, (1 << clkdm2->dep_bit));
93}
94
95static int omap3_clkdm_clear_all_sleepdeps(struct clockdomain *clkdm)
96{
97 struct clkdm_dep *cd;
98 u32 mask = 0;
99
100 for (cd = clkdm->sleepdep_srcs; cd && cd->clkdm_name; cd++) {
4aef7a2a
RN
101 if (!cd->clkdm)
102 continue; /* only happens if data is erroneous */
103
104 /* PRM accesses are slow, so minimize them */
105 mask |= 1 << cd->clkdm->dep_bit;
106 atomic_set(&cd->sleepdep_usecount, 0);
107 }
108 omap2_prm_clear_mod_reg_bits(mask, clkdm->pwrdm.ptr->prcm_offs,
109 OMAP3430_CM_SLEEPDEP);
110 return 0;
111}
112
68b921ad
RN
113static int omap2_clkdm_sleep(struct clockdomain *clkdm)
114{
115 omap2_cm_set_mod_reg_bits(OMAP24XX_FORCESTATE_MASK,
116 clkdm->pwrdm.ptr->prcm_offs,
117 OMAP2_PM_PWSTCTRL);
118 return 0;
119}
120
121static int omap2_clkdm_wakeup(struct clockdomain *clkdm)
122{
123 omap2_cm_clear_mod_reg_bits(OMAP24XX_FORCESTATE_MASK,
124 clkdm->pwrdm.ptr->prcm_offs,
125 OMAP2_PM_PWSTCTRL);
126 return 0;
127}
128
5cd1937b
RN
129static void omap2_clkdm_allow_idle(struct clockdomain *clkdm)
130{
131 if (atomic_read(&clkdm->usecount) > 0)
132 _clkdm_add_autodeps(clkdm);
133
134 omap2xxx_cm_clkdm_enable_hwsup(clkdm->pwrdm.ptr->prcm_offs,
135 clkdm->clktrctrl_mask);
136}
137
138static void omap2_clkdm_deny_idle(struct clockdomain *clkdm)
139{
140 omap2xxx_cm_clkdm_disable_hwsup(clkdm->pwrdm.ptr->prcm_offs,
141 clkdm->clktrctrl_mask);
142
143 if (atomic_read(&clkdm->usecount) > 0)
144 _clkdm_del_autodeps(clkdm);
145}
146
4da71ae6
RN
147static void _enable_hwsup(struct clockdomain *clkdm)
148{
149 if (cpu_is_omap24xx())
150 omap2xxx_cm_clkdm_enable_hwsup(clkdm->pwrdm.ptr->prcm_offs,
151 clkdm->clktrctrl_mask);
152 else if (cpu_is_omap34xx())
153 omap3xxx_cm_clkdm_enable_hwsup(clkdm->pwrdm.ptr->prcm_offs,
154 clkdm->clktrctrl_mask);
155}
156
157static void _disable_hwsup(struct clockdomain *clkdm)
158{
159 if (cpu_is_omap24xx())
160 omap2xxx_cm_clkdm_disable_hwsup(clkdm->pwrdm.ptr->prcm_offs,
161 clkdm->clktrctrl_mask);
162 else if (cpu_is_omap34xx())
163 omap3xxx_cm_clkdm_disable_hwsup(clkdm->pwrdm.ptr->prcm_offs,
164 clkdm->clktrctrl_mask);
165}
166
b71c7217
PW
167static int omap3_clkdm_sleep(struct clockdomain *clkdm)
168{
169 omap3xxx_cm_clkdm_force_sleep(clkdm->pwrdm.ptr->prcm_offs,
170 clkdm->clktrctrl_mask);
171 return 0;
172}
173
174static int omap3_clkdm_wakeup(struct clockdomain *clkdm)
175{
176 omap3xxx_cm_clkdm_force_wakeup(clkdm->pwrdm.ptr->prcm_offs,
177 clkdm->clktrctrl_mask);
178 return 0;
179}
4da71ae6
RN
180
181static int omap2_clkdm_clk_enable(struct clockdomain *clkdm)
182{
183 bool hwsup = false;
184
185 if (!clkdm->clktrctrl_mask)
186 return 0;
187
188 hwsup = omap2_cm_is_clkdm_in_hwsup(clkdm->pwrdm.ptr->prcm_offs,
189 clkdm->clktrctrl_mask);
190
191 if (hwsup) {
192 /* Disable HW transitions when we are changing deps */
193 _disable_hwsup(clkdm);
194 _clkdm_add_autodeps(clkdm);
195 _enable_hwsup(clkdm);
196 } else {
555e74ea
RN
197 if (clkdm->flags & CLKDM_CAN_FORCE_WAKEUP)
198 omap2_clkdm_wakeup(clkdm);
4da71ae6
RN
199 }
200
201 return 0;
202}
203
204static int omap2_clkdm_clk_disable(struct clockdomain *clkdm)
205{
206 bool hwsup = false;
207
208 if (!clkdm->clktrctrl_mask)
209 return 0;
210
211 hwsup = omap2_cm_is_clkdm_in_hwsup(clkdm->pwrdm.ptr->prcm_offs,
212 clkdm->clktrctrl_mask);
213
214 if (hwsup) {
215 /* Disable HW transitions when we are changing deps */
216 _disable_hwsup(clkdm);
217 _clkdm_del_autodeps(clkdm);
218 _enable_hwsup(clkdm);
219 } else {
555e74ea
RN
220 if (clkdm->flags & CLKDM_CAN_FORCE_SLEEP)
221 omap2_clkdm_sleep(clkdm);
4da71ae6
RN
222 }
223
224 return 0;
225}
226
5cd1937b
RN
227static void omap3_clkdm_allow_idle(struct clockdomain *clkdm)
228{
229 if (atomic_read(&clkdm->usecount) > 0)
230 _clkdm_add_autodeps(clkdm);
231
232 omap3xxx_cm_clkdm_enable_hwsup(clkdm->pwrdm.ptr->prcm_offs,
233 clkdm->clktrctrl_mask);
234}
235
236static void omap3_clkdm_deny_idle(struct clockdomain *clkdm)
237{
238 omap3xxx_cm_clkdm_disable_hwsup(clkdm->pwrdm.ptr->prcm_offs,
239 clkdm->clktrctrl_mask);
240
241 if (atomic_read(&clkdm->usecount) > 0)
242 _clkdm_del_autodeps(clkdm);
243}
244
bfb7dd25
PW
245static int omap3xxx_clkdm_clk_enable(struct clockdomain *clkdm)
246{
247 bool hwsup = false;
248
249 if (!clkdm->clktrctrl_mask)
250 return 0;
251
cf956d9f
JH
252 /*
253 * The CLKDM_MISSING_IDLE_REPORTING flag documentation has
254 * more details on the unpleasant problem this is working
255 * around
256 */
257 if ((clkdm->flags & CLKDM_MISSING_IDLE_REPORTING) &&
258 (clkdm->flags & CLKDM_CAN_FORCE_WAKEUP)) {
259 omap3_clkdm_wakeup(clkdm);
260 return 0;
261 }
262
bfb7dd25
PW
263 hwsup = omap2_cm_is_clkdm_in_hwsup(clkdm->pwrdm.ptr->prcm_offs,
264 clkdm->clktrctrl_mask);
265
266 if (hwsup) {
267 /* Disable HW transitions when we are changing deps */
268 _disable_hwsup(clkdm);
269 _clkdm_add_autodeps(clkdm);
270 _enable_hwsup(clkdm);
271 } else {
272 if (clkdm->flags & CLKDM_CAN_FORCE_WAKEUP)
273 omap3_clkdm_wakeup(clkdm);
274 }
275
276 return 0;
277}
278
279static int omap3xxx_clkdm_clk_disable(struct clockdomain *clkdm)
280{
281 bool hwsup = false;
282
283 if (!clkdm->clktrctrl_mask)
284 return 0;
285
cf956d9f
JH
286 /*
287 * The CLKDM_MISSING_IDLE_REPORTING flag documentation has
288 * more details on the unpleasant problem this is working
289 * around
290 */
291 if (clkdm->flags & CLKDM_MISSING_IDLE_REPORTING &&
292 !(clkdm->flags & CLKDM_CAN_FORCE_SLEEP)) {
293 _enable_hwsup(clkdm);
294 return 0;
295 }
296
bfb7dd25
PW
297 hwsup = omap2_cm_is_clkdm_in_hwsup(clkdm->pwrdm.ptr->prcm_offs,
298 clkdm->clktrctrl_mask);
299
300 if (hwsup) {
301 /* Disable HW transitions when we are changing deps */
302 _disable_hwsup(clkdm);
303 _clkdm_del_autodeps(clkdm);
304 _enable_hwsup(clkdm);
305 } else {
306 if (clkdm->flags & CLKDM_CAN_FORCE_SLEEP)
307 omap3_clkdm_sleep(clkdm);
308 }
309
310 return 0;
311}
312
4aef7a2a
RN
313struct clkdm_ops omap2_clkdm_operations = {
314 .clkdm_add_wkdep = omap2_clkdm_add_wkdep,
315 .clkdm_del_wkdep = omap2_clkdm_del_wkdep,
316 .clkdm_read_wkdep = omap2_clkdm_read_wkdep,
317 .clkdm_clear_all_wkdeps = omap2_clkdm_clear_all_wkdeps,
68b921ad
RN
318 .clkdm_sleep = omap2_clkdm_sleep,
319 .clkdm_wakeup = omap2_clkdm_wakeup,
5cd1937b
RN
320 .clkdm_allow_idle = omap2_clkdm_allow_idle,
321 .clkdm_deny_idle = omap2_clkdm_deny_idle,
4da71ae6
RN
322 .clkdm_clk_enable = omap2_clkdm_clk_enable,
323 .clkdm_clk_disable = omap2_clkdm_clk_disable,
4aef7a2a
RN
324};
325
326struct clkdm_ops omap3_clkdm_operations = {
327 .clkdm_add_wkdep = omap2_clkdm_add_wkdep,
328 .clkdm_del_wkdep = omap2_clkdm_del_wkdep,
329 .clkdm_read_wkdep = omap2_clkdm_read_wkdep,
330 .clkdm_clear_all_wkdeps = omap2_clkdm_clear_all_wkdeps,
331 .clkdm_add_sleepdep = omap3_clkdm_add_sleepdep,
332 .clkdm_del_sleepdep = omap3_clkdm_del_sleepdep,
333 .clkdm_read_sleepdep = omap3_clkdm_read_sleepdep,
334 .clkdm_clear_all_sleepdeps = omap3_clkdm_clear_all_sleepdeps,
68b921ad
RN
335 .clkdm_sleep = omap3_clkdm_sleep,
336 .clkdm_wakeup = omap3_clkdm_wakeup,
5cd1937b
RN
337 .clkdm_allow_idle = omap3_clkdm_allow_idle,
338 .clkdm_deny_idle = omap3_clkdm_deny_idle,
bfb7dd25
PW
339 .clkdm_clk_enable = omap3xxx_clkdm_clk_enable,
340 .clkdm_clk_disable = omap3xxx_clkdm_clk_disable,
4aef7a2a 341};
This page took 0.114993 seconds and 5 git commands to generate.