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