aboutsummaryrefslogtreecommitdiffstats
path: root/arch/arm/mach-omap2/cm3xxx.c
diff options
context:
space:
mode:
Diffstat (limited to 'arch/arm/mach-omap2/cm3xxx.c')
-rw-r--r--arch/arm/mach-omap2/cm3xxx.c174
1 files changed, 172 insertions, 2 deletions
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 */