2 * OMAP3-specific clock framework functions
4 * Copyright (C) 2007-2008 Texas Instruments, Inc.
5 * Copyright (C) 2007-2010 Nokia Corporation
10 * Parts of this code are based on code written by
11 * Richard Woodruff, Tony Lindgren, Tuukka Tikkanen, Karthik Dasu
13 * This program is free software; you can redistribute it and/or modify
14 * it under the terms of the GNU General Public License version 2 as
15 * published by the Free Software Foundation.
19 #include <linux/kernel.h>
20 #include <linux/errno.h>
21 #include <linux/delay.h>
22 #include <linux/clk.h>
26 #include <plat/clock.h>
29 #include "clock34xx.h"
31 #include "prm-regbits-34xx.h"
33 #include "cm-regbits-34xx.h"
36 * DPLL5_FREQ_FOR_USBHOST: USBHOST and USBTLL are the only clocks
37 * that are sourced by DPLL5, and both of these require this clock
38 * to be at 120 MHz for proper operation.
40 #define DPLL5_FREQ_FOR_USBHOST 120000000
42 /* needed by omap3_core_dpll_m2_set_rate() */
43 struct clk *sdrc_ick_p, *arm_fck_p;
46 * omap3430es2_clk_ssi_find_idlest - return CM_IDLEST info for SSI
47 * @clk: struct clk * being enabled
48 * @idlest_reg: void __iomem ** to store CM_IDLEST reg address into
49 * @idlest_bit: pointer to a u8 to store the CM_IDLEST bit shift into
50 * @idlest_val: pointer to a u8 to store the CM_IDLEST indicator
52 * The OMAP3430ES2 SSI target CM_IDLEST bit is at a different shift
53 * from the CM_{I,F}CLKEN bit. Pass back the correct info via
54 * @idlest_reg and @idlest_bit. No return value.
56 static void omap3430es2_clk_ssi_find_idlest(struct clk *clk,
57 void __iomem **idlest_reg,
63 r = (((__force u32)clk->enable_reg & ~0xf0) | 0x20);
64 *idlest_reg = (__force void __iomem *)r;
65 *idlest_bit = OMAP3430ES2_ST_SSI_IDLE_SHIFT;
66 *idlest_val = OMAP34XX_CM_IDLEST_VAL;
69 const struct clkops clkops_omap3430es2_ssi_wait = {
70 .enable = omap2_dflt_clk_enable,
71 .disable = omap2_dflt_clk_disable,
72 .find_idlest = omap3430es2_clk_ssi_find_idlest,
73 .find_companion = omap2_clk_dflt_find_companion,
77 * omap3430es2_clk_dss_usbhost_find_idlest - CM_IDLEST info for DSS, USBHOST
78 * @clk: struct clk * being enabled
79 * @idlest_reg: void __iomem ** to store CM_IDLEST reg address into
80 * @idlest_bit: pointer to a u8 to store the CM_IDLEST bit shift into
81 * @idlest_val: pointer to a u8 to store the CM_IDLEST indicator
83 * Some OMAP modules on OMAP3 ES2+ chips have both initiator and
84 * target IDLEST bits. For our purposes, we are concerned with the
85 * target IDLEST bits, which exist at a different bit position than
86 * the *CLKEN bit position for these modules (DSS and USBHOST) (The
87 * default find_idlest code assumes that they are at the same
88 * position.) No return value.
90 static void omap3430es2_clk_dss_usbhost_find_idlest(struct clk *clk,
91 void __iomem **idlest_reg,
97 r = (((__force u32)clk->enable_reg & ~0xf0) | 0x20);
98 *idlest_reg = (__force void __iomem *)r;
99 /* USBHOST_IDLE has same shift */
100 *idlest_bit = OMAP3430ES2_ST_DSS_IDLE_SHIFT;
101 *idlest_val = OMAP34XX_CM_IDLEST_VAL;
104 const struct clkops clkops_omap3430es2_dss_usbhost_wait = {
105 .enable = omap2_dflt_clk_enable,
106 .disable = omap2_dflt_clk_disable,
107 .find_idlest = omap3430es2_clk_dss_usbhost_find_idlest,
108 .find_companion = omap2_clk_dflt_find_companion,
112 * omap3430es2_clk_hsotgusb_find_idlest - return CM_IDLEST info for HSOTGUSB
113 * @clk: struct clk * being enabled
114 * @idlest_reg: void __iomem ** to store CM_IDLEST reg address into
115 * @idlest_bit: pointer to a u8 to store the CM_IDLEST bit shift into
116 * @idlest_val: pointer to a u8 to store the CM_IDLEST indicator
118 * The OMAP3430ES2 HSOTGUSB target CM_IDLEST bit is at a different
119 * shift from the CM_{I,F}CLKEN bit. Pass back the correct info via
120 * @idlest_reg and @idlest_bit. No return value.
122 static void omap3430es2_clk_hsotgusb_find_idlest(struct clk *clk,
123 void __iomem **idlest_reg,
129 r = (((__force u32)clk->enable_reg & ~0xf0) | 0x20);
130 *idlest_reg = (__force void __iomem *)r;
131 *idlest_bit = OMAP3430ES2_ST_HSOTGUSB_IDLE_SHIFT;
132 *idlest_val = OMAP34XX_CM_IDLEST_VAL;
135 const struct clkops clkops_omap3430es2_hsotgusb_wait = {
136 .enable = omap2_dflt_clk_enable,
137 .disable = omap2_dflt_clk_disable,
138 .find_idlest = omap3430es2_clk_hsotgusb_find_idlest,
139 .find_companion = omap2_clk_dflt_find_companion,
142 const struct clkops omap3_clkops_noncore_dpll_ops = {
143 .enable = omap3_noncore_dpll_enable,
144 .disable = omap3_noncore_dpll_disable,
147 int omap3_dpll4_set_rate(struct clk *clk, unsigned long rate)
150 * According to the 12-5 CDP code from TI, "Limitation 2.5"
151 * on 3430ES1 prevents us from changing DPLL multipliers or dividers
154 if (omap_rev() == OMAP3430_REV_ES1_0) {
155 printk(KERN_ERR "clock: DPLL4 cannot change rate due to "
156 "silicon 'Limitation 2.5' on 3430ES1.\n");
159 return omap3_noncore_dpll_set_rate(clk, rate);
162 void __init omap3_clk_lock_dpll5(void)
164 struct clk *dpll5_clk;
165 struct clk *dpll5_m2_clk;
167 dpll5_clk = clk_get(NULL, "dpll5_ck");
168 clk_set_rate(dpll5_clk, DPLL5_FREQ_FOR_USBHOST);
169 clk_enable(dpll5_clk);
171 /* Enable autoidle to allow it to enter low power bypass */
172 omap3_dpll_allow_idle(dpll5_clk);
174 /* Program dpll5_m2_clk divider for no division */
175 dpll5_m2_clk = clk_get(NULL, "dpll5_m2_ck");
176 clk_enable(dpll5_m2_clk);
177 clk_set_rate(dpll5_m2_clk, DPLL5_FREQ_FOR_USBHOST);
179 clk_disable(dpll5_m2_clk);
180 clk_disable(dpll5_clk);
184 /* Common clock code */
186 /* REVISIT: Move this init stuff out into clock.c */
189 * Switch the MPU rate if specified on cmdline.
190 * We cannot do this early until cmdline is parsed.
192 static int __init omap3xxx_clk_arch_init(void)
194 struct clk *osc_sys_ck, *dpll1_ck, *arm_fck, *core_ck;
195 unsigned long osc_sys_rate;
197 if (!cpu_is_omap34xx())
203 /* XXX test these for success */
204 dpll1_ck = clk_get(NULL, "dpll1_ck");
205 arm_fck = clk_get(NULL, "arm_fck");
206 core_ck = clk_get(NULL, "core_ck");
207 osc_sys_ck = clk_get(NULL, "osc_sys_ck");
209 /* REVISIT: not yet ready for 343x */
210 if (clk_set_rate(dpll1_ck, mpurate))
211 printk(KERN_ERR "*** Unable to set MPU rate\n");
213 recalculate_root_clocks();
215 osc_sys_rate = clk_get_rate(osc_sys_ck);
217 pr_info("Switched to new clocking rate (Crystal/Core/MPU): "
218 "%ld.%01ld/%ld/%ld MHz\n",
219 (osc_sys_rate / 1000000),
220 ((osc_sys_rate / 100000) % 10),
221 (clk_get_rate(core_ck) / 1000000),
222 (clk_get_rate(arm_fck) / 1000000));
228 arch_initcall(omap3xxx_clk_arch_init);