1d2912cb1SThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only
2ff4ae5d9SPaul Walmsley /*
3ff4ae5d9SPaul Walmsley * OMAP2xxx CM module functions
4ff4ae5d9SPaul Walmsley *
5ff4ae5d9SPaul Walmsley * Copyright (C) 2009 Nokia Corporation
64bd5259eSPaul Walmsley * Copyright (C) 2008-2010, 2012 Texas Instruments, Inc.
7ff4ae5d9SPaul Walmsley * Paul Walmsley
84bd5259eSPaul Walmsley * Rajendra Nayak <rnayak@ti.com>
9ff4ae5d9SPaul Walmsley */
10ff4ae5d9SPaul Walmsley
11ff4ae5d9SPaul Walmsley #include <linux/kernel.h>
12ff4ae5d9SPaul Walmsley #include <linux/types.h>
13ff4ae5d9SPaul Walmsley #include <linux/delay.h>
14ff4ae5d9SPaul Walmsley #include <linux/errno.h>
15ff4ae5d9SPaul Walmsley #include <linux/err.h>
16ff4ae5d9SPaul Walmsley #include <linux/io.h>
17ff4ae5d9SPaul Walmsley
184bd5259eSPaul Walmsley #include "prm2xxx.h"
19ff4ae5d9SPaul Walmsley #include "cm.h"
20ff4ae5d9SPaul Walmsley #include "cm2xxx.h"
21ff4ae5d9SPaul Walmsley #include "cm-regbits-24xx.h"
224bd5259eSPaul Walmsley #include "clockdomain.h"
23ff4ae5d9SPaul Walmsley
24ff4ae5d9SPaul Walmsley /* CM_AUTOIDLE_PLL.AUTO_* bit values for DPLLs */
25ff4ae5d9SPaul Walmsley #define DPLL_AUTOIDLE_DISABLE 0x0
26ff4ae5d9SPaul Walmsley #define OMAP2XXX_DPLL_AUTOIDLE_LOW_POWER_STOP 0x3
27ff4ae5d9SPaul Walmsley
28ff4ae5d9SPaul Walmsley /* CM_AUTOIDLE_PLL.AUTO_* bit values for APLLs (OMAP2xxx only) */
29ff4ae5d9SPaul Walmsley #define OMAP2XXX_APLL_AUTOIDLE_DISABLE 0x0
30ff4ae5d9SPaul Walmsley #define OMAP2XXX_APLL_AUTOIDLE_LOW_POWER_STOP 0x3
31ff4ae5d9SPaul Walmsley
32b6ffa050SPaul Walmsley /* CM_IDLEST_PLL bit value offset for APLLs (OMAP2xxx only) */
33b6ffa050SPaul Walmsley #define EN_APLL_LOCKED 3
34b6ffa050SPaul Walmsley
35ff4ae5d9SPaul Walmsley static const u8 omap2xxx_cm_idlest_offs[] = {
36ff4ae5d9SPaul Walmsley CM_IDLEST1, CM_IDLEST2, OMAP2430_CM_IDLEST3, OMAP24XX_CM_IDLEST4
37ff4ae5d9SPaul Walmsley };
38ff4ae5d9SPaul Walmsley
39ff4ae5d9SPaul Walmsley /*
40ff4ae5d9SPaul Walmsley *
41ff4ae5d9SPaul Walmsley */
42ff4ae5d9SPaul Walmsley
_write_clktrctrl(u8 c,s16 module,u32 mask)43ff4ae5d9SPaul Walmsley static void _write_clktrctrl(u8 c, s16 module, u32 mask)
44ff4ae5d9SPaul Walmsley {
45ff4ae5d9SPaul Walmsley u32 v;
46ff4ae5d9SPaul Walmsley
47ff4ae5d9SPaul Walmsley v = omap2_cm_read_mod_reg(module, OMAP2_CM_CLKSTCTRL);
48ff4ae5d9SPaul Walmsley v &= ~mask;
49ff4ae5d9SPaul Walmsley v |= c << __ffs(mask);
50ff4ae5d9SPaul Walmsley omap2_cm_write_mod_reg(v, module, OMAP2_CM_CLKSTCTRL);
51ff4ae5d9SPaul Walmsley }
52ff4ae5d9SPaul Walmsley
omap2xxx_cm_is_clkdm_in_hwsup(s16 module,u32 mask)53f2650d6eSTero Kristo static bool omap2xxx_cm_is_clkdm_in_hwsup(s16 module, u32 mask)
54ff4ae5d9SPaul Walmsley {
55ff4ae5d9SPaul Walmsley u32 v;
56ff4ae5d9SPaul Walmsley
57ff4ae5d9SPaul Walmsley v = omap2_cm_read_mod_reg(module, OMAP2_CM_CLKSTCTRL);
58ff4ae5d9SPaul Walmsley v &= mask;
59ff4ae5d9SPaul Walmsley v >>= __ffs(mask);
60ff4ae5d9SPaul Walmsley
61ff4ae5d9SPaul Walmsley return (v == OMAP24XX_CLKSTCTRL_ENABLE_AUTO) ? 1 : 0;
62ff4ae5d9SPaul Walmsley }
63ff4ae5d9SPaul Walmsley
omap2xxx_cm_clkdm_enable_hwsup(s16 module,u32 mask)64f2650d6eSTero Kristo static void omap2xxx_cm_clkdm_enable_hwsup(s16 module, u32 mask)
65ff4ae5d9SPaul Walmsley {
66ff4ae5d9SPaul Walmsley _write_clktrctrl(OMAP24XX_CLKSTCTRL_ENABLE_AUTO, module, mask);
67ff4ae5d9SPaul Walmsley }
68ff4ae5d9SPaul Walmsley
omap2xxx_cm_clkdm_disable_hwsup(s16 module,u32 mask)69f2650d6eSTero Kristo static void omap2xxx_cm_clkdm_disable_hwsup(s16 module, u32 mask)
70ff4ae5d9SPaul Walmsley {
71ff4ae5d9SPaul Walmsley _write_clktrctrl(OMAP24XX_CLKSTCTRL_DISABLE_AUTO, module, mask);
72ff4ae5d9SPaul Walmsley }
73ff4ae5d9SPaul Walmsley
74ff4ae5d9SPaul Walmsley /*
75ff4ae5d9SPaul Walmsley * DPLL autoidle control
76ff4ae5d9SPaul Walmsley */
77ff4ae5d9SPaul Walmsley
_omap2xxx_set_dpll_autoidle(u8 m)78ff4ae5d9SPaul Walmsley static void _omap2xxx_set_dpll_autoidle(u8 m)
79ff4ae5d9SPaul Walmsley {
80ff4ae5d9SPaul Walmsley u32 v;
81ff4ae5d9SPaul Walmsley
82ff4ae5d9SPaul Walmsley v = omap2_cm_read_mod_reg(PLL_MOD, CM_AUTOIDLE);
83ff4ae5d9SPaul Walmsley v &= ~OMAP24XX_AUTO_DPLL_MASK;
84ff4ae5d9SPaul Walmsley v |= m << OMAP24XX_AUTO_DPLL_SHIFT;
85ff4ae5d9SPaul Walmsley omap2_cm_write_mod_reg(v, PLL_MOD, CM_AUTOIDLE);
86ff4ae5d9SPaul Walmsley }
87ff4ae5d9SPaul Walmsley
omap2xxx_cm_set_dpll_disable_autoidle(void)88ff4ae5d9SPaul Walmsley void omap2xxx_cm_set_dpll_disable_autoidle(void)
89ff4ae5d9SPaul Walmsley {
90ff4ae5d9SPaul Walmsley _omap2xxx_set_dpll_autoidle(OMAP2XXX_DPLL_AUTOIDLE_LOW_POWER_STOP);
91ff4ae5d9SPaul Walmsley }
92ff4ae5d9SPaul Walmsley
omap2xxx_cm_set_dpll_auto_low_power_stop(void)93ff4ae5d9SPaul Walmsley void omap2xxx_cm_set_dpll_auto_low_power_stop(void)
94ff4ae5d9SPaul Walmsley {
95ff4ae5d9SPaul Walmsley _omap2xxx_set_dpll_autoidle(DPLL_AUTOIDLE_DISABLE);
96ff4ae5d9SPaul Walmsley }
97ff4ae5d9SPaul Walmsley
98c4ceedcbSPaul Walmsley /**
99c4ceedcbSPaul Walmsley * omap2xxx_cm_split_idlest_reg - split CM_IDLEST reg addr into its components
100c4ceedcbSPaul Walmsley * @idlest_reg: CM_IDLEST* virtual address
101c4ceedcbSPaul Walmsley * @prcm_inst: pointer to an s16 to return the PRCM instance offset
102c4ceedcbSPaul Walmsley * @idlest_reg_id: pointer to a u8 to return the CM_IDLESTx register ID
103c4ceedcbSPaul Walmsley *
104c4ceedcbSPaul Walmsley * XXX This function is only needed until absolute register addresses are
105c4ceedcbSPaul Walmsley * removed from the OMAP struct clk records.
106c4ceedcbSPaul Walmsley */
omap2xxx_cm_split_idlest_reg(struct clk_omap_reg * idlest_reg,s16 * prcm_inst,u8 * idlest_reg_id)1076c0afb50STero Kristo static int omap2xxx_cm_split_idlest_reg(struct clk_omap_reg *idlest_reg,
1082196a9b8STero Kristo s16 *prcm_inst,
109c4ceedcbSPaul Walmsley u8 *idlest_reg_id)
110c4ceedcbSPaul Walmsley {
111c4ceedcbSPaul Walmsley unsigned long offs;
112c4ceedcbSPaul Walmsley u8 idlest_offs;
113c4ceedcbSPaul Walmsley int i;
114c4ceedcbSPaul Walmsley
1156c0afb50STero Kristo idlest_offs = idlest_reg->offset & 0xff;
116c4ceedcbSPaul Walmsley for (i = 0; i < ARRAY_SIZE(omap2xxx_cm_idlest_offs); i++) {
117c4ceedcbSPaul Walmsley if (idlest_offs == omap2xxx_cm_idlest_offs[i]) {
118c4ceedcbSPaul Walmsley *idlest_reg_id = i + 1;
119c4ceedcbSPaul Walmsley break;
120c4ceedcbSPaul Walmsley }
121c4ceedcbSPaul Walmsley }
122c4ceedcbSPaul Walmsley
123c4ceedcbSPaul Walmsley if (i == ARRAY_SIZE(omap2xxx_cm_idlest_offs))
124c4ceedcbSPaul Walmsley return -EINVAL;
125c4ceedcbSPaul Walmsley
1266c0afb50STero Kristo offs = idlest_reg->offset;
127c4ceedcbSPaul Walmsley offs &= 0xff00;
128c4ceedcbSPaul Walmsley *prcm_inst = offs;
129c4ceedcbSPaul Walmsley
130c4ceedcbSPaul Walmsley return 0;
131c4ceedcbSPaul Walmsley }
132c4ceedcbSPaul Walmsley
133ff4ae5d9SPaul Walmsley /*
134ff4ae5d9SPaul Walmsley *
135ff4ae5d9SPaul Walmsley */
136ff4ae5d9SPaul Walmsley
137ff4ae5d9SPaul Walmsley /**
138ff4ae5d9SPaul Walmsley * omap2xxx_cm_wait_module_ready - wait for a module to leave idle or standby
139021b6ff0STero Kristo * @part: PRCM partition, ignored for OMAP2
140ff4ae5d9SPaul Walmsley * @prcm_mod: PRCM module offset
141ff4ae5d9SPaul Walmsley * @idlest_id: CM_IDLESTx register ID (i.e., x = 1, 2, 3)
142ff4ae5d9SPaul Walmsley * @idlest_shift: shift of the bit in the CM_IDLEST* register to check
143ff4ae5d9SPaul Walmsley *
144ff4ae5d9SPaul Walmsley * Wait for the PRCM to indicate that the module identified by
145ff4ae5d9SPaul Walmsley * (@prcm_mod, @idlest_id, @idlest_shift) is clocked. Return 0 upon
146ff4ae5d9SPaul Walmsley * success or -EBUSY if the module doesn't enable in time.
147ff4ae5d9SPaul Walmsley */
omap2xxx_cm_wait_module_ready(u8 part,s16 prcm_mod,u16 idlest_id,u8 idlest_shift)148*6aeb51c1SArnd Bergmann static int omap2xxx_cm_wait_module_ready(u8 part, s16 prcm_mod, u16 idlest_id,
149021b6ff0STero Kristo u8 idlest_shift)
150ff4ae5d9SPaul Walmsley {
151ff4ae5d9SPaul Walmsley int ena = 0, i = 0;
152ff4ae5d9SPaul Walmsley u8 cm_idlest_reg;
153ff4ae5d9SPaul Walmsley u32 mask;
154ff4ae5d9SPaul Walmsley
155ff4ae5d9SPaul Walmsley if (!idlest_id || (idlest_id > ARRAY_SIZE(omap2xxx_cm_idlest_offs)))
156ff4ae5d9SPaul Walmsley return -EINVAL;
157ff4ae5d9SPaul Walmsley
158ff4ae5d9SPaul Walmsley cm_idlest_reg = omap2xxx_cm_idlest_offs[idlest_id - 1];
159ff4ae5d9SPaul Walmsley
160ff4ae5d9SPaul Walmsley mask = 1 << idlest_shift;
161ff4ae5d9SPaul Walmsley ena = mask;
162ff4ae5d9SPaul Walmsley
163ff4ae5d9SPaul Walmsley omap_test_timeout(((omap2_cm_read_mod_reg(prcm_mod, cm_idlest_reg) &
164ff4ae5d9SPaul Walmsley mask) == ena), MAX_MODULE_READY_TIME, i);
165ff4ae5d9SPaul Walmsley
166ff4ae5d9SPaul Walmsley return (i < MAX_MODULE_READY_TIME) ? 0 : -EBUSY;
167ff4ae5d9SPaul Walmsley }
1684bd5259eSPaul Walmsley
1694bd5259eSPaul Walmsley /* Clockdomain low-level functions */
1704bd5259eSPaul Walmsley
omap2xxx_clkdm_allow_idle(struct clockdomain * clkdm)1714bd5259eSPaul Walmsley static void omap2xxx_clkdm_allow_idle(struct clockdomain *clkdm)
1724bd5259eSPaul Walmsley {
1734bd5259eSPaul Walmsley omap2xxx_cm_clkdm_enable_hwsup(clkdm->pwrdm.ptr->prcm_offs,
1744bd5259eSPaul Walmsley clkdm->clktrctrl_mask);
1754bd5259eSPaul Walmsley }
1764bd5259eSPaul Walmsley
omap2xxx_clkdm_deny_idle(struct clockdomain * clkdm)1774bd5259eSPaul Walmsley static void omap2xxx_clkdm_deny_idle(struct clockdomain *clkdm)
1784bd5259eSPaul Walmsley {
1794bd5259eSPaul Walmsley omap2xxx_cm_clkdm_disable_hwsup(clkdm->pwrdm.ptr->prcm_offs,
1804bd5259eSPaul Walmsley clkdm->clktrctrl_mask);
1814bd5259eSPaul Walmsley }
1824bd5259eSPaul Walmsley
omap2xxx_clkdm_clk_enable(struct clockdomain * clkdm)1834bd5259eSPaul Walmsley static int omap2xxx_clkdm_clk_enable(struct clockdomain *clkdm)
1844bd5259eSPaul Walmsley {
1854bd5259eSPaul Walmsley bool hwsup = false;
1864bd5259eSPaul Walmsley
1874bd5259eSPaul Walmsley if (!clkdm->clktrctrl_mask)
1884bd5259eSPaul Walmsley return 0;
1894bd5259eSPaul Walmsley
1904bd5259eSPaul Walmsley hwsup = omap2xxx_cm_is_clkdm_in_hwsup(clkdm->pwrdm.ptr->prcm_offs,
1914bd5259eSPaul Walmsley clkdm->clktrctrl_mask);
192cc3af91bSPaul Walmsley if (!hwsup && clkdm->flags & CLKDM_CAN_FORCE_WAKEUP)
1934bd5259eSPaul Walmsley omap2xxx_clkdm_wakeup(clkdm);
1944bd5259eSPaul Walmsley
1954bd5259eSPaul Walmsley return 0;
1964bd5259eSPaul Walmsley }
1974bd5259eSPaul Walmsley
omap2xxx_clkdm_clk_disable(struct clockdomain * clkdm)1984bd5259eSPaul Walmsley static int omap2xxx_clkdm_clk_disable(struct clockdomain *clkdm)
1994bd5259eSPaul Walmsley {
2004bd5259eSPaul Walmsley bool hwsup = false;
2014bd5259eSPaul Walmsley
2024bd5259eSPaul Walmsley if (!clkdm->clktrctrl_mask)
2034bd5259eSPaul Walmsley return 0;
2044bd5259eSPaul Walmsley
2054bd5259eSPaul Walmsley hwsup = omap2xxx_cm_is_clkdm_in_hwsup(clkdm->pwrdm.ptr->prcm_offs,
2064bd5259eSPaul Walmsley clkdm->clktrctrl_mask);
2074bd5259eSPaul Walmsley
208cc3af91bSPaul Walmsley if (!hwsup && clkdm->flags & CLKDM_CAN_FORCE_SLEEP)
2094bd5259eSPaul Walmsley omap2xxx_clkdm_sleep(clkdm);
2104bd5259eSPaul Walmsley
2114bd5259eSPaul Walmsley return 0;
2124bd5259eSPaul Walmsley }
2134bd5259eSPaul Walmsley
2144bd5259eSPaul Walmsley struct clkdm_ops omap2_clkdm_operations = {
2154bd5259eSPaul Walmsley .clkdm_add_wkdep = omap2_clkdm_add_wkdep,
2164bd5259eSPaul Walmsley .clkdm_del_wkdep = omap2_clkdm_del_wkdep,
2174bd5259eSPaul Walmsley .clkdm_read_wkdep = omap2_clkdm_read_wkdep,
2184bd5259eSPaul Walmsley .clkdm_clear_all_wkdeps = omap2_clkdm_clear_all_wkdeps,
2194bd5259eSPaul Walmsley .clkdm_sleep = omap2xxx_clkdm_sleep,
2204bd5259eSPaul Walmsley .clkdm_wakeup = omap2xxx_clkdm_wakeup,
2214bd5259eSPaul Walmsley .clkdm_allow_idle = omap2xxx_clkdm_allow_idle,
2224bd5259eSPaul Walmsley .clkdm_deny_idle = omap2xxx_clkdm_deny_idle,
2234bd5259eSPaul Walmsley .clkdm_clk_enable = omap2xxx_clkdm_clk_enable,
2244bd5259eSPaul Walmsley .clkdm_clk_disable = omap2xxx_clkdm_clk_disable,
2254bd5259eSPaul Walmsley };
226c4ceedcbSPaul Walmsley
omap2xxx_cm_fclks_active(void)227cd6e9db2STero Kristo int omap2xxx_cm_fclks_active(void)
228cd6e9db2STero Kristo {
229cd6e9db2STero Kristo u32 f1, f2;
230cd6e9db2STero Kristo
231cd6e9db2STero Kristo f1 = omap2_cm_read_mod_reg(CORE_MOD, CM_FCLKEN1);
232cd6e9db2STero Kristo f2 = omap2_cm_read_mod_reg(CORE_MOD, OMAP24XX_CM_FCLKEN2);
233cd6e9db2STero Kristo
234cd6e9db2STero Kristo return (f1 | f2) ? 1 : 0;
235cd6e9db2STero Kristo }
236cd6e9db2STero Kristo
omap2xxx_cm_mpu_retention_allowed(void)237cd6e9db2STero Kristo int omap2xxx_cm_mpu_retention_allowed(void)
238cd6e9db2STero Kristo {
239cd6e9db2STero Kristo u32 l;
240cd6e9db2STero Kristo
241cd6e9db2STero Kristo /* Check for MMC, UART2, UART1, McSPI2, McSPI1 and DSS1. */
242cd6e9db2STero Kristo l = omap2_cm_read_mod_reg(CORE_MOD, CM_FCLKEN1);
243cd6e9db2STero Kristo if (l & (OMAP2420_EN_MMC_MASK | OMAP24XX_EN_UART2_MASK |
244cd6e9db2STero Kristo OMAP24XX_EN_UART1_MASK | OMAP24XX_EN_MCSPI2_MASK |
245cd6e9db2STero Kristo OMAP24XX_EN_MCSPI1_MASK | OMAP24XX_EN_DSS1_MASK))
246cd6e9db2STero Kristo return 0;
247cd6e9db2STero Kristo /* Check for UART3. */
248cd6e9db2STero Kristo l = omap2_cm_read_mod_reg(CORE_MOD, OMAP24XX_CM_FCLKEN2);
249cd6e9db2STero Kristo if (l & OMAP24XX_EN_UART3_MASK)
250cd6e9db2STero Kristo return 0;
251cd6e9db2STero Kristo
252cd6e9db2STero Kristo return 1;
253cd6e9db2STero Kristo }
254cd6e9db2STero Kristo
omap2xxx_cm_get_core_clk_src(void)255cd6e9db2STero Kristo u32 omap2xxx_cm_get_core_clk_src(void)
256cd6e9db2STero Kristo {
257cd6e9db2STero Kristo u32 v;
258cd6e9db2STero Kristo
259cd6e9db2STero Kristo v = omap2_cm_read_mod_reg(PLL_MOD, CM_CLKSEL2);
260cd6e9db2STero Kristo v &= OMAP24XX_CORE_CLK_SRC_MASK;
261cd6e9db2STero Kristo
262cd6e9db2STero Kristo return v;
263cd6e9db2STero Kristo }
264cd6e9db2STero Kristo
omap2xxx_cm_get_core_pll_config(void)265cd6e9db2STero Kristo u32 omap2xxx_cm_get_core_pll_config(void)
266cd6e9db2STero Kristo {
267cd6e9db2STero Kristo return omap2_cm_read_mod_reg(PLL_MOD, CM_CLKSEL2);
268cd6e9db2STero Kristo }
269cd6e9db2STero Kristo
omap2xxx_cm_set_mod_dividers(u32 mpu,u32 dsp,u32 gfx,u32 core,u32 mdm)270cd6e9db2STero Kristo void omap2xxx_cm_set_mod_dividers(u32 mpu, u32 dsp, u32 gfx, u32 core, u32 mdm)
271cd6e9db2STero Kristo {
272cd6e9db2STero Kristo u32 tmp;
273cd6e9db2STero Kristo
274cd6e9db2STero Kristo omap2_cm_write_mod_reg(mpu, MPU_MOD, CM_CLKSEL);
275cd6e9db2STero Kristo omap2_cm_write_mod_reg(dsp, OMAP24XX_DSP_MOD, CM_CLKSEL);
276cd6e9db2STero Kristo omap2_cm_write_mod_reg(gfx, GFX_MOD, CM_CLKSEL);
277cd6e9db2STero Kristo tmp = omap2_cm_read_mod_reg(CORE_MOD, CM_CLKSEL1) &
278cd6e9db2STero Kristo OMAP24XX_CLKSEL_DSS2_MASK;
279cd6e9db2STero Kristo omap2_cm_write_mod_reg(core | tmp, CORE_MOD, CM_CLKSEL1);
2807af13637STero Kristo if (mdm)
281cd6e9db2STero Kristo omap2_cm_write_mod_reg(mdm, OMAP2430_MDM_MOD, CM_CLKSEL);
282cd6e9db2STero Kristo }
283cd6e9db2STero Kristo
284c4ceedcbSPaul Walmsley /*
285c4ceedcbSPaul Walmsley *
286c4ceedcbSPaul Walmsley */
287c4ceedcbSPaul Walmsley
28860af58cdSBhumika Goyal static const struct cm_ll_data omap2xxx_cm_ll_data = {
289c4ceedcbSPaul Walmsley .split_idlest_reg = &omap2xxx_cm_split_idlest_reg,
290c4ceedcbSPaul Walmsley .wait_module_ready = &omap2xxx_cm_wait_module_ready,
291c4ceedcbSPaul Walmsley };
292c4ceedcbSPaul Walmsley
omap2xxx_cm_init(const struct omap_prcm_init_data * data)293425dc8b2STero Kristo int __init omap2xxx_cm_init(const struct omap_prcm_init_data *data)
294c4ceedcbSPaul Walmsley {
295c4ceedcbSPaul Walmsley return cm_register(&omap2xxx_cm_ll_data);
296c4ceedcbSPaul Walmsley }
297c4ceedcbSPaul Walmsley
omap2xxx_cm_exit(void)298c4ceedcbSPaul Walmsley static void __exit omap2xxx_cm_exit(void)
299c4ceedcbSPaul Walmsley {
3007af13637STero Kristo cm_unregister(&omap2xxx_cm_ll_data);
301c4ceedcbSPaul Walmsley }
302c4ceedcbSPaul Walmsley __exitcall(omap2xxx_cm_exit);
303