1*4882a593Smuzhiyun /*
2*4882a593Smuzhiyun * AM33XX CM functions
3*4882a593Smuzhiyun *
4*4882a593Smuzhiyun * Copyright (C) 2011-2012 Texas Instruments Incorporated - https://www.ti.com/
5*4882a593Smuzhiyun * Vaibhav Hiremath <hvaibhav@ti.com>
6*4882a593Smuzhiyun *
7*4882a593Smuzhiyun * Reference taken from from OMAP4 cminst44xx.c
8*4882a593Smuzhiyun *
9*4882a593Smuzhiyun * This program is free software; you can redistribute it and/or
10*4882a593Smuzhiyun * modify it under the terms of the GNU General Public License as
11*4882a593Smuzhiyun * published by the Free Software Foundation version 2.
12*4882a593Smuzhiyun *
13*4882a593Smuzhiyun * This program is distributed "as is" WITHOUT ANY WARRANTY of any
14*4882a593Smuzhiyun * kind, whether express or implied; without even the implied warranty
15*4882a593Smuzhiyun * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16*4882a593Smuzhiyun * GNU General Public License for more details.
17*4882a593Smuzhiyun */
18*4882a593Smuzhiyun
19*4882a593Smuzhiyun #include <linux/kernel.h>
20*4882a593Smuzhiyun #include <linux/types.h>
21*4882a593Smuzhiyun #include <linux/errno.h>
22*4882a593Smuzhiyun #include <linux/err.h>
23*4882a593Smuzhiyun #include <linux/io.h>
24*4882a593Smuzhiyun
25*4882a593Smuzhiyun #include "clockdomain.h"
26*4882a593Smuzhiyun #include "cm.h"
27*4882a593Smuzhiyun #include "cm33xx.h"
28*4882a593Smuzhiyun #include "cm-regbits-34xx.h"
29*4882a593Smuzhiyun #include "cm-regbits-33xx.h"
30*4882a593Smuzhiyun #include "prm33xx.h"
31*4882a593Smuzhiyun
32*4882a593Smuzhiyun /*
33*4882a593Smuzhiyun * CLKCTRL_IDLEST_*: possible values for the CM_*_CLKCTRL.IDLEST bitfield:
34*4882a593Smuzhiyun *
35*4882a593Smuzhiyun * 0x0 func: Module is fully functional, including OCP
36*4882a593Smuzhiyun * 0x1 trans: Module is performing transition: wakeup, or sleep, or sleep
37*4882a593Smuzhiyun * abortion
38*4882a593Smuzhiyun * 0x2 idle: Module is in Idle mode (only OCP part). It is functional if
39*4882a593Smuzhiyun * using separate functional clock
40*4882a593Smuzhiyun * 0x3 disabled: Module is disabled and cannot be accessed
41*4882a593Smuzhiyun *
42*4882a593Smuzhiyun */
43*4882a593Smuzhiyun #define CLKCTRL_IDLEST_FUNCTIONAL 0x0
44*4882a593Smuzhiyun #define CLKCTRL_IDLEST_INTRANSITION 0x1
45*4882a593Smuzhiyun #define CLKCTRL_IDLEST_INTERFACE_IDLE 0x2
46*4882a593Smuzhiyun #define CLKCTRL_IDLEST_DISABLED 0x3
47*4882a593Smuzhiyun
48*4882a593Smuzhiyun /* Private functions */
49*4882a593Smuzhiyun
50*4882a593Smuzhiyun /* Read a register in a CM instance */
am33xx_cm_read_reg(u16 inst,u16 idx)51*4882a593Smuzhiyun static inline u32 am33xx_cm_read_reg(u16 inst, u16 idx)
52*4882a593Smuzhiyun {
53*4882a593Smuzhiyun return readl_relaxed(cm_base.va + inst + idx);
54*4882a593Smuzhiyun }
55*4882a593Smuzhiyun
56*4882a593Smuzhiyun /* Write into a register in a CM */
am33xx_cm_write_reg(u32 val,u16 inst,u16 idx)57*4882a593Smuzhiyun static inline void am33xx_cm_write_reg(u32 val, u16 inst, u16 idx)
58*4882a593Smuzhiyun {
59*4882a593Smuzhiyun writel_relaxed(val, cm_base.va + inst + idx);
60*4882a593Smuzhiyun }
61*4882a593Smuzhiyun
62*4882a593Smuzhiyun /* Read-modify-write a register in CM */
am33xx_cm_rmw_reg_bits(u32 mask,u32 bits,s16 inst,s16 idx)63*4882a593Smuzhiyun static inline u32 am33xx_cm_rmw_reg_bits(u32 mask, u32 bits, s16 inst, s16 idx)
64*4882a593Smuzhiyun {
65*4882a593Smuzhiyun u32 v;
66*4882a593Smuzhiyun
67*4882a593Smuzhiyun v = am33xx_cm_read_reg(inst, idx);
68*4882a593Smuzhiyun v &= ~mask;
69*4882a593Smuzhiyun v |= bits;
70*4882a593Smuzhiyun am33xx_cm_write_reg(v, inst, idx);
71*4882a593Smuzhiyun
72*4882a593Smuzhiyun return v;
73*4882a593Smuzhiyun }
74*4882a593Smuzhiyun
am33xx_cm_read_reg_bits(u16 inst,s16 idx,u32 mask)75*4882a593Smuzhiyun static inline u32 am33xx_cm_read_reg_bits(u16 inst, s16 idx, u32 mask)
76*4882a593Smuzhiyun {
77*4882a593Smuzhiyun u32 v;
78*4882a593Smuzhiyun
79*4882a593Smuzhiyun v = am33xx_cm_read_reg(inst, idx);
80*4882a593Smuzhiyun v &= mask;
81*4882a593Smuzhiyun v >>= __ffs(mask);
82*4882a593Smuzhiyun
83*4882a593Smuzhiyun return v;
84*4882a593Smuzhiyun }
85*4882a593Smuzhiyun
86*4882a593Smuzhiyun /**
87*4882a593Smuzhiyun * _clkctrl_idlest - read a CM_*_CLKCTRL register; mask & shift IDLEST bitfield
88*4882a593Smuzhiyun * @inst: CM instance register offset (*_INST macro)
89*4882a593Smuzhiyun * @clkctrl_offs: Module clock control register offset (*_CLKCTRL macro)
90*4882a593Smuzhiyun *
91*4882a593Smuzhiyun * Return the IDLEST bitfield of a CM_*_CLKCTRL register, shifted down to
92*4882a593Smuzhiyun * bit 0.
93*4882a593Smuzhiyun */
_clkctrl_idlest(u16 inst,u16 clkctrl_offs)94*4882a593Smuzhiyun static u32 _clkctrl_idlest(u16 inst, u16 clkctrl_offs)
95*4882a593Smuzhiyun {
96*4882a593Smuzhiyun u32 v = am33xx_cm_read_reg(inst, clkctrl_offs);
97*4882a593Smuzhiyun v &= AM33XX_IDLEST_MASK;
98*4882a593Smuzhiyun v >>= AM33XX_IDLEST_SHIFT;
99*4882a593Smuzhiyun return v;
100*4882a593Smuzhiyun }
101*4882a593Smuzhiyun
102*4882a593Smuzhiyun /**
103*4882a593Smuzhiyun * _is_module_ready - can module registers be accessed without causing an abort?
104*4882a593Smuzhiyun * @inst: CM instance register offset (*_INST macro)
105*4882a593Smuzhiyun * @clkctrl_offs: Module clock control register offset (*_CLKCTRL macro)
106*4882a593Smuzhiyun *
107*4882a593Smuzhiyun * Returns true if the module's CM_*_CLKCTRL.IDLEST bitfield is either
108*4882a593Smuzhiyun * *FUNCTIONAL or *INTERFACE_IDLE; false otherwise.
109*4882a593Smuzhiyun */
_is_module_ready(u16 inst,u16 clkctrl_offs)110*4882a593Smuzhiyun static bool _is_module_ready(u16 inst, u16 clkctrl_offs)
111*4882a593Smuzhiyun {
112*4882a593Smuzhiyun u32 v;
113*4882a593Smuzhiyun
114*4882a593Smuzhiyun v = _clkctrl_idlest(inst, clkctrl_offs);
115*4882a593Smuzhiyun
116*4882a593Smuzhiyun return (v == CLKCTRL_IDLEST_FUNCTIONAL ||
117*4882a593Smuzhiyun v == CLKCTRL_IDLEST_INTERFACE_IDLE) ? true : false;
118*4882a593Smuzhiyun }
119*4882a593Smuzhiyun
120*4882a593Smuzhiyun /**
121*4882a593Smuzhiyun * _clktrctrl_write - write @c to a CM_CLKSTCTRL.CLKTRCTRL register bitfield
122*4882a593Smuzhiyun * @c: CLKTRCTRL register bitfield (LSB = bit 0, i.e., unshifted)
123*4882a593Smuzhiyun * @inst: CM instance register offset (*_INST macro)
124*4882a593Smuzhiyun * @cdoffs: Clockdomain register offset (*_CDOFFS macro)
125*4882a593Smuzhiyun *
126*4882a593Smuzhiyun * @c must be the unshifted value for CLKTRCTRL - i.e., this function
127*4882a593Smuzhiyun * will handle the shift itself.
128*4882a593Smuzhiyun */
_clktrctrl_write(u8 c,u16 inst,u16 cdoffs)129*4882a593Smuzhiyun static void _clktrctrl_write(u8 c, u16 inst, u16 cdoffs)
130*4882a593Smuzhiyun {
131*4882a593Smuzhiyun u32 v;
132*4882a593Smuzhiyun
133*4882a593Smuzhiyun v = am33xx_cm_read_reg(inst, cdoffs);
134*4882a593Smuzhiyun v &= ~AM33XX_CLKTRCTRL_MASK;
135*4882a593Smuzhiyun v |= c << AM33XX_CLKTRCTRL_SHIFT;
136*4882a593Smuzhiyun am33xx_cm_write_reg(v, inst, cdoffs);
137*4882a593Smuzhiyun }
138*4882a593Smuzhiyun
139*4882a593Smuzhiyun /* Public functions */
140*4882a593Smuzhiyun
141*4882a593Smuzhiyun /**
142*4882a593Smuzhiyun * am33xx_cm_is_clkdm_in_hwsup - is a clockdomain in hwsup idle mode?
143*4882a593Smuzhiyun * @inst: CM instance register offset (*_INST macro)
144*4882a593Smuzhiyun * @cdoffs: Clockdomain register offset (*_CDOFFS macro)
145*4882a593Smuzhiyun *
146*4882a593Smuzhiyun * Returns true if the clockdomain referred to by (@inst, @cdoffs)
147*4882a593Smuzhiyun * is in hardware-supervised idle mode, or 0 otherwise.
148*4882a593Smuzhiyun */
am33xx_cm_is_clkdm_in_hwsup(u16 inst,u16 cdoffs)149*4882a593Smuzhiyun static bool am33xx_cm_is_clkdm_in_hwsup(u16 inst, u16 cdoffs)
150*4882a593Smuzhiyun {
151*4882a593Smuzhiyun u32 v;
152*4882a593Smuzhiyun
153*4882a593Smuzhiyun v = am33xx_cm_read_reg(inst, cdoffs);
154*4882a593Smuzhiyun v &= AM33XX_CLKTRCTRL_MASK;
155*4882a593Smuzhiyun v >>= AM33XX_CLKTRCTRL_SHIFT;
156*4882a593Smuzhiyun
157*4882a593Smuzhiyun return (v == OMAP34XX_CLKSTCTRL_ENABLE_AUTO) ? true : false;
158*4882a593Smuzhiyun }
159*4882a593Smuzhiyun
160*4882a593Smuzhiyun /**
161*4882a593Smuzhiyun * am33xx_cm_clkdm_enable_hwsup - put a clockdomain in hwsup-idle mode
162*4882a593Smuzhiyun * @inst: CM instance register offset (*_INST macro)
163*4882a593Smuzhiyun * @cdoffs: Clockdomain register offset (*_CDOFFS macro)
164*4882a593Smuzhiyun *
165*4882a593Smuzhiyun * Put a clockdomain referred to by (@inst, @cdoffs) into
166*4882a593Smuzhiyun * hardware-supervised idle mode. No return value.
167*4882a593Smuzhiyun */
am33xx_cm_clkdm_enable_hwsup(u16 inst,u16 cdoffs)168*4882a593Smuzhiyun static void am33xx_cm_clkdm_enable_hwsup(u16 inst, u16 cdoffs)
169*4882a593Smuzhiyun {
170*4882a593Smuzhiyun _clktrctrl_write(OMAP34XX_CLKSTCTRL_ENABLE_AUTO, inst, cdoffs);
171*4882a593Smuzhiyun }
172*4882a593Smuzhiyun
173*4882a593Smuzhiyun /**
174*4882a593Smuzhiyun * am33xx_cm_clkdm_disable_hwsup - put a clockdomain in swsup-idle mode
175*4882a593Smuzhiyun * @inst: CM instance register offset (*_INST macro)
176*4882a593Smuzhiyun * @cdoffs: Clockdomain register offset (*_CDOFFS macro)
177*4882a593Smuzhiyun *
178*4882a593Smuzhiyun * Put a clockdomain referred to by (@inst, @cdoffs) into
179*4882a593Smuzhiyun * software-supervised idle mode, i.e., controlled manually by the
180*4882a593Smuzhiyun * Linux OMAP clockdomain code. No return value.
181*4882a593Smuzhiyun */
am33xx_cm_clkdm_disable_hwsup(u16 inst,u16 cdoffs)182*4882a593Smuzhiyun static void am33xx_cm_clkdm_disable_hwsup(u16 inst, u16 cdoffs)
183*4882a593Smuzhiyun {
184*4882a593Smuzhiyun _clktrctrl_write(OMAP34XX_CLKSTCTRL_DISABLE_AUTO, inst, cdoffs);
185*4882a593Smuzhiyun }
186*4882a593Smuzhiyun
187*4882a593Smuzhiyun /**
188*4882a593Smuzhiyun * am33xx_cm_clkdm_force_sleep - try to put a clockdomain into idle
189*4882a593Smuzhiyun * @inst: CM instance register offset (*_INST macro)
190*4882a593Smuzhiyun * @cdoffs: Clockdomain register offset (*_CDOFFS macro)
191*4882a593Smuzhiyun *
192*4882a593Smuzhiyun * Put a clockdomain referred to by (@inst, @cdoffs) into idle
193*4882a593Smuzhiyun * No return value.
194*4882a593Smuzhiyun */
am33xx_cm_clkdm_force_sleep(u16 inst,u16 cdoffs)195*4882a593Smuzhiyun static void am33xx_cm_clkdm_force_sleep(u16 inst, u16 cdoffs)
196*4882a593Smuzhiyun {
197*4882a593Smuzhiyun _clktrctrl_write(OMAP34XX_CLKSTCTRL_FORCE_SLEEP, inst, cdoffs);
198*4882a593Smuzhiyun }
199*4882a593Smuzhiyun
200*4882a593Smuzhiyun /**
201*4882a593Smuzhiyun * am33xx_cm_clkdm_force_wakeup - try to take a clockdomain out of idle
202*4882a593Smuzhiyun * @inst: CM instance register offset (*_INST macro)
203*4882a593Smuzhiyun * @cdoffs: Clockdomain register offset (*_CDOFFS macro)
204*4882a593Smuzhiyun *
205*4882a593Smuzhiyun * Take a clockdomain referred to by (@inst, @cdoffs) out of idle,
206*4882a593Smuzhiyun * waking it up. No return value.
207*4882a593Smuzhiyun */
am33xx_cm_clkdm_force_wakeup(u16 inst,u16 cdoffs)208*4882a593Smuzhiyun static void am33xx_cm_clkdm_force_wakeup(u16 inst, u16 cdoffs)
209*4882a593Smuzhiyun {
210*4882a593Smuzhiyun _clktrctrl_write(OMAP34XX_CLKSTCTRL_FORCE_WAKEUP, inst, cdoffs);
211*4882a593Smuzhiyun }
212*4882a593Smuzhiyun
213*4882a593Smuzhiyun /*
214*4882a593Smuzhiyun *
215*4882a593Smuzhiyun */
216*4882a593Smuzhiyun
217*4882a593Smuzhiyun /**
218*4882a593Smuzhiyun * am33xx_cm_wait_module_ready - wait for a module to be in 'func' state
219*4882a593Smuzhiyun * @part: PRCM partition, ignored for AM33xx
220*4882a593Smuzhiyun * @inst: CM instance register offset (*_INST macro)
221*4882a593Smuzhiyun * @clkctrl_offs: Module clock control register offset (*_CLKCTRL macro)
222*4882a593Smuzhiyun * @bit_shift: bit shift for the register, ignored for AM33xx
223*4882a593Smuzhiyun *
224*4882a593Smuzhiyun * Wait for the module IDLEST to be functional. If the idle state is in any
225*4882a593Smuzhiyun * the non functional state (trans, idle or disabled), module and thus the
226*4882a593Smuzhiyun * sysconfig cannot be accessed and will probably lead to an "imprecise
227*4882a593Smuzhiyun * external abort"
228*4882a593Smuzhiyun */
am33xx_cm_wait_module_ready(u8 part,s16 inst,u16 clkctrl_offs,u8 bit_shift)229*4882a593Smuzhiyun static int am33xx_cm_wait_module_ready(u8 part, s16 inst, u16 clkctrl_offs,
230*4882a593Smuzhiyun u8 bit_shift)
231*4882a593Smuzhiyun {
232*4882a593Smuzhiyun int i = 0;
233*4882a593Smuzhiyun
234*4882a593Smuzhiyun omap_test_timeout(_is_module_ready(inst, clkctrl_offs),
235*4882a593Smuzhiyun MAX_MODULE_READY_TIME, i);
236*4882a593Smuzhiyun
237*4882a593Smuzhiyun return (i < MAX_MODULE_READY_TIME) ? 0 : -EBUSY;
238*4882a593Smuzhiyun }
239*4882a593Smuzhiyun
240*4882a593Smuzhiyun /**
241*4882a593Smuzhiyun * am33xx_cm_wait_module_idle - wait for a module to be in 'disabled'
242*4882a593Smuzhiyun * state
243*4882a593Smuzhiyun * @part: CM partition, ignored for AM33xx
244*4882a593Smuzhiyun * @inst: CM instance register offset (*_INST macro)
245*4882a593Smuzhiyun * @clkctrl_offs: Module clock control register offset (*_CLKCTRL macro)
246*4882a593Smuzhiyun * @bit_shift: bit shift for the register, ignored for AM33xx
247*4882a593Smuzhiyun *
248*4882a593Smuzhiyun * Wait for the module IDLEST to be disabled. Some PRCM transition,
249*4882a593Smuzhiyun * like reset assertion or parent clock de-activation must wait the
250*4882a593Smuzhiyun * module to be fully disabled.
251*4882a593Smuzhiyun */
am33xx_cm_wait_module_idle(u8 part,s16 inst,u16 clkctrl_offs,u8 bit_shift)252*4882a593Smuzhiyun static int am33xx_cm_wait_module_idle(u8 part, s16 inst, u16 clkctrl_offs,
253*4882a593Smuzhiyun u8 bit_shift)
254*4882a593Smuzhiyun {
255*4882a593Smuzhiyun int i = 0;
256*4882a593Smuzhiyun
257*4882a593Smuzhiyun omap_test_timeout((_clkctrl_idlest(inst, clkctrl_offs) ==
258*4882a593Smuzhiyun CLKCTRL_IDLEST_DISABLED),
259*4882a593Smuzhiyun MAX_MODULE_READY_TIME, i);
260*4882a593Smuzhiyun
261*4882a593Smuzhiyun return (i < MAX_MODULE_READY_TIME) ? 0 : -EBUSY;
262*4882a593Smuzhiyun }
263*4882a593Smuzhiyun
264*4882a593Smuzhiyun /**
265*4882a593Smuzhiyun * am33xx_cm_module_enable - Enable the modulemode inside CLKCTRL
266*4882a593Smuzhiyun * @mode: Module mode (SW or HW)
267*4882a593Smuzhiyun * @part: CM partition, ignored for AM33xx
268*4882a593Smuzhiyun * @inst: CM instance register offset (*_INST macro)
269*4882a593Smuzhiyun * @clkctrl_offs: Module clock control register offset (*_CLKCTRL macro)
270*4882a593Smuzhiyun *
271*4882a593Smuzhiyun * No return value.
272*4882a593Smuzhiyun */
am33xx_cm_module_enable(u8 mode,u8 part,u16 inst,u16 clkctrl_offs)273*4882a593Smuzhiyun static void am33xx_cm_module_enable(u8 mode, u8 part, u16 inst,
274*4882a593Smuzhiyun u16 clkctrl_offs)
275*4882a593Smuzhiyun {
276*4882a593Smuzhiyun u32 v;
277*4882a593Smuzhiyun
278*4882a593Smuzhiyun v = am33xx_cm_read_reg(inst, clkctrl_offs);
279*4882a593Smuzhiyun v &= ~AM33XX_MODULEMODE_MASK;
280*4882a593Smuzhiyun v |= mode << AM33XX_MODULEMODE_SHIFT;
281*4882a593Smuzhiyun am33xx_cm_write_reg(v, inst, clkctrl_offs);
282*4882a593Smuzhiyun }
283*4882a593Smuzhiyun
284*4882a593Smuzhiyun /**
285*4882a593Smuzhiyun * am33xx_cm_module_disable - Disable the module inside CLKCTRL
286*4882a593Smuzhiyun * @part: CM partition, ignored for AM33xx
287*4882a593Smuzhiyun * @inst: CM instance register offset (*_INST macro)
288*4882a593Smuzhiyun * @clkctrl_offs: Module clock control register offset (*_CLKCTRL macro)
289*4882a593Smuzhiyun *
290*4882a593Smuzhiyun * No return value.
291*4882a593Smuzhiyun */
am33xx_cm_module_disable(u8 part,u16 inst,u16 clkctrl_offs)292*4882a593Smuzhiyun static void am33xx_cm_module_disable(u8 part, u16 inst, u16 clkctrl_offs)
293*4882a593Smuzhiyun {
294*4882a593Smuzhiyun u32 v;
295*4882a593Smuzhiyun
296*4882a593Smuzhiyun v = am33xx_cm_read_reg(inst, clkctrl_offs);
297*4882a593Smuzhiyun v &= ~AM33XX_MODULEMODE_MASK;
298*4882a593Smuzhiyun am33xx_cm_write_reg(v, inst, clkctrl_offs);
299*4882a593Smuzhiyun }
300*4882a593Smuzhiyun
301*4882a593Smuzhiyun /*
302*4882a593Smuzhiyun * Clockdomain low-level functions
303*4882a593Smuzhiyun */
304*4882a593Smuzhiyun
am33xx_clkdm_sleep(struct clockdomain * clkdm)305*4882a593Smuzhiyun static int am33xx_clkdm_sleep(struct clockdomain *clkdm)
306*4882a593Smuzhiyun {
307*4882a593Smuzhiyun am33xx_cm_clkdm_force_sleep(clkdm->cm_inst, clkdm->clkdm_offs);
308*4882a593Smuzhiyun return 0;
309*4882a593Smuzhiyun }
310*4882a593Smuzhiyun
am33xx_clkdm_wakeup(struct clockdomain * clkdm)311*4882a593Smuzhiyun static int am33xx_clkdm_wakeup(struct clockdomain *clkdm)
312*4882a593Smuzhiyun {
313*4882a593Smuzhiyun am33xx_cm_clkdm_force_wakeup(clkdm->cm_inst, clkdm->clkdm_offs);
314*4882a593Smuzhiyun return 0;
315*4882a593Smuzhiyun }
316*4882a593Smuzhiyun
am33xx_clkdm_allow_idle(struct clockdomain * clkdm)317*4882a593Smuzhiyun static void am33xx_clkdm_allow_idle(struct clockdomain *clkdm)
318*4882a593Smuzhiyun {
319*4882a593Smuzhiyun am33xx_cm_clkdm_enable_hwsup(clkdm->cm_inst, clkdm->clkdm_offs);
320*4882a593Smuzhiyun }
321*4882a593Smuzhiyun
am33xx_clkdm_deny_idle(struct clockdomain * clkdm)322*4882a593Smuzhiyun static void am33xx_clkdm_deny_idle(struct clockdomain *clkdm)
323*4882a593Smuzhiyun {
324*4882a593Smuzhiyun am33xx_cm_clkdm_disable_hwsup(clkdm->cm_inst, clkdm->clkdm_offs);
325*4882a593Smuzhiyun }
326*4882a593Smuzhiyun
am33xx_clkdm_clk_enable(struct clockdomain * clkdm)327*4882a593Smuzhiyun static int am33xx_clkdm_clk_enable(struct clockdomain *clkdm)
328*4882a593Smuzhiyun {
329*4882a593Smuzhiyun if (clkdm->flags & CLKDM_CAN_FORCE_WAKEUP)
330*4882a593Smuzhiyun return am33xx_clkdm_wakeup(clkdm);
331*4882a593Smuzhiyun
332*4882a593Smuzhiyun return 0;
333*4882a593Smuzhiyun }
334*4882a593Smuzhiyun
am33xx_clkdm_clk_disable(struct clockdomain * clkdm)335*4882a593Smuzhiyun static int am33xx_clkdm_clk_disable(struct clockdomain *clkdm)
336*4882a593Smuzhiyun {
337*4882a593Smuzhiyun bool hwsup = false;
338*4882a593Smuzhiyun
339*4882a593Smuzhiyun hwsup = am33xx_cm_is_clkdm_in_hwsup(clkdm->cm_inst, clkdm->clkdm_offs);
340*4882a593Smuzhiyun
341*4882a593Smuzhiyun if (!hwsup && (clkdm->flags & CLKDM_CAN_FORCE_SLEEP))
342*4882a593Smuzhiyun am33xx_clkdm_sleep(clkdm);
343*4882a593Smuzhiyun
344*4882a593Smuzhiyun return 0;
345*4882a593Smuzhiyun }
346*4882a593Smuzhiyun
am33xx_cm_xlate_clkctrl(u8 part,u16 inst,u16 offset)347*4882a593Smuzhiyun static u32 am33xx_cm_xlate_clkctrl(u8 part, u16 inst, u16 offset)
348*4882a593Smuzhiyun {
349*4882a593Smuzhiyun return cm_base.pa + inst + offset;
350*4882a593Smuzhiyun }
351*4882a593Smuzhiyun
352*4882a593Smuzhiyun /**
353*4882a593Smuzhiyun * am33xx_clkdm_save_context - Save the clockdomain transition context
354*4882a593Smuzhiyun * @clkdm: The clockdomain pointer whose context needs to be saved
355*4882a593Smuzhiyun *
356*4882a593Smuzhiyun * Save the clockdomain transition context.
357*4882a593Smuzhiyun */
am33xx_clkdm_save_context(struct clockdomain * clkdm)358*4882a593Smuzhiyun static int am33xx_clkdm_save_context(struct clockdomain *clkdm)
359*4882a593Smuzhiyun {
360*4882a593Smuzhiyun clkdm->context = am33xx_cm_read_reg_bits(clkdm->cm_inst,
361*4882a593Smuzhiyun clkdm->clkdm_offs,
362*4882a593Smuzhiyun AM33XX_CLKTRCTRL_MASK);
363*4882a593Smuzhiyun
364*4882a593Smuzhiyun return 0;
365*4882a593Smuzhiyun }
366*4882a593Smuzhiyun
367*4882a593Smuzhiyun /**
368*4882a593Smuzhiyun * am33xx_restore_save_context - Restore the clockdomain transition context
369*4882a593Smuzhiyun * @clkdm: The clockdomain pointer whose context needs to be restored
370*4882a593Smuzhiyun *
371*4882a593Smuzhiyun * Restore the clockdomain transition context.
372*4882a593Smuzhiyun */
am33xx_clkdm_restore_context(struct clockdomain * clkdm)373*4882a593Smuzhiyun static int am33xx_clkdm_restore_context(struct clockdomain *clkdm)
374*4882a593Smuzhiyun {
375*4882a593Smuzhiyun switch (clkdm->context) {
376*4882a593Smuzhiyun case OMAP34XX_CLKSTCTRL_DISABLE_AUTO:
377*4882a593Smuzhiyun am33xx_clkdm_deny_idle(clkdm);
378*4882a593Smuzhiyun break;
379*4882a593Smuzhiyun case OMAP34XX_CLKSTCTRL_FORCE_SLEEP:
380*4882a593Smuzhiyun am33xx_clkdm_sleep(clkdm);
381*4882a593Smuzhiyun break;
382*4882a593Smuzhiyun case OMAP34XX_CLKSTCTRL_FORCE_WAKEUP:
383*4882a593Smuzhiyun am33xx_clkdm_wakeup(clkdm);
384*4882a593Smuzhiyun break;
385*4882a593Smuzhiyun case OMAP34XX_CLKSTCTRL_ENABLE_AUTO:
386*4882a593Smuzhiyun am33xx_clkdm_allow_idle(clkdm);
387*4882a593Smuzhiyun break;
388*4882a593Smuzhiyun }
389*4882a593Smuzhiyun return 0;
390*4882a593Smuzhiyun }
391*4882a593Smuzhiyun
392*4882a593Smuzhiyun struct clkdm_ops am33xx_clkdm_operations = {
393*4882a593Smuzhiyun .clkdm_sleep = am33xx_clkdm_sleep,
394*4882a593Smuzhiyun .clkdm_wakeup = am33xx_clkdm_wakeup,
395*4882a593Smuzhiyun .clkdm_allow_idle = am33xx_clkdm_allow_idle,
396*4882a593Smuzhiyun .clkdm_deny_idle = am33xx_clkdm_deny_idle,
397*4882a593Smuzhiyun .clkdm_clk_enable = am33xx_clkdm_clk_enable,
398*4882a593Smuzhiyun .clkdm_clk_disable = am33xx_clkdm_clk_disable,
399*4882a593Smuzhiyun .clkdm_save_context = am33xx_clkdm_save_context,
400*4882a593Smuzhiyun .clkdm_restore_context = am33xx_clkdm_restore_context,
401*4882a593Smuzhiyun };
402*4882a593Smuzhiyun
403*4882a593Smuzhiyun static const struct cm_ll_data am33xx_cm_ll_data = {
404*4882a593Smuzhiyun .wait_module_ready = &am33xx_cm_wait_module_ready,
405*4882a593Smuzhiyun .wait_module_idle = &am33xx_cm_wait_module_idle,
406*4882a593Smuzhiyun .module_enable = &am33xx_cm_module_enable,
407*4882a593Smuzhiyun .module_disable = &am33xx_cm_module_disable,
408*4882a593Smuzhiyun .xlate_clkctrl = &am33xx_cm_xlate_clkctrl,
409*4882a593Smuzhiyun };
410*4882a593Smuzhiyun
am33xx_cm_init(const struct omap_prcm_init_data * data)411*4882a593Smuzhiyun int __init am33xx_cm_init(const struct omap_prcm_init_data *data)
412*4882a593Smuzhiyun {
413*4882a593Smuzhiyun return cm_register(&am33xx_cm_ll_data);
414*4882a593Smuzhiyun }
415*4882a593Smuzhiyun
am33xx_cm_exit(void)416*4882a593Smuzhiyun static void __exit am33xx_cm_exit(void)
417*4882a593Smuzhiyun {
418*4882a593Smuzhiyun cm_unregister(&am33xx_cm_ll_data);
419*4882a593Smuzhiyun }
420*4882a593Smuzhiyun __exitcall(am33xx_cm_exit);
421