blob: deb873fb12b652ef8c6b5524cde94cbb6e0fa366 [file] [log] [blame]
Colin Crossd8611962010-01-28 16:40:29 -08001/*
Prashant Gaikwad92fe58f2012-08-06 11:57:43 +05302 * arch/arm/mach-tegra/tegra20_clocks.c
Colin Crossd8611962010-01-28 16:40:29 -08003 *
4 * Copyright (C) 2010 Google, Inc.
Prashant Gaikwad92fe58f2012-08-06 11:57:43 +05305 * Copyright (c) 2010-2012 NVIDIA CORPORATION. All rights reserved.
Colin Crossd8611962010-01-28 16:40:29 -08006 *
7 * Author:
8 * Colin Cross <ccross@google.com>
9 *
10 * This software is licensed under the terms of the GNU General Public
11 * License version 2, as published by the Free Software Foundation, and
12 * may be copied, distributed, and modified under those terms.
13 *
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
18 *
19 */
20
21#include <linux/kernel.h>
22#include <linux/module.h>
23#include <linux/list.h>
24#include <linux/spinlock.h>
25#include <linux/delay.h>
26#include <linux/io.h>
Jean-Christop PLAGNIOL-VILLARD6d803ba2010-11-17 10:04:33 +010027#include <linux/clkdev.h>
Colin Cross4729fd72011-02-12 16:43:05 -080028#include <linux/clk.h>
Colin Crossd8611962010-01-28 16:40:29 -080029
30#include <mach/iomap.h>
31
32#include "clock.h"
Colin Cross71fc84c2010-06-07 20:49:46 -070033#include "fuse.h"
Colin Cross6d296822010-11-22 18:37:54 -080034#include "tegra2_emc.h"
Joseph Lodab403e2012-08-16 17:31:48 +080035#include "tegra_cpu_car.h"
Colin Crossd8611962010-01-28 16:40:29 -080036
37#define RST_DEVICES 0x004
38#define RST_DEVICES_SET 0x300
39#define RST_DEVICES_CLR 0x304
Colin Cross71fc84c2010-06-07 20:49:46 -070040#define RST_DEVICES_NUM 3
Colin Crossd8611962010-01-28 16:40:29 -080041
42#define CLK_OUT_ENB 0x010
43#define CLK_OUT_ENB_SET 0x320
44#define CLK_OUT_ENB_CLR 0x324
Colin Cross71fc84c2010-06-07 20:49:46 -070045#define CLK_OUT_ENB_NUM 3
46
47#define CLK_MASK_ARM 0x44
48#define MISC_CLK_ENB 0x48
Colin Crossd8611962010-01-28 16:40:29 -080049
50#define OSC_CTRL 0x50
51#define OSC_CTRL_OSC_FREQ_MASK (3<<30)
52#define OSC_CTRL_OSC_FREQ_13MHZ (0<<30)
53#define OSC_CTRL_OSC_FREQ_19_2MHZ (1<<30)
54#define OSC_CTRL_OSC_FREQ_12MHZ (2<<30)
55#define OSC_CTRL_OSC_FREQ_26MHZ (3<<30)
Colin Crosscea62c82010-10-04 11:49:26 -070056#define OSC_CTRL_MASK (0x3f2 | OSC_CTRL_OSC_FREQ_MASK)
Colin Crossd8611962010-01-28 16:40:29 -080057
58#define OSC_FREQ_DET 0x58
59#define OSC_FREQ_DET_TRIG (1<<31)
60
61#define OSC_FREQ_DET_STATUS 0x5C
62#define OSC_FREQ_DET_BUSY (1<<31)
63#define OSC_FREQ_DET_CNT_MASK 0xFFFF
64
Colin Cross71fc84c2010-06-07 20:49:46 -070065#define PERIPH_CLK_SOURCE_I2S1 0x100
66#define PERIPH_CLK_SOURCE_EMC 0x19c
67#define PERIPH_CLK_SOURCE_OSC 0x1fc
68#define PERIPH_CLK_SOURCE_NUM \
69 ((PERIPH_CLK_SOURCE_OSC - PERIPH_CLK_SOURCE_I2S1) / 4)
70
Colin Crossd8611962010-01-28 16:40:29 -080071#define PERIPH_CLK_SOURCE_MASK (3<<30)
72#define PERIPH_CLK_SOURCE_SHIFT 30
Simon Quebb1dccf2011-12-16 20:11:22 +010073#define PERIPH_CLK_SOURCE_PWM_MASK (7<<28)
74#define PERIPH_CLK_SOURCE_PWM_SHIFT 28
Colin Crossd8611962010-01-28 16:40:29 -080075#define PERIPH_CLK_SOURCE_ENABLE (1<<28)
Colin Cross71fc84c2010-06-07 20:49:46 -070076#define PERIPH_CLK_SOURCE_DIVU71_MASK 0xFF
77#define PERIPH_CLK_SOURCE_DIVU16_MASK 0xFFFF
Colin Crossd8611962010-01-28 16:40:29 -080078#define PERIPH_CLK_SOURCE_DIV_SHIFT 0
79
Colin Cross9743b382011-02-12 18:24:32 -080080#define SDMMC_CLK_INT_FB_SEL (1 << 23)
81#define SDMMC_CLK_INT_FB_DLY_SHIFT 16
82#define SDMMC_CLK_INT_FB_DLY_MASK (0xF << SDMMC_CLK_INT_FB_DLY_SHIFT)
83
Colin Crossd8611962010-01-28 16:40:29 -080084#define PLL_BASE 0x0
85#define PLL_BASE_BYPASS (1<<31)
86#define PLL_BASE_ENABLE (1<<30)
87#define PLL_BASE_REF_ENABLE (1<<29)
88#define PLL_BASE_OVERRIDE (1<<28)
Colin Crossd8611962010-01-28 16:40:29 -080089#define PLL_BASE_DIVP_MASK (0x7<<20)
90#define PLL_BASE_DIVP_SHIFT 20
91#define PLL_BASE_DIVN_MASK (0x3FF<<8)
92#define PLL_BASE_DIVN_SHIFT 8
93#define PLL_BASE_DIVM_MASK (0x1F)
94#define PLL_BASE_DIVM_SHIFT 0
95
96#define PLL_OUT_RATIO_MASK (0xFF<<8)
97#define PLL_OUT_RATIO_SHIFT 8
98#define PLL_OUT_OVERRIDE (1<<2)
99#define PLL_OUT_CLKEN (1<<1)
100#define PLL_OUT_RESET_DISABLE (1<<0)
101
Prashant Gaikwad92fe58f2012-08-06 11:57:43 +0530102#define PLL_MISC(c) (((c)->flags & PLL_ALT_MISC_REG) ? 0x4 : 0xc)
Colin Cross71fc84c2010-06-07 20:49:46 -0700103
Colin Crossd8611962010-01-28 16:40:29 -0800104#define PLL_MISC_DCCON_SHIFT 20
Colin Crossd8611962010-01-28 16:40:29 -0800105#define PLL_MISC_CPCON_SHIFT 8
106#define PLL_MISC_CPCON_MASK (0xF<<PLL_MISC_CPCON_SHIFT)
107#define PLL_MISC_LFCON_SHIFT 4
108#define PLL_MISC_LFCON_MASK (0xF<<PLL_MISC_LFCON_SHIFT)
109#define PLL_MISC_VCOCON_SHIFT 0
110#define PLL_MISC_VCOCON_MASK (0xF<<PLL_MISC_VCOCON_SHIFT)
111
Colin Cross71fc84c2010-06-07 20:49:46 -0700112#define PLLU_BASE_POST_DIV (1<<20)
113
Colin Crossd8611962010-01-28 16:40:29 -0800114#define PLLD_MISC_CLKENABLE (1<<30)
115#define PLLD_MISC_DIV_RST (1<<23)
116#define PLLD_MISC_DCCON_SHIFT 12
117
Mike Rapoport8d685bc2010-09-27 11:26:32 +0200118#define PLLE_MISC_READY (1 << 15)
119
Colin Crossf1519612011-02-12 16:05:31 -0800120#define PERIPH_CLK_TO_ENB_REG(c) ((c->u.periph.clk_num / 32) * 4)
121#define PERIPH_CLK_TO_ENB_SET_REG(c) ((c->u.periph.clk_num / 32) * 8)
122#define PERIPH_CLK_TO_ENB_BIT(c) (1 << (c->u.periph.clk_num % 32))
Colin Crossd8611962010-01-28 16:40:29 -0800123
124#define SUPER_CLK_MUX 0x00
125#define SUPER_STATE_SHIFT 28
126#define SUPER_STATE_MASK (0xF << SUPER_STATE_SHIFT)
127#define SUPER_STATE_STANDBY (0x0 << SUPER_STATE_SHIFT)
128#define SUPER_STATE_IDLE (0x1 << SUPER_STATE_SHIFT)
129#define SUPER_STATE_RUN (0x2 << SUPER_STATE_SHIFT)
130#define SUPER_STATE_IRQ (0x3 << SUPER_STATE_SHIFT)
131#define SUPER_STATE_FIQ (0x4 << SUPER_STATE_SHIFT)
132#define SUPER_SOURCE_MASK 0xF
133#define SUPER_FIQ_SOURCE_SHIFT 12
134#define SUPER_IRQ_SOURCE_SHIFT 8
135#define SUPER_RUN_SOURCE_SHIFT 4
136#define SUPER_IDLE_SOURCE_SHIFT 0
137
138#define SUPER_CLK_DIVIDER 0x04
139
140#define BUS_CLK_DISABLE (1<<3)
141#define BUS_CLK_DIV_MASK 0x3
142
Colin Crosscea62c82010-10-04 11:49:26 -0700143#define PMC_CTRL 0x0
144 #define PMC_CTRL_BLINK_ENB (1 << 7)
145
146#define PMC_DPD_PADS_ORIDE 0x1c
147 #define PMC_DPD_PADS_ORIDE_BLINK_ENB (1 << 20)
148
149#define PMC_BLINK_TIMER_DATA_ON_SHIFT 0
150#define PMC_BLINK_TIMER_DATA_ON_MASK 0x7fff
151#define PMC_BLINK_TIMER_ENB (1 << 15)
152#define PMC_BLINK_TIMER_DATA_OFF_SHIFT 16
153#define PMC_BLINK_TIMER_DATA_OFF_MASK 0xffff
154
Joseph Lodab403e2012-08-16 17:31:48 +0800155/* Tegra CPU clock and reset control regs */
156#define TEGRA_CLK_RST_CONTROLLER_CLK_CPU_CMPLX 0x4c
157#define TEGRA_CLK_RST_CONTROLLER_RST_CPU_CMPLX_SET 0x340
158#define TEGRA_CLK_RST_CONTROLLER_RST_CPU_CMPLX_CLR 0x344
159
160#define CPU_CLOCK(cpu) (0x1 << (8 + cpu))
161#define CPU_RESET(cpu) (0x1111ul << (cpu))
162
Colin Crossd8611962010-01-28 16:40:29 -0800163static void __iomem *reg_clk_base = IO_ADDRESS(TEGRA_CLK_RESET_BASE);
Colin Crosscea62c82010-10-04 11:49:26 -0700164static void __iomem *reg_pmc_base = IO_ADDRESS(TEGRA_PMC_BASE);
Colin Crossd8611962010-01-28 16:40:29 -0800165
Colin Cross4729fd72011-02-12 16:43:05 -0800166/*
167 * Some clocks share a register with other clocks. Any clock op that
168 * non-atomically modifies a register used by another clock must lock
169 * clock_register_lock first.
170 */
171static DEFINE_SPINLOCK(clock_register_lock);
172
Colin Cross78f379b2010-10-20 19:19:58 -0700173/*
174 * Some peripheral clocks share an enable bit, so refcount the enable bits
175 * in registers CLK_ENABLE_L, CLK_ENABLE_H, and CLK_ENABLE_U
176 */
177static int tegra_periph_clk_enable_refcount[3 * 32];
178
Colin Crossd8611962010-01-28 16:40:29 -0800179#define clk_writel(value, reg) \
Olof Johanssond3959352011-09-08 17:56:59 -0700180 __raw_writel(value, reg_clk_base + (reg))
Colin Crossd8611962010-01-28 16:40:29 -0800181#define clk_readl(reg) \
Olof Johanssond3959352011-09-08 17:56:59 -0700182 __raw_readl(reg_clk_base + (reg))
Colin Crosscea62c82010-10-04 11:49:26 -0700183#define pmc_writel(value, reg) \
Olof Johanssond3959352011-09-08 17:56:59 -0700184 __raw_writel(value, reg_pmc_base + (reg))
Colin Crosscea62c82010-10-04 11:49:26 -0700185#define pmc_readl(reg) \
Olof Johanssond3959352011-09-08 17:56:59 -0700186 __raw_readl(reg_pmc_base + (reg))
Colin Crossd8611962010-01-28 16:40:29 -0800187
Peter De Schrijver8e4fab22011-12-14 17:03:16 +0200188static unsigned long clk_measure_input_freq(void)
Colin Crossd8611962010-01-28 16:40:29 -0800189{
190 u32 clock_autodetect;
191 clk_writel(OSC_FREQ_DET_TRIG | 1, OSC_FREQ_DET);
192 do {} while (clk_readl(OSC_FREQ_DET_STATUS) & OSC_FREQ_DET_BUSY);
193 clock_autodetect = clk_readl(OSC_FREQ_DET_STATUS);
194 if (clock_autodetect >= 732 - 3 && clock_autodetect <= 732 + 3) {
195 return 12000000;
196 } else if (clock_autodetect >= 794 - 3 && clock_autodetect <= 794 + 3) {
197 return 13000000;
198 } else if (clock_autodetect >= 1172 - 3 && clock_autodetect <= 1172 + 3) {
199 return 19200000;
200 } else if (clock_autodetect >= 1587 - 3 && clock_autodetect <= 1587 + 3) {
201 return 26000000;
202 } else {
Prashant Gaikwad92fe58f2012-08-06 11:57:43 +0530203 pr_err("%s: Unexpected clock autodetect value %d",
204 __func__, clock_autodetect);
Colin Crossd8611962010-01-28 16:40:29 -0800205 BUG();
206 return 0;
207 }
208}
209
Colin Cross71fc84c2010-06-07 20:49:46 -0700210static int clk_div71_get_divider(unsigned long parent_rate, unsigned long rate)
Colin Crossd8611962010-01-28 16:40:29 -0800211{
Colin Cross71fc84c2010-06-07 20:49:46 -0700212 s64 divider_u71 = parent_rate * 2;
213 divider_u71 += rate - 1;
214 do_div(divider_u71, rate);
Colin Crossd8611962010-01-28 16:40:29 -0800215
Colin Cross71fc84c2010-06-07 20:49:46 -0700216 if (divider_u71 - 2 < 0)
217 return 0;
Colin Crossd8611962010-01-28 16:40:29 -0800218
Colin Cross71fc84c2010-06-07 20:49:46 -0700219 if (divider_u71 - 2 > 255)
Colin Crossd8611962010-01-28 16:40:29 -0800220 return -EINVAL;
221
222 return divider_u71 - 2;
223}
224
Colin Cross71fc84c2010-06-07 20:49:46 -0700225static int clk_div16_get_divider(unsigned long parent_rate, unsigned long rate)
Colin Crossd8611962010-01-28 16:40:29 -0800226{
Colin Cross71fc84c2010-06-07 20:49:46 -0700227 s64 divider_u16;
Colin Crossd8611962010-01-28 16:40:29 -0800228
Colin Cross71fc84c2010-06-07 20:49:46 -0700229 divider_u16 = parent_rate;
230 divider_u16 += rate - 1;
231 do_div(divider_u16, rate);
232
233 if (divider_u16 - 1 < 0)
234 return 0;
235
Stephen Warreneb70e1b2012-07-24 15:48:12 -0600236 if (divider_u16 - 1 > 0xFFFF)
Colin Cross71fc84c2010-06-07 20:49:46 -0700237 return -EINVAL;
238
239 return divider_u16 - 1;
Colin Crossd8611962010-01-28 16:40:29 -0800240}
241
Joseph Lob78c0302012-08-17 14:51:21 +0800242static unsigned long tegra_clk_fixed_recalc_rate(struct clk_hw *hw,
243 unsigned long parent_rate)
244{
245 return to_clk_tegra(hw)->fixed_rate;
246}
247
248struct clk_ops tegra_clk_32k_ops = {
249 .recalc_rate = tegra_clk_fixed_recalc_rate,
250};
251
Colin Crossd8611962010-01-28 16:40:29 -0800252/* clk_m functions */
Prashant Gaikwad92fe58f2012-08-06 11:57:43 +0530253static unsigned long tegra20_clk_m_recalc_rate(struct clk_hw *hw,
254 unsigned long prate)
Colin Crossd8611962010-01-28 16:40:29 -0800255{
Prashant Gaikwad92fe58f2012-08-06 11:57:43 +0530256 if (!to_clk_tegra(hw)->fixed_rate)
257 to_clk_tegra(hw)->fixed_rate = clk_measure_input_freq();
258 return to_clk_tegra(hw)->fixed_rate;
259}
Colin Crossd8611962010-01-28 16:40:29 -0800260
Prashant Gaikwad92fe58f2012-08-06 11:57:43 +0530261static void tegra20_clk_m_init(struct clk_hw *hw)
262{
263 struct clk_tegra *c = to_clk_tegra(hw);
264 u32 osc_ctrl = clk_readl(OSC_CTRL);
265 u32 auto_clock_control = osc_ctrl & ~OSC_CTRL_OSC_FREQ_MASK;
266
267 switch (c->fixed_rate) {
Colin Crossd8611962010-01-28 16:40:29 -0800268 case 12000000:
269 auto_clock_control |= OSC_CTRL_OSC_FREQ_12MHZ;
270 break;
271 case 13000000:
272 auto_clock_control |= OSC_CTRL_OSC_FREQ_13MHZ;
273 break;
274 case 19200000:
275 auto_clock_control |= OSC_CTRL_OSC_FREQ_19_2MHZ;
276 break;
277 case 26000000:
278 auto_clock_control |= OSC_CTRL_OSC_FREQ_26MHZ;
279 break;
280 default:
Colin Crossd8611962010-01-28 16:40:29 -0800281 BUG();
282 }
283 clk_writel(auto_clock_control, OSC_CTRL);
Colin Crossd8611962010-01-28 16:40:29 -0800284}
285
Prashant Gaikwad86edb872012-08-06 11:57:40 +0530286struct clk_ops tegra_clk_m_ops = {
Prashant Gaikwad92fe58f2012-08-06 11:57:43 +0530287 .init = tegra20_clk_m_init,
288 .recalc_rate = tegra20_clk_m_recalc_rate,
Colin Crossd8611962010-01-28 16:40:29 -0800289};
290
291/* super clock functions */
292/* "super clocks" on tegra have two-stage muxes and a clock skipping
293 * super divider. We will ignore the clock skipping divider, since we
294 * can't lower the voltage when using the clock skip, but we can if we
295 * lower the PLL frequency.
296 */
Prashant Gaikwad92fe58f2012-08-06 11:57:43 +0530297static int tegra20_super_clk_is_enabled(struct clk_hw *hw)
Colin Crossd8611962010-01-28 16:40:29 -0800298{
Prashant Gaikwad92fe58f2012-08-06 11:57:43 +0530299 struct clk_tegra *c = to_clk_tegra(hw);
Colin Crossd8611962010-01-28 16:40:29 -0800300 u32 val;
Prashant Gaikwad92fe58f2012-08-06 11:57:43 +0530301
302 val = clk_readl(c->reg + SUPER_CLK_MUX);
303 BUG_ON(((val & SUPER_STATE_MASK) != SUPER_STATE_RUN) &&
304 ((val & SUPER_STATE_MASK) != SUPER_STATE_IDLE));
305 c->state = ON;
306 return c->state;
307}
308
309static int tegra20_super_clk_enable(struct clk_hw *hw)
310{
311 struct clk_tegra *c = to_clk_tegra(hw);
312 clk_writel(0, c->reg + SUPER_CLK_DIVIDER);
313 return 0;
314}
315
316static void tegra20_super_clk_disable(struct clk_hw *hw)
317{
318 pr_debug("%s on clock %s\n", __func__, __clk_get_name(hw->clk));
319
320 /* oops - don't disable the CPU clock! */
321 BUG();
322}
323
324static u8 tegra20_super_clk_get_parent(struct clk_hw *hw)
325{
326 struct clk_tegra *c = to_clk_tegra(hw);
327 int val = clk_readl(c->reg + SUPER_CLK_MUX);
Colin Crossd8611962010-01-28 16:40:29 -0800328 int source;
329 int shift;
Prashant Gaikwad92fe58f2012-08-06 11:57:43 +0530330
Colin Crossd8611962010-01-28 16:40:29 -0800331 BUG_ON(((val & SUPER_STATE_MASK) != SUPER_STATE_RUN) &&
332 ((val & SUPER_STATE_MASK) != SUPER_STATE_IDLE));
333 shift = ((val & SUPER_STATE_MASK) == SUPER_STATE_IDLE) ?
334 SUPER_IDLE_SOURCE_SHIFT : SUPER_RUN_SOURCE_SHIFT;
335 source = (val >> shift) & SUPER_SOURCE_MASK;
Prashant Gaikwad92fe58f2012-08-06 11:57:43 +0530336 return source;
Colin Crossd8611962010-01-28 16:40:29 -0800337}
338
Prashant Gaikwad92fe58f2012-08-06 11:57:43 +0530339static int tegra20_super_clk_set_parent(struct clk_hw *hw, u8 index)
Colin Crossd8611962010-01-28 16:40:29 -0800340{
Prashant Gaikwad92fe58f2012-08-06 11:57:43 +0530341 struct clk_tegra *c = to_clk_tegra(hw);
342 u32 val = clk_readl(c->reg + SUPER_CLK_MUX);
Colin Crossd8611962010-01-28 16:40:29 -0800343 int shift;
Colin Cross71fc84c2010-06-07 20:49:46 -0700344
Colin Crossd8611962010-01-28 16:40:29 -0800345 BUG_ON(((val & SUPER_STATE_MASK) != SUPER_STATE_RUN) &&
346 ((val & SUPER_STATE_MASK) != SUPER_STATE_IDLE));
347 shift = ((val & SUPER_STATE_MASK) == SUPER_STATE_IDLE) ?
348 SUPER_IDLE_SOURCE_SHIFT : SUPER_RUN_SOURCE_SHIFT;
Prashant Gaikwad92fe58f2012-08-06 11:57:43 +0530349 val &= ~(SUPER_SOURCE_MASK << shift);
350 val |= index << shift;
Colin Cross71fc84c2010-06-07 20:49:46 -0700351
Prashant Gaikwad92fe58f2012-08-06 11:57:43 +0530352 clk_writel(val, c->reg);
Colin Cross71fc84c2010-06-07 20:49:46 -0700353
Prashant Gaikwad92fe58f2012-08-06 11:57:43 +0530354 return 0;
Colin Crossd8611962010-01-28 16:40:29 -0800355}
356
Prashant Gaikwad92fe58f2012-08-06 11:57:43 +0530357/* FIX ME: Need to switch parents to change the source PLL rate */
358static unsigned long tegra20_super_clk_recalc_rate(struct clk_hw *hw,
359 unsigned long prate)
Colin Cross9c7dc562011-02-12 21:25:23 -0800360{
Prashant Gaikwad92fe58f2012-08-06 11:57:43 +0530361 return prate;
Colin Cross9c7dc562011-02-12 21:25:23 -0800362}
363
Prashant Gaikwad92fe58f2012-08-06 11:57:43 +0530364static long tegra20_super_clk_round_rate(struct clk_hw *hw, unsigned long rate,
365 unsigned long *prate)
Colin Cross71fc84c2010-06-07 20:49:46 -0700366{
Prashant Gaikwad92fe58f2012-08-06 11:57:43 +0530367 return *prate;
Colin Cross71fc84c2010-06-07 20:49:46 -0700368}
369
Prashant Gaikwad92fe58f2012-08-06 11:57:43 +0530370static int tegra20_super_clk_set_rate(struct clk_hw *hw, unsigned long rate,
371 unsigned long parent_rate)
Colin Cross71fc84c2010-06-07 20:49:46 -0700372{
373 return 0;
374}
375
Prashant Gaikwad92fe58f2012-08-06 11:57:43 +0530376struct clk_ops tegra_super_ops = {
377 .is_enabled = tegra20_super_clk_is_enabled,
378 .enable = tegra20_super_clk_enable,
379 .disable = tegra20_super_clk_disable,
380 .set_parent = tegra20_super_clk_set_parent,
381 .get_parent = tegra20_super_clk_get_parent,
382 .set_rate = tegra20_super_clk_set_rate,
383 .round_rate = tegra20_super_clk_round_rate,
384 .recalc_rate = tegra20_super_clk_recalc_rate,
385};
Colin Cross71fc84c2010-06-07 20:49:46 -0700386
Prashant Gaikwadb4350f42012-09-13 15:04:33 +0530387static unsigned long tegra20_twd_clk_recalc_rate(struct clk_hw *hw,
388 unsigned long parent_rate)
389{
390 struct clk_tegra *c = to_clk_tegra(hw);
391 u64 rate = parent_rate;
392
393 if (c->mul != 0 && c->div != 0) {
394 rate *= c->mul;
395 rate += c->div - 1; /* round up */
396 do_div(rate, c->div);
397 }
398
399 return rate;
400}
401
402struct clk_ops tegra_twd_ops = {
403 .recalc_rate = tegra20_twd_clk_recalc_rate,
404};
405
Prashant Gaikwad92fe58f2012-08-06 11:57:43 +0530406static u8 tegra20_cop_clk_get_parent(struct clk_hw *hw)
407{
408 return 0;
Colin Cross71fc84c2010-06-07 20:49:46 -0700409}
410
Prashant Gaikwad92fe58f2012-08-06 11:57:43 +0530411struct clk_ops tegra_cop_ops = {
412 .get_parent = tegra20_cop_clk_get_parent,
Colin Crossd8611962010-01-28 16:40:29 -0800413};
414
Colin Cross9c7dc562011-02-12 21:25:23 -0800415/* virtual cop clock functions. Used to acquire the fake 'cop' clock to
416 * reset the COP block (i.e. AVP) */
Prashant Gaikwad92fe58f2012-08-06 11:57:43 +0530417void tegra2_cop_clk_reset(struct clk_hw *hw, bool assert)
Colin Cross9c7dc562011-02-12 21:25:23 -0800418{
419 unsigned long reg = assert ? RST_DEVICES_SET : RST_DEVICES_CLR;
420
421 pr_debug("%s %s\n", __func__, assert ? "assert" : "deassert");
422 clk_writel(1 << 1, reg);
423}
424
Colin Crossd8611962010-01-28 16:40:29 -0800425/* bus clock functions */
Prashant Gaikwad92fe58f2012-08-06 11:57:43 +0530426static int tegra20_bus_clk_is_enabled(struct clk_hw *hw)
Colin Crossd8611962010-01-28 16:40:29 -0800427{
Prashant Gaikwad92fe58f2012-08-06 11:57:43 +0530428 struct clk_tegra *c = to_clk_tegra(hw);
Colin Crossd8611962010-01-28 16:40:29 -0800429 u32 val = clk_readl(c->reg);
Prashant Gaikwad92fe58f2012-08-06 11:57:43 +0530430
Colin Crossd8611962010-01-28 16:40:29 -0800431 c->state = ((val >> c->reg_shift) & BUS_CLK_DISABLE) ? OFF : ON;
Prashant Gaikwad92fe58f2012-08-06 11:57:43 +0530432 return c->state;
Colin Crossd8611962010-01-28 16:40:29 -0800433}
434
Prashant Gaikwad92fe58f2012-08-06 11:57:43 +0530435static int tegra20_bus_clk_enable(struct clk_hw *hw)
Colin Crossd8611962010-01-28 16:40:29 -0800436{
Prashant Gaikwad92fe58f2012-08-06 11:57:43 +0530437 struct clk_tegra *c = to_clk_tegra(hw);
Colin Cross4729fd72011-02-12 16:43:05 -0800438 unsigned long flags;
Prashant Gaikwad92fe58f2012-08-06 11:57:43 +0530439 u32 val;
Colin Cross4729fd72011-02-12 16:43:05 -0800440
441 spin_lock_irqsave(&clock_register_lock, flags);
442
443 val = clk_readl(c->reg);
Colin Crossd8611962010-01-28 16:40:29 -0800444 val &= ~(BUS_CLK_DISABLE << c->reg_shift);
445 clk_writel(val, c->reg);
Colin Cross4729fd72011-02-12 16:43:05 -0800446
447 spin_unlock_irqrestore(&clock_register_lock, flags);
448
Colin Crossd8611962010-01-28 16:40:29 -0800449 return 0;
450}
451
Prashant Gaikwad92fe58f2012-08-06 11:57:43 +0530452static void tegra20_bus_clk_disable(struct clk_hw *hw)
Colin Crossd8611962010-01-28 16:40:29 -0800453{
Prashant Gaikwad92fe58f2012-08-06 11:57:43 +0530454 struct clk_tegra *c = to_clk_tegra(hw);
Colin Cross4729fd72011-02-12 16:43:05 -0800455 unsigned long flags;
Prashant Gaikwad92fe58f2012-08-06 11:57:43 +0530456 u32 val;
Colin Cross4729fd72011-02-12 16:43:05 -0800457
458 spin_lock_irqsave(&clock_register_lock, flags);
459
460 val = clk_readl(c->reg);
Colin Crossd8611962010-01-28 16:40:29 -0800461 val |= BUS_CLK_DISABLE << c->reg_shift;
462 clk_writel(val, c->reg);
Colin Cross4729fd72011-02-12 16:43:05 -0800463
464 spin_unlock_irqrestore(&clock_register_lock, flags);
Colin Crossd8611962010-01-28 16:40:29 -0800465}
466
Prashant Gaikwad92fe58f2012-08-06 11:57:43 +0530467static unsigned long tegra20_bus_clk_recalc_rate(struct clk_hw *hw,
468 unsigned long prate)
Colin Crossd8611962010-01-28 16:40:29 -0800469{
Prashant Gaikwad92fe58f2012-08-06 11:57:43 +0530470 struct clk_tegra *c = to_clk_tegra(hw);
471 u32 val = clk_readl(c->reg);
472 u64 rate = prate;
473
474 c->div = ((val >> c->reg_shift) & BUS_CLK_DIV_MASK) + 1;
475 c->mul = 1;
476
477 if (c->mul != 0 && c->div != 0) {
478 rate *= c->mul;
479 rate += c->div - 1; /* round up */
480 do_div(rate, c->div);
481 }
482 return rate;
483}
484
485static int tegra20_bus_clk_set_rate(struct clk_hw *hw, unsigned long rate,
486 unsigned long parent_rate)
487{
488 struct clk_tegra *c = to_clk_tegra(hw);
Colin Cross4729fd72011-02-12 16:43:05 -0800489 int ret = -EINVAL;
Prashant Gaikwad92fe58f2012-08-06 11:57:43 +0530490 unsigned long flags;
491 u32 val;
Colin Crossd8611962010-01-28 16:40:29 -0800492 int i;
Colin Cross4729fd72011-02-12 16:43:05 -0800493
494 spin_lock_irqsave(&clock_register_lock, flags);
495
496 val = clk_readl(c->reg);
Colin Crossd8611962010-01-28 16:40:29 -0800497 for (i = 1; i <= 4; i++) {
498 if (rate == parent_rate / i) {
499 val &= ~(BUS_CLK_DIV_MASK << c->reg_shift);
500 val |= (i - 1) << c->reg_shift;
501 clk_writel(val, c->reg);
502 c->div = i;
503 c->mul = 1;
Colin Cross4729fd72011-02-12 16:43:05 -0800504 ret = 0;
505 break;
Colin Crossd8611962010-01-28 16:40:29 -0800506 }
507 }
Colin Cross4729fd72011-02-12 16:43:05 -0800508
509 spin_unlock_irqrestore(&clock_register_lock, flags);
510
511 return ret;
Colin Crossd8611962010-01-28 16:40:29 -0800512}
513
Prashant Gaikwad92fe58f2012-08-06 11:57:43 +0530514static long tegra20_bus_clk_round_rate(struct clk_hw *hw, unsigned long rate,
515 unsigned long *prate)
516{
517 unsigned long parent_rate = *prate;
518 s64 divider;
519
520 if (rate >= parent_rate)
521 return rate;
522
523 divider = parent_rate;
524 divider += rate - 1;
525 do_div(divider, rate);
526
527 if (divider < 0)
528 return divider;
529
530 if (divider > 4)
531 divider = 4;
532 do_div(parent_rate, divider);
533
534 return parent_rate;
535}
536
Prashant Gaikwad86edb872012-08-06 11:57:40 +0530537struct clk_ops tegra_bus_ops = {
Prashant Gaikwad92fe58f2012-08-06 11:57:43 +0530538 .is_enabled = tegra20_bus_clk_is_enabled,
539 .enable = tegra20_bus_clk_enable,
540 .disable = tegra20_bus_clk_disable,
541 .set_rate = tegra20_bus_clk_set_rate,
542 .round_rate = tegra20_bus_clk_round_rate,
543 .recalc_rate = tegra20_bus_clk_recalc_rate,
Colin Crossd8611962010-01-28 16:40:29 -0800544};
545
Colin Crosscea62c82010-10-04 11:49:26 -0700546/* Blink output functions */
Prashant Gaikwad92fe58f2012-08-06 11:57:43 +0530547static int tegra20_blink_clk_is_enabled(struct clk_hw *hw)
Colin Crosscea62c82010-10-04 11:49:26 -0700548{
Prashant Gaikwad92fe58f2012-08-06 11:57:43 +0530549 struct clk_tegra *c = to_clk_tegra(hw);
Colin Crosscea62c82010-10-04 11:49:26 -0700550 u32 val;
551
552 val = pmc_readl(PMC_CTRL);
553 c->state = (val & PMC_CTRL_BLINK_ENB) ? ON : OFF;
Prashant Gaikwad92fe58f2012-08-06 11:57:43 +0530554 return c->state;
555}
556
557static unsigned long tegra20_blink_clk_recalc_rate(struct clk_hw *hw,
558 unsigned long prate)
559{
560 struct clk_tegra *c = to_clk_tegra(hw);
561 u64 rate = prate;
562 u32 val;
563
Colin Crosscea62c82010-10-04 11:49:26 -0700564 c->mul = 1;
565 val = pmc_readl(c->reg);
566
567 if (val & PMC_BLINK_TIMER_ENB) {
568 unsigned int on_off;
569
570 on_off = (val >> PMC_BLINK_TIMER_DATA_ON_SHIFT) &
571 PMC_BLINK_TIMER_DATA_ON_MASK;
572 val >>= PMC_BLINK_TIMER_DATA_OFF_SHIFT;
573 val &= PMC_BLINK_TIMER_DATA_OFF_MASK;
574 on_off += val;
575 /* each tick in the blink timer is 4 32KHz clocks */
576 c->div = on_off * 4;
577 } else {
578 c->div = 1;
579 }
Prashant Gaikwad92fe58f2012-08-06 11:57:43 +0530580
581 if (c->mul != 0 && c->div != 0) {
582 rate *= c->mul;
583 rate += c->div - 1; /* round up */
584 do_div(rate, c->div);
585 }
586 return rate;
Colin Crosscea62c82010-10-04 11:49:26 -0700587}
588
Prashant Gaikwad92fe58f2012-08-06 11:57:43 +0530589static int tegra20_blink_clk_enable(struct clk_hw *hw)
Colin Crosscea62c82010-10-04 11:49:26 -0700590{
591 u32 val;
592
593 val = pmc_readl(PMC_DPD_PADS_ORIDE);
594 pmc_writel(val | PMC_DPD_PADS_ORIDE_BLINK_ENB, PMC_DPD_PADS_ORIDE);
595
596 val = pmc_readl(PMC_CTRL);
597 pmc_writel(val | PMC_CTRL_BLINK_ENB, PMC_CTRL);
598
599 return 0;
600}
601
Prashant Gaikwad92fe58f2012-08-06 11:57:43 +0530602static void tegra20_blink_clk_disable(struct clk_hw *hw)
Colin Crosscea62c82010-10-04 11:49:26 -0700603{
604 u32 val;
605
606 val = pmc_readl(PMC_CTRL);
607 pmc_writel(val & ~PMC_CTRL_BLINK_ENB, PMC_CTRL);
608
609 val = pmc_readl(PMC_DPD_PADS_ORIDE);
610 pmc_writel(val & ~PMC_DPD_PADS_ORIDE_BLINK_ENB, PMC_DPD_PADS_ORIDE);
611}
612
Prashant Gaikwad92fe58f2012-08-06 11:57:43 +0530613static int tegra20_blink_clk_set_rate(struct clk_hw *hw, unsigned long rate,
614 unsigned long parent_rate)
Colin Crosscea62c82010-10-04 11:49:26 -0700615{
Prashant Gaikwad92fe58f2012-08-06 11:57:43 +0530616 struct clk_tegra *c = to_clk_tegra(hw);
617
Colin Cross4729fd72011-02-12 16:43:05 -0800618 if (rate >= parent_rate) {
Colin Crosscea62c82010-10-04 11:49:26 -0700619 c->div = 1;
620 pmc_writel(0, c->reg);
621 } else {
622 unsigned int on_off;
623 u32 val;
624
Colin Cross4729fd72011-02-12 16:43:05 -0800625 on_off = DIV_ROUND_UP(parent_rate / 8, rate);
Colin Crosscea62c82010-10-04 11:49:26 -0700626 c->div = on_off * 8;
627
628 val = (on_off & PMC_BLINK_TIMER_DATA_ON_MASK) <<
629 PMC_BLINK_TIMER_DATA_ON_SHIFT;
630 on_off &= PMC_BLINK_TIMER_DATA_OFF_MASK;
631 on_off <<= PMC_BLINK_TIMER_DATA_OFF_SHIFT;
632 val |= on_off;
633 val |= PMC_BLINK_TIMER_ENB;
634 pmc_writel(val, c->reg);
635 }
636
637 return 0;
638}
639
Prashant Gaikwad92fe58f2012-08-06 11:57:43 +0530640static long tegra20_blink_clk_round_rate(struct clk_hw *hw, unsigned long rate,
641 unsigned long *prate)
642{
643 int div;
644 int mul;
645 long round_rate = *prate;
646
647 mul = 1;
648
649 if (rate >= *prate) {
650 div = 1;
651 } else {
652 div = DIV_ROUND_UP(*prate / 8, rate);
653 div *= 8;
654 }
655
656 round_rate *= mul;
657 round_rate += div - 1;
658 do_div(round_rate, div);
659
660 return round_rate;
661}
662
Prashant Gaikwad86edb872012-08-06 11:57:40 +0530663struct clk_ops tegra_blink_clk_ops = {
Prashant Gaikwad92fe58f2012-08-06 11:57:43 +0530664 .is_enabled = tegra20_blink_clk_is_enabled,
665 .enable = tegra20_blink_clk_enable,
666 .disable = tegra20_blink_clk_disable,
667 .set_rate = tegra20_blink_clk_set_rate,
668 .round_rate = tegra20_blink_clk_round_rate,
669 .recalc_rate = tegra20_blink_clk_recalc_rate,
Colin Crosscea62c82010-10-04 11:49:26 -0700670};
671
Colin Crossd8611962010-01-28 16:40:29 -0800672/* PLL Functions */
Prashant Gaikwad92fe58f2012-08-06 11:57:43 +0530673static int tegra20_pll_clk_wait_for_lock(struct clk_tegra *c)
Colin Crossd8611962010-01-28 16:40:29 -0800674{
Colin Crossf1519612011-02-12 16:05:31 -0800675 udelay(c->u.pll.lock_delay);
Colin Crossd8611962010-01-28 16:40:29 -0800676 return 0;
677}
678
Prashant Gaikwad92fe58f2012-08-06 11:57:43 +0530679static int tegra20_pll_clk_is_enabled(struct clk_hw *hw)
Colin Crossd8611962010-01-28 16:40:29 -0800680{
Prashant Gaikwad92fe58f2012-08-06 11:57:43 +0530681 struct clk_tegra *c = to_clk_tegra(hw);
Colin Crossd8611962010-01-28 16:40:29 -0800682 u32 val = clk_readl(c->reg + PLL_BASE);
683
684 c->state = (val & PLL_BASE_ENABLE) ? ON : OFF;
Prashant Gaikwad92fe58f2012-08-06 11:57:43 +0530685 return c->state;
686}
687
688static unsigned long tegra20_pll_clk_recalc_rate(struct clk_hw *hw,
689 unsigned long prate)
690{
691 struct clk_tegra *c = to_clk_tegra(hw);
692 u32 val = clk_readl(c->reg + PLL_BASE);
693 u64 rate = prate;
Colin Crossd8611962010-01-28 16:40:29 -0800694
695 if (c->flags & PLL_FIXED && !(val & PLL_BASE_OVERRIDE)) {
Prashant Gaikwad92fe58f2012-08-06 11:57:43 +0530696 const struct clk_pll_freq_table *sel;
697 for (sel = c->u.pll.freq_table; sel->input_rate != 0; sel++) {
698 if (sel->input_rate == prate &&
699 sel->output_rate == c->u.pll.fixed_rate) {
700 c->mul = sel->n;
701 c->div = sel->m * sel->p;
702 break;
703 }
704 }
705 pr_err("Clock %s has unknown fixed frequency\n",
706 __clk_get_name(hw->clk));
707 BUG();
Colin Crossd8611962010-01-28 16:40:29 -0800708 } else if (val & PLL_BASE_BYPASS) {
Colin Cross71fc84c2010-06-07 20:49:46 -0700709 c->mul = 1;
710 c->div = 1;
Colin Crossd8611962010-01-28 16:40:29 -0800711 } else {
Colin Cross71fc84c2010-06-07 20:49:46 -0700712 c->mul = (val & PLL_BASE_DIVN_MASK) >> PLL_BASE_DIVN_SHIFT;
713 c->div = (val & PLL_BASE_DIVM_MASK) >> PLL_BASE_DIVM_SHIFT;
714 if (c->flags & PLLU)
715 c->div *= (val & PLLU_BASE_POST_DIV) ? 1 : 2;
716 else
717 c->div *= (val & PLL_BASE_DIVP_MASK) ? 2 : 1;
Colin Crossd8611962010-01-28 16:40:29 -0800718 }
Prashant Gaikwad92fe58f2012-08-06 11:57:43 +0530719
720 if (c->mul != 0 && c->div != 0) {
721 rate *= c->mul;
722 rate += c->div - 1; /* round up */
723 do_div(rate, c->div);
724 }
725 return rate;
Colin Crossd8611962010-01-28 16:40:29 -0800726}
727
Prashant Gaikwad92fe58f2012-08-06 11:57:43 +0530728static int tegra20_pll_clk_enable(struct clk_hw *hw)
Colin Crossd8611962010-01-28 16:40:29 -0800729{
Prashant Gaikwad92fe58f2012-08-06 11:57:43 +0530730 struct clk_tegra *c = to_clk_tegra(hw);
Colin Crossd8611962010-01-28 16:40:29 -0800731 u32 val;
Prashant Gaikwad92fe58f2012-08-06 11:57:43 +0530732 pr_debug("%s on clock %s\n", __func__, __clk_get_name(hw->clk));
Colin Crossd8611962010-01-28 16:40:29 -0800733
734 val = clk_readl(c->reg + PLL_BASE);
735 val &= ~PLL_BASE_BYPASS;
736 val |= PLL_BASE_ENABLE;
737 clk_writel(val, c->reg + PLL_BASE);
738
Prashant Gaikwad92fe58f2012-08-06 11:57:43 +0530739 tegra20_pll_clk_wait_for_lock(c);
Colin Crossd8611962010-01-28 16:40:29 -0800740
741 return 0;
742}
743
Prashant Gaikwad92fe58f2012-08-06 11:57:43 +0530744static void tegra20_pll_clk_disable(struct clk_hw *hw)
Colin Crossd8611962010-01-28 16:40:29 -0800745{
Prashant Gaikwad92fe58f2012-08-06 11:57:43 +0530746 struct clk_tegra *c = to_clk_tegra(hw);
Colin Crossd8611962010-01-28 16:40:29 -0800747 u32 val;
Prashant Gaikwad92fe58f2012-08-06 11:57:43 +0530748 pr_debug("%s on clock %s\n", __func__, __clk_get_name(hw->clk));
Colin Crossd8611962010-01-28 16:40:29 -0800749
750 val = clk_readl(c->reg);
751 val &= ~(PLL_BASE_BYPASS | PLL_BASE_ENABLE);
752 clk_writel(val, c->reg);
753}
754
Prashant Gaikwad92fe58f2012-08-06 11:57:43 +0530755static int tegra20_pll_clk_set_rate(struct clk_hw *hw, unsigned long rate,
756 unsigned long parent_rate)
Colin Crossd8611962010-01-28 16:40:29 -0800757{
Prashant Gaikwad92fe58f2012-08-06 11:57:43 +0530758 struct clk_tegra *c = to_clk_tegra(hw);
759 unsigned long input_rate = parent_rate;
Colin Crossf1519612011-02-12 16:05:31 -0800760 const struct clk_pll_freq_table *sel;
Prashant Gaikwad92fe58f2012-08-06 11:57:43 +0530761 u32 val;
Colin Crossd8611962010-01-28 16:40:29 -0800762
Prashant Gaikwad92fe58f2012-08-06 11:57:43 +0530763 pr_debug("%s: %s %lu\n", __func__, __clk_get_name(hw->clk), rate);
Colin Crossd8611962010-01-28 16:40:29 -0800764
Prashant Gaikwad92fe58f2012-08-06 11:57:43 +0530765 if (c->flags & PLL_FIXED) {
766 int ret = 0;
767 if (rate != c->u.pll.fixed_rate) {
768 pr_err("%s: Can not change %s fixed rate %lu to %lu\n",
769 __func__, __clk_get_name(hw->clk),
770 c->u.pll.fixed_rate, rate);
771 ret = -EINVAL;
772 }
773 return ret;
774 }
775
Colin Crossf1519612011-02-12 16:05:31 -0800776 for (sel = c->u.pll.freq_table; sel->input_rate != 0; sel++) {
Colin Crossd8611962010-01-28 16:40:29 -0800777 if (sel->input_rate == input_rate && sel->output_rate == rate) {
Colin Cross71fc84c2010-06-07 20:49:46 -0700778 c->mul = sel->n;
779 c->div = sel->m * sel->p;
Colin Crossd8611962010-01-28 16:40:29 -0800780
781 val = clk_readl(c->reg + PLL_BASE);
782 if (c->flags & PLL_FIXED)
783 val |= PLL_BASE_OVERRIDE;
784 val &= ~(PLL_BASE_DIVP_MASK | PLL_BASE_DIVN_MASK |
785 PLL_BASE_DIVM_MASK);
Colin Cross71fc84c2010-06-07 20:49:46 -0700786 val |= (sel->m << PLL_BASE_DIVM_SHIFT) |
787 (sel->n << PLL_BASE_DIVN_SHIFT);
788 BUG_ON(sel->p < 1 || sel->p > 2);
789 if (c->flags & PLLU) {
790 if (sel->p == 1)
791 val |= PLLU_BASE_POST_DIV;
792 } else {
793 if (sel->p == 2)
794 val |= 1 << PLL_BASE_DIVP_SHIFT;
795 }
Colin Crossd8611962010-01-28 16:40:29 -0800796 clk_writel(val, c->reg + PLL_BASE);
797
798 if (c->flags & PLL_HAS_CPCON) {
Colin Cross71fc84c2010-06-07 20:49:46 -0700799 val = clk_readl(c->reg + PLL_MISC(c));
800 val &= ~PLL_MISC_CPCON_MASK;
801 val |= sel->cpcon << PLL_MISC_CPCON_SHIFT;
Colin Crossd8611962010-01-28 16:40:29 -0800802 clk_writel(val, c->reg + PLL_MISC(c));
803 }
804
805 if (c->state == ON)
Prashant Gaikwad92fe58f2012-08-06 11:57:43 +0530806 tegra20_pll_clk_enable(hw);
Colin Crossd8611962010-01-28 16:40:29 -0800807 return 0;
808 }
809 }
810 return -EINVAL;
811}
812
Prashant Gaikwad92fe58f2012-08-06 11:57:43 +0530813static long tegra20_pll_clk_round_rate(struct clk_hw *hw, unsigned long rate,
814 unsigned long *prate)
815{
816 struct clk_tegra *c = to_clk_tegra(hw);
817 const struct clk_pll_freq_table *sel;
818 unsigned long input_rate = *prate;
Stephen Warren7a74a442012-09-10 17:02:45 -0600819 u64 output_rate = *prate;
Prashant Gaikwad92fe58f2012-08-06 11:57:43 +0530820 int mul;
821 int div;
822
823 if (c->flags & PLL_FIXED)
824 return c->u.pll.fixed_rate;
825
826 for (sel = c->u.pll.freq_table; sel->input_rate != 0; sel++)
827 if (sel->input_rate == input_rate && sel->output_rate == rate) {
828 mul = sel->n;
829 div = sel->m * sel->p;
830 break;
831 }
832
833 if (sel->input_rate == 0)
834 return -EINVAL;
835
836 output_rate *= mul;
837 output_rate += div - 1; /* round up */
838 do_div(output_rate, div);
839
840 return output_rate;
841}
842
Prashant Gaikwad86edb872012-08-06 11:57:40 +0530843struct clk_ops tegra_pll_ops = {
Prashant Gaikwad92fe58f2012-08-06 11:57:43 +0530844 .is_enabled = tegra20_pll_clk_is_enabled,
845 .enable = tegra20_pll_clk_enable,
846 .disable = tegra20_pll_clk_disable,
847 .set_rate = tegra20_pll_clk_set_rate,
848 .recalc_rate = tegra20_pll_clk_recalc_rate,
849 .round_rate = tegra20_pll_clk_round_rate,
Colin Cross71fc84c2010-06-07 20:49:46 -0700850};
851
Prashant Gaikwad92fe58f2012-08-06 11:57:43 +0530852static void tegra20_pllx_clk_init(struct clk_hw *hw)
Colin Cross71fc84c2010-06-07 20:49:46 -0700853{
Prashant Gaikwad92fe58f2012-08-06 11:57:43 +0530854 struct clk_tegra *c = to_clk_tegra(hw);
Colin Cross71fc84c2010-06-07 20:49:46 -0700855
Olof Johansson9a1086d2011-10-13 00:31:20 -0700856 if (tegra_sku_id == 7)
Colin Cross71fc84c2010-06-07 20:49:46 -0700857 c->max_rate = 750000000;
858}
859
Prashant Gaikwad86edb872012-08-06 11:57:40 +0530860struct clk_ops tegra_pllx_ops = {
Prashant Gaikwad92fe58f2012-08-06 11:57:43 +0530861 .init = tegra20_pllx_clk_init,
862 .is_enabled = tegra20_pll_clk_is_enabled,
863 .enable = tegra20_pll_clk_enable,
864 .disable = tegra20_pll_clk_disable,
865 .set_rate = tegra20_pll_clk_set_rate,
866 .recalc_rate = tegra20_pll_clk_recalc_rate,
867 .round_rate = tegra20_pll_clk_round_rate,
Colin Crossd8611962010-01-28 16:40:29 -0800868};
869
Prashant Gaikwad92fe58f2012-08-06 11:57:43 +0530870static int tegra20_plle_clk_enable(struct clk_hw *hw)
Mike Rapoport8d685bc2010-09-27 11:26:32 +0200871{
Prashant Gaikwad92fe58f2012-08-06 11:57:43 +0530872 struct clk_tegra *c = to_clk_tegra(hw);
Mike Rapoport8d685bc2010-09-27 11:26:32 +0200873 u32 val;
874
Prashant Gaikwad92fe58f2012-08-06 11:57:43 +0530875 pr_debug("%s on clock %s\n", __func__, __clk_get_name(hw->clk));
Mike Rapoport8d685bc2010-09-27 11:26:32 +0200876
877 mdelay(1);
878
879 val = clk_readl(c->reg + PLL_BASE);
880 if (!(val & PLLE_MISC_READY))
881 return -EBUSY;
882
883 val = clk_readl(c->reg + PLL_BASE);
884 val |= PLL_BASE_ENABLE | PLL_BASE_BYPASS;
885 clk_writel(val, c->reg + PLL_BASE);
886
887 return 0;
888}
889
Prashant Gaikwad86edb872012-08-06 11:57:40 +0530890struct clk_ops tegra_plle_ops = {
Prashant Gaikwad92fe58f2012-08-06 11:57:43 +0530891 .is_enabled = tegra20_pll_clk_is_enabled,
892 .enable = tegra20_plle_clk_enable,
893 .set_rate = tegra20_pll_clk_set_rate,
894 .recalc_rate = tegra20_pll_clk_recalc_rate,
895 .round_rate = tegra20_pll_clk_round_rate,
Mike Rapoport8d685bc2010-09-27 11:26:32 +0200896};
897
Colin Crossd8611962010-01-28 16:40:29 -0800898/* Clock divider ops */
Prashant Gaikwad92fe58f2012-08-06 11:57:43 +0530899static int tegra20_pll_div_clk_is_enabled(struct clk_hw *hw)
Colin Crossd8611962010-01-28 16:40:29 -0800900{
Prashant Gaikwad92fe58f2012-08-06 11:57:43 +0530901 struct clk_tegra *c = to_clk_tegra(hw);
Colin Crossd8611962010-01-28 16:40:29 -0800902 u32 val = clk_readl(c->reg);
Prashant Gaikwad92fe58f2012-08-06 11:57:43 +0530903
Colin Crossd8611962010-01-28 16:40:29 -0800904 val >>= c->reg_shift;
905 c->state = (val & PLL_OUT_CLKEN) ? ON : OFF;
906 if (!(val & PLL_OUT_RESET_DISABLE))
907 c->state = OFF;
Prashant Gaikwad92fe58f2012-08-06 11:57:43 +0530908 return c->state;
909}
910
911static unsigned long tegra20_pll_div_clk_recalc_rate(struct clk_hw *hw,
912 unsigned long prate)
913{
914 struct clk_tegra *c = to_clk_tegra(hw);
915 u64 rate = prate;
916 u32 val = clk_readl(c->reg);
917 u32 divu71;
918
919 val >>= c->reg_shift;
Colin Crossd8611962010-01-28 16:40:29 -0800920
921 if (c->flags & DIV_U71) {
922 divu71 = (val & PLL_OUT_RATIO_MASK) >> PLL_OUT_RATIO_SHIFT;
923 c->div = (divu71 + 2);
924 c->mul = 2;
925 } else if (c->flags & DIV_2) {
926 c->div = 2;
927 c->mul = 1;
928 } else {
929 c->div = 1;
930 c->mul = 1;
931 }
Prashant Gaikwad92fe58f2012-08-06 11:57:43 +0530932
933 rate *= c->mul;
934 rate += c->div - 1; /* round up */
935 do_div(rate, c->div);
936
937 return rate;
Colin Crossd8611962010-01-28 16:40:29 -0800938}
939
Prashant Gaikwad92fe58f2012-08-06 11:57:43 +0530940static int tegra20_pll_div_clk_enable(struct clk_hw *hw)
Colin Crossd8611962010-01-28 16:40:29 -0800941{
Prashant Gaikwad92fe58f2012-08-06 11:57:43 +0530942 struct clk_tegra *c = to_clk_tegra(hw);
Colin Cross4729fd72011-02-12 16:43:05 -0800943 unsigned long flags;
Prashant Gaikwad92fe58f2012-08-06 11:57:43 +0530944 u32 new_val;
945 u32 val;
Colin Crossd8611962010-01-28 16:40:29 -0800946
Prashant Gaikwad92fe58f2012-08-06 11:57:43 +0530947 pr_debug("%s: %s\n", __func__, __clk_get_name(hw->clk));
948
Colin Crossd8611962010-01-28 16:40:29 -0800949 if (c->flags & DIV_U71) {
Colin Cross4729fd72011-02-12 16:43:05 -0800950 spin_lock_irqsave(&clock_register_lock, flags);
Colin Crossd8611962010-01-28 16:40:29 -0800951 val = clk_readl(c->reg);
952 new_val = val >> c->reg_shift;
953 new_val &= 0xFFFF;
954
955 new_val |= PLL_OUT_CLKEN | PLL_OUT_RESET_DISABLE;
956
957 val &= ~(0xFFFF << c->reg_shift);
958 val |= new_val << c->reg_shift;
959 clk_writel(val, c->reg);
Colin Cross4729fd72011-02-12 16:43:05 -0800960 spin_unlock_irqrestore(&clock_register_lock, flags);
Colin Crossd8611962010-01-28 16:40:29 -0800961 return 0;
962 } else if (c->flags & DIV_2) {
963 BUG_ON(!(c->flags & PLLD));
Colin Cross4729fd72011-02-12 16:43:05 -0800964 spin_lock_irqsave(&clock_register_lock, flags);
Colin Crossd8611962010-01-28 16:40:29 -0800965 val = clk_readl(c->reg);
966 val &= ~PLLD_MISC_DIV_RST;
967 clk_writel(val, c->reg);
Colin Cross4729fd72011-02-12 16:43:05 -0800968 spin_unlock_irqrestore(&clock_register_lock, flags);
Colin Crossd8611962010-01-28 16:40:29 -0800969 return 0;
970 }
971 return -EINVAL;
972}
973
Prashant Gaikwad92fe58f2012-08-06 11:57:43 +0530974static void tegra20_pll_div_clk_disable(struct clk_hw *hw)
Colin Crossd8611962010-01-28 16:40:29 -0800975{
Prashant Gaikwad92fe58f2012-08-06 11:57:43 +0530976 struct clk_tegra *c = to_clk_tegra(hw);
Colin Cross4729fd72011-02-12 16:43:05 -0800977 unsigned long flags;
Prashant Gaikwad92fe58f2012-08-06 11:57:43 +0530978 u32 new_val;
979 u32 val;
Colin Crossd8611962010-01-28 16:40:29 -0800980
Prashant Gaikwad92fe58f2012-08-06 11:57:43 +0530981 pr_debug("%s: %s\n", __func__, __clk_get_name(hw->clk));
982
Colin Crossd8611962010-01-28 16:40:29 -0800983 if (c->flags & DIV_U71) {
Colin Cross4729fd72011-02-12 16:43:05 -0800984 spin_lock_irqsave(&clock_register_lock, flags);
Colin Crossd8611962010-01-28 16:40:29 -0800985 val = clk_readl(c->reg);
986 new_val = val >> c->reg_shift;
987 new_val &= 0xFFFF;
988
989 new_val &= ~(PLL_OUT_CLKEN | PLL_OUT_RESET_DISABLE);
990
991 val &= ~(0xFFFF << c->reg_shift);
992 val |= new_val << c->reg_shift;
993 clk_writel(val, c->reg);
Colin Cross4729fd72011-02-12 16:43:05 -0800994 spin_unlock_irqrestore(&clock_register_lock, flags);
Colin Crossd8611962010-01-28 16:40:29 -0800995 } else if (c->flags & DIV_2) {
996 BUG_ON(!(c->flags & PLLD));
Colin Cross4729fd72011-02-12 16:43:05 -0800997 spin_lock_irqsave(&clock_register_lock, flags);
Colin Crossd8611962010-01-28 16:40:29 -0800998 val = clk_readl(c->reg);
999 val |= PLLD_MISC_DIV_RST;
1000 clk_writel(val, c->reg);
Colin Cross4729fd72011-02-12 16:43:05 -08001001 spin_unlock_irqrestore(&clock_register_lock, flags);
Colin Crossd8611962010-01-28 16:40:29 -08001002 }
1003}
1004
Prashant Gaikwad92fe58f2012-08-06 11:57:43 +05301005static int tegra20_pll_div_clk_set_rate(struct clk_hw *hw, unsigned long rate,
1006 unsigned long parent_rate)
Colin Crossd8611962010-01-28 16:40:29 -08001007{
Prashant Gaikwad92fe58f2012-08-06 11:57:43 +05301008 struct clk_tegra *c = to_clk_tegra(hw);
Colin Cross4729fd72011-02-12 16:43:05 -08001009 unsigned long flags;
Prashant Gaikwad92fe58f2012-08-06 11:57:43 +05301010 int divider_u71;
1011 u32 new_val;
1012 u32 val;
Colin Cross4729fd72011-02-12 16:43:05 -08001013
Prashant Gaikwad92fe58f2012-08-06 11:57:43 +05301014 pr_debug("%s: %s %lu\n", __func__, __clk_get_name(hw->clk), rate);
1015
Colin Crossd8611962010-01-28 16:40:29 -08001016 if (c->flags & DIV_U71) {
Colin Cross4729fd72011-02-12 16:43:05 -08001017 divider_u71 = clk_div71_get_divider(parent_rate, rate);
Colin Crossd8611962010-01-28 16:40:29 -08001018 if (divider_u71 >= 0) {
Colin Cross4729fd72011-02-12 16:43:05 -08001019 spin_lock_irqsave(&clock_register_lock, flags);
Colin Crossd8611962010-01-28 16:40:29 -08001020 val = clk_readl(c->reg);
1021 new_val = val >> c->reg_shift;
1022 new_val &= 0xFFFF;
1023 if (c->flags & DIV_U71_FIXED)
1024 new_val |= PLL_OUT_OVERRIDE;
1025 new_val &= ~PLL_OUT_RATIO_MASK;
1026 new_val |= divider_u71 << PLL_OUT_RATIO_SHIFT;
1027
1028 val &= ~(0xFFFF << c->reg_shift);
1029 val |= new_val << c->reg_shift;
1030 clk_writel(val, c->reg);
1031 c->div = divider_u71 + 2;
1032 c->mul = 2;
Colin Cross4729fd72011-02-12 16:43:05 -08001033 spin_unlock_irqrestore(&clock_register_lock, flags);
Colin Crossd8611962010-01-28 16:40:29 -08001034 return 0;
1035 }
1036 } else if (c->flags & DIV_2) {
Colin Cross4729fd72011-02-12 16:43:05 -08001037 if (parent_rate == rate * 2)
Colin Crossd8611962010-01-28 16:40:29 -08001038 return 0;
Colin Crossd8611962010-01-28 16:40:29 -08001039 }
1040 return -EINVAL;
1041}
1042
Prashant Gaikwad92fe58f2012-08-06 11:57:43 +05301043static long tegra20_pll_div_clk_round_rate(struct clk_hw *hw, unsigned long rate,
1044 unsigned long *prate)
Colin Cross71fc84c2010-06-07 20:49:46 -07001045{
Prashant Gaikwad92fe58f2012-08-06 11:57:43 +05301046 struct clk_tegra *c = to_clk_tegra(hw);
1047 unsigned long parent_rate = *prate;
Colin Cross71fc84c2010-06-07 20:49:46 -07001048 int divider;
Prashant Gaikwad92fe58f2012-08-06 11:57:43 +05301049
1050 pr_debug("%s: %s %lu\n", __func__, __clk_get_name(hw->clk), rate);
Colin Cross71fc84c2010-06-07 20:49:46 -07001051
1052 if (c->flags & DIV_U71) {
Colin Cross4729fd72011-02-12 16:43:05 -08001053 divider = clk_div71_get_divider(parent_rate, rate);
Colin Cross71fc84c2010-06-07 20:49:46 -07001054 if (divider < 0)
1055 return divider;
Colin Cross421186e2011-02-12 18:21:47 -08001056 return DIV_ROUND_UP(parent_rate * 2, divider + 2);
Colin Cross71fc84c2010-06-07 20:49:46 -07001057 } else if (c->flags & DIV_2) {
Colin Cross421186e2011-02-12 18:21:47 -08001058 return DIV_ROUND_UP(parent_rate, 2);
Colin Cross71fc84c2010-06-07 20:49:46 -07001059 }
1060 return -EINVAL;
1061}
Colin Crossd8611962010-01-28 16:40:29 -08001062
Prashant Gaikwad86edb872012-08-06 11:57:40 +05301063struct clk_ops tegra_pll_div_ops = {
Prashant Gaikwad92fe58f2012-08-06 11:57:43 +05301064 .is_enabled = tegra20_pll_div_clk_is_enabled,
1065 .enable = tegra20_pll_div_clk_enable,
1066 .disable = tegra20_pll_div_clk_disable,
1067 .set_rate = tegra20_pll_div_clk_set_rate,
1068 .round_rate = tegra20_pll_div_clk_round_rate,
1069 .recalc_rate = tegra20_pll_div_clk_recalc_rate,
Colin Crossd8611962010-01-28 16:40:29 -08001070};
1071
1072/* Periph clk ops */
1073
Prashant Gaikwad92fe58f2012-08-06 11:57:43 +05301074static int tegra20_periph_clk_is_enabled(struct clk_hw *hw)
Colin Crossd8611962010-01-28 16:40:29 -08001075{
Prashant Gaikwad92fe58f2012-08-06 11:57:43 +05301076 struct clk_tegra *c = to_clk_tegra(hw);
Colin Crossd8611962010-01-28 16:40:29 -08001077
1078 c->state = ON;
Colin Cross1be3d052011-02-21 16:44:07 -08001079
1080 if (!c->u.periph.clk_num)
Prashant Gaikwad92fe58f2012-08-06 11:57:43 +05301081 goto out;
Colin Cross1be3d052011-02-21 16:44:07 -08001082
Colin Crossd8611962010-01-28 16:40:29 -08001083 if (!(clk_readl(CLK_OUT_ENB + PERIPH_CLK_TO_ENB_REG(c)) &
1084 PERIPH_CLK_TO_ENB_BIT(c)))
1085 c->state = OFF;
Colin Cross1be3d052011-02-21 16:44:07 -08001086
Colin Crossd8611962010-01-28 16:40:29 -08001087 if (!(c->flags & PERIPH_NO_RESET))
1088 if (clk_readl(RST_DEVICES + PERIPH_CLK_TO_ENB_REG(c)) &
1089 PERIPH_CLK_TO_ENB_BIT(c))
1090 c->state = OFF;
Prashant Gaikwad92fe58f2012-08-06 11:57:43 +05301091
1092out:
1093 return c->state;
Colin Crossd8611962010-01-28 16:40:29 -08001094}
1095
Prashant Gaikwad92fe58f2012-08-06 11:57:43 +05301096static int tegra20_periph_clk_enable(struct clk_hw *hw)
Colin Crossd8611962010-01-28 16:40:29 -08001097{
Prashant Gaikwad92fe58f2012-08-06 11:57:43 +05301098 struct clk_tegra *c = to_clk_tegra(hw);
Colin Cross78f379b2010-10-20 19:19:58 -07001099 unsigned long flags;
Prashant Gaikwad92fe58f2012-08-06 11:57:43 +05301100 u32 val;
1101
1102 pr_debug("%s on clock %s\n", __func__, __clk_get_name(hw->clk));
Colin Crossd8611962010-01-28 16:40:29 -08001103
Colin Cross1be3d052011-02-21 16:44:07 -08001104 if (!c->u.periph.clk_num)
1105 return 0;
1106
Prashant Gaikwad92fe58f2012-08-06 11:57:43 +05301107 tegra_periph_clk_enable_refcount[c->u.periph.clk_num]++;
1108 if (tegra_periph_clk_enable_refcount[c->u.periph.clk_num] > 1)
1109 return 0;
1110
Colin Cross78f379b2010-10-20 19:19:58 -07001111 spin_lock_irqsave(&clock_register_lock, flags);
1112
Colin Crossd8611962010-01-28 16:40:29 -08001113 clk_writel(PERIPH_CLK_TO_ENB_BIT(c),
1114 CLK_OUT_ENB_SET + PERIPH_CLK_TO_ENB_SET_REG(c));
1115 if (!(c->flags & PERIPH_NO_RESET) && !(c->flags & PERIPH_MANUAL_RESET))
1116 clk_writel(PERIPH_CLK_TO_ENB_BIT(c),
1117 RST_DEVICES_CLR + PERIPH_CLK_TO_ENB_SET_REG(c));
1118 if (c->flags & PERIPH_EMC_ENB) {
1119 /* The EMC peripheral clock has 2 extra enable bits */
1120 /* FIXME: Do they need to be disabled? */
1121 val = clk_readl(c->reg);
1122 val |= 0x3 << 24;
1123 clk_writel(val, c->reg);
1124 }
Colin Cross78f379b2010-10-20 19:19:58 -07001125
Colin Cross78f379b2010-10-20 19:19:58 -07001126 spin_unlock_irqrestore(&clock_register_lock, flags);
1127
Colin Crossd8611962010-01-28 16:40:29 -08001128 return 0;
1129}
1130
Prashant Gaikwad92fe58f2012-08-06 11:57:43 +05301131static void tegra20_periph_clk_disable(struct clk_hw *hw)
Colin Crossd8611962010-01-28 16:40:29 -08001132{
Prashant Gaikwad92fe58f2012-08-06 11:57:43 +05301133 struct clk_tegra *c = to_clk_tegra(hw);
Colin Cross78f379b2010-10-20 19:19:58 -07001134 unsigned long flags;
1135
Prashant Gaikwad92fe58f2012-08-06 11:57:43 +05301136 pr_debug("%s on clock %s\n", __func__, __clk_get_name(hw->clk));
Colin Crossd8611962010-01-28 16:40:29 -08001137
Colin Cross1be3d052011-02-21 16:44:07 -08001138 if (!c->u.periph.clk_num)
1139 return;
1140
Prashant Gaikwad92fe58f2012-08-06 11:57:43 +05301141 tegra_periph_clk_enable_refcount[c->u.periph.clk_num]--;
1142
1143 if (tegra_periph_clk_enable_refcount[c->u.periph.clk_num] > 0)
1144 return;
1145
Colin Cross78f379b2010-10-20 19:19:58 -07001146 spin_lock_irqsave(&clock_register_lock, flags);
1147
Prashant Gaikwad92fe58f2012-08-06 11:57:43 +05301148 clk_writel(PERIPH_CLK_TO_ENB_BIT(c),
1149 CLK_OUT_ENB_CLR + PERIPH_CLK_TO_ENB_SET_REG(c));
Colin Cross78f379b2010-10-20 19:19:58 -07001150
1151 spin_unlock_irqrestore(&clock_register_lock, flags);
Colin Crossd8611962010-01-28 16:40:29 -08001152}
1153
Prashant Gaikwad92fe58f2012-08-06 11:57:43 +05301154void tegra2_periph_clk_reset(struct clk_hw *hw, bool assert)
Colin Crossd8611962010-01-28 16:40:29 -08001155{
Prashant Gaikwad92fe58f2012-08-06 11:57:43 +05301156 struct clk_tegra *c = to_clk_tegra(hw);
Dima Zavin2b84cb4f2010-09-02 19:11:11 -07001157 unsigned long base = assert ? RST_DEVICES_SET : RST_DEVICES_CLR;
1158
1159 pr_debug("%s %s on clock %s\n", __func__,
Prashant Gaikwad92fe58f2012-08-06 11:57:43 +05301160 assert ? "assert" : "deassert", __clk_get_name(hw->clk));
Colin Cross1be3d052011-02-21 16:44:07 -08001161
1162 BUG_ON(!c->u.periph.clk_num);
1163
Colin Crossd8611962010-01-28 16:40:29 -08001164 if (!(c->flags & PERIPH_NO_RESET))
1165 clk_writel(PERIPH_CLK_TO_ENB_BIT(c),
Dima Zavin2b84cb4f2010-09-02 19:11:11 -07001166 base + PERIPH_CLK_TO_ENB_SET_REG(c));
Colin Crossd8611962010-01-28 16:40:29 -08001167}
1168
Prashant Gaikwad92fe58f2012-08-06 11:57:43 +05301169static int tegra20_periph_clk_set_parent(struct clk_hw *hw, u8 index)
Colin Crossd8611962010-01-28 16:40:29 -08001170{
Prashant Gaikwad92fe58f2012-08-06 11:57:43 +05301171 struct clk_tegra *c = to_clk_tegra(hw);
Colin Crossd8611962010-01-28 16:40:29 -08001172 u32 val;
Prashant Gaikwad92fe58f2012-08-06 11:57:43 +05301173 u32 mask;
1174 u32 shift;
Simon Quebb1dccf2011-12-16 20:11:22 +01001175
Prashant Gaikwad92fe58f2012-08-06 11:57:43 +05301176 pr_debug("%s: %s %d\n", __func__, __clk_get_name(hw->clk), index);
Simon Quebb1dccf2011-12-16 20:11:22 +01001177
1178 if (c->flags & MUX_PWM) {
1179 shift = PERIPH_CLK_SOURCE_PWM_SHIFT;
1180 mask = PERIPH_CLK_SOURCE_PWM_MASK;
1181 } else {
1182 shift = PERIPH_CLK_SOURCE_SHIFT;
1183 mask = PERIPH_CLK_SOURCE_MASK;
1184 }
1185
Prashant Gaikwad92fe58f2012-08-06 11:57:43 +05301186 val = clk_readl(c->reg);
1187 val &= ~mask;
1188 val |= (index) << shift;
Colin Cross71fc84c2010-06-07 20:49:46 -07001189
Prashant Gaikwad92fe58f2012-08-06 11:57:43 +05301190 clk_writel(val, c->reg);
Colin Cross71fc84c2010-06-07 20:49:46 -07001191
Prashant Gaikwad92fe58f2012-08-06 11:57:43 +05301192 return 0;
Colin Crossd8611962010-01-28 16:40:29 -08001193}
1194
Prashant Gaikwad92fe58f2012-08-06 11:57:43 +05301195static u8 tegra20_periph_clk_get_parent(struct clk_hw *hw)
Colin Crossd8611962010-01-28 16:40:29 -08001196{
Prashant Gaikwad92fe58f2012-08-06 11:57:43 +05301197 struct clk_tegra *c = to_clk_tegra(hw);
1198 u32 val = clk_readl(c->reg);
1199 u32 mask;
1200 u32 shift;
1201
1202 if (c->flags & MUX_PWM) {
1203 shift = PERIPH_CLK_SOURCE_PWM_SHIFT;
1204 mask = PERIPH_CLK_SOURCE_PWM_MASK;
1205 } else {
1206 shift = PERIPH_CLK_SOURCE_SHIFT;
1207 mask = PERIPH_CLK_SOURCE_MASK;
1208 }
1209
1210 if (c->flags & MUX)
1211 return (val & mask) >> shift;
1212 else
1213 return 0;
1214}
1215
1216static unsigned long tegra20_periph_clk_recalc_rate(struct clk_hw *hw,
1217 unsigned long prate)
1218{
1219 struct clk_tegra *c = to_clk_tegra(hw);
1220 unsigned long rate = prate;
1221 u32 val = clk_readl(c->reg);
1222
1223 if (c->flags & DIV_U71) {
1224 u32 divu71 = val & PERIPH_CLK_SOURCE_DIVU71_MASK;
1225 c->div = divu71 + 2;
1226 c->mul = 2;
1227 } else if (c->flags & DIV_U16) {
1228 u32 divu16 = val & PERIPH_CLK_SOURCE_DIVU16_MASK;
1229 c->div = divu16 + 1;
1230 c->mul = 1;
1231 } else {
1232 c->div = 1;
1233 c->mul = 1;
1234 return rate;
1235 }
1236
1237 if (c->mul != 0 && c->div != 0) {
1238 rate *= c->mul;
1239 rate += c->div - 1; /* round up */
1240 do_div(rate, c->div);
1241 }
1242
1243 return rate;
1244}
1245
1246static int tegra20_periph_clk_set_rate(struct clk_hw *hw, unsigned long rate,
1247 unsigned long parent_rate)
1248{
1249 struct clk_tegra *c = to_clk_tegra(hw);
Colin Crossd8611962010-01-28 16:40:29 -08001250 u32 val;
Colin Cross71fc84c2010-06-07 20:49:46 -07001251 int divider;
Prashant Gaikwad92fe58f2012-08-06 11:57:43 +05301252
1253 val = clk_readl(c->reg);
Colin Cross4729fd72011-02-12 16:43:05 -08001254
Colin Crossd8611962010-01-28 16:40:29 -08001255 if (c->flags & DIV_U71) {
Colin Cross4729fd72011-02-12 16:43:05 -08001256 divider = clk_div71_get_divider(parent_rate, rate);
Prashant Gaikwad92fe58f2012-08-06 11:57:43 +05301257
Colin Cross71fc84c2010-06-07 20:49:46 -07001258 if (divider >= 0) {
Colin Crossd8611962010-01-28 16:40:29 -08001259 val = clk_readl(c->reg);
Colin Cross71fc84c2010-06-07 20:49:46 -07001260 val &= ~PERIPH_CLK_SOURCE_DIVU71_MASK;
1261 val |= divider;
Colin Crossd8611962010-01-28 16:40:29 -08001262 clk_writel(val, c->reg);
Colin Cross71fc84c2010-06-07 20:49:46 -07001263 c->div = divider + 2;
Colin Crossd8611962010-01-28 16:40:29 -08001264 c->mul = 2;
Colin Crossd8611962010-01-28 16:40:29 -08001265 return 0;
1266 }
Colin Cross71fc84c2010-06-07 20:49:46 -07001267 } else if (c->flags & DIV_U16) {
Colin Cross4729fd72011-02-12 16:43:05 -08001268 divider = clk_div16_get_divider(parent_rate, rate);
Colin Cross71fc84c2010-06-07 20:49:46 -07001269 if (divider >= 0) {
1270 val = clk_readl(c->reg);
1271 val &= ~PERIPH_CLK_SOURCE_DIVU16_MASK;
1272 val |= divider;
1273 clk_writel(val, c->reg);
1274 c->div = divider + 1;
1275 c->mul = 1;
1276 return 0;
1277 }
Colin Cross4729fd72011-02-12 16:43:05 -08001278 } else if (parent_rate <= rate) {
Colin Cross71fc84c2010-06-07 20:49:46 -07001279 c->div = 1;
1280 c->mul = 1;
1281 return 0;
1282 }
Prashant Gaikwad92fe58f2012-08-06 11:57:43 +05301283
Colin Cross71fc84c2010-06-07 20:49:46 -07001284 return -EINVAL;
1285}
1286
Prashant Gaikwad92fe58f2012-08-06 11:57:43 +05301287static long tegra20_periph_clk_round_rate(struct clk_hw *hw,
1288 unsigned long rate, unsigned long *prate)
Colin Cross71fc84c2010-06-07 20:49:46 -07001289{
Prashant Gaikwad92fe58f2012-08-06 11:57:43 +05301290 struct clk_tegra *c = to_clk_tegra(hw);
1291 unsigned long parent_rate = __clk_get_rate(__clk_get_parent(hw->clk));
Colin Cross71fc84c2010-06-07 20:49:46 -07001292 int divider;
Prashant Gaikwad92fe58f2012-08-06 11:57:43 +05301293
1294 pr_debug("%s: %s %lu\n", __func__, __clk_get_name(hw->clk), rate);
1295
1296 if (prate)
1297 parent_rate = *prate;
Colin Cross71fc84c2010-06-07 20:49:46 -07001298
1299 if (c->flags & DIV_U71) {
Colin Cross4729fd72011-02-12 16:43:05 -08001300 divider = clk_div71_get_divider(parent_rate, rate);
Colin Cross71fc84c2010-06-07 20:49:46 -07001301 if (divider < 0)
1302 return divider;
1303
Colin Cross421186e2011-02-12 18:21:47 -08001304 return DIV_ROUND_UP(parent_rate * 2, divider + 2);
Colin Cross71fc84c2010-06-07 20:49:46 -07001305 } else if (c->flags & DIV_U16) {
Colin Cross4729fd72011-02-12 16:43:05 -08001306 divider = clk_div16_get_divider(parent_rate, rate);
Colin Cross71fc84c2010-06-07 20:49:46 -07001307 if (divider < 0)
1308 return divider;
Colin Cross421186e2011-02-12 18:21:47 -08001309 return DIV_ROUND_UP(parent_rate, divider + 1);
Colin Crossd8611962010-01-28 16:40:29 -08001310 }
1311 return -EINVAL;
1312}
1313
Prashant Gaikwad86edb872012-08-06 11:57:40 +05301314struct clk_ops tegra_periph_clk_ops = {
Prashant Gaikwad92fe58f2012-08-06 11:57:43 +05301315 .is_enabled = tegra20_periph_clk_is_enabled,
1316 .enable = tegra20_periph_clk_enable,
1317 .disable = tegra20_periph_clk_disable,
1318 .set_parent = tegra20_periph_clk_set_parent,
1319 .get_parent = tegra20_periph_clk_get_parent,
1320 .set_rate = tegra20_periph_clk_set_rate,
1321 .round_rate = tegra20_periph_clk_round_rate,
1322 .recalc_rate = tegra20_periph_clk_recalc_rate,
Colin Crossd8611962010-01-28 16:40:29 -08001323};
1324
Colin Cross6d296822010-11-22 18:37:54 -08001325/* External memory controller clock ops */
Prashant Gaikwad92fe58f2012-08-06 11:57:43 +05301326static void tegra20_emc_clk_init(struct clk_hw *hw)
Colin Cross6d296822010-11-22 18:37:54 -08001327{
Prashant Gaikwad92fe58f2012-08-06 11:57:43 +05301328 struct clk_tegra *c = to_clk_tegra(hw);
1329 c->max_rate = __clk_get_rate(hw->clk);
Colin Cross6d296822010-11-22 18:37:54 -08001330}
1331
Prashant Gaikwad92fe58f2012-08-06 11:57:43 +05301332static long tegra20_emc_clk_round_rate(struct clk_hw *hw, unsigned long rate,
1333 unsigned long *prate)
Colin Cross6d296822010-11-22 18:37:54 -08001334{
Prashant Gaikwad92fe58f2012-08-06 11:57:43 +05301335 struct clk_tegra *c = to_clk_tegra(hw);
Stephen Warrene186ad72012-02-06 17:09:15 -08001336 long emc_rate;
1337 long clk_rate;
Colin Cross6d296822010-11-22 18:37:54 -08001338
Stephen Warrene186ad72012-02-06 17:09:15 -08001339 /*
1340 * The slowest entry in the EMC clock table that is at least as
1341 * fast as rate.
1342 */
1343 emc_rate = tegra_emc_round_rate(rate);
1344 if (emc_rate < 0)
Colin Cross6d296822010-11-22 18:37:54 -08001345 return c->max_rate;
1346
Stephen Warrene186ad72012-02-06 17:09:15 -08001347 /*
1348 * The fastest rate the PLL will generate that is at most the
1349 * requested rate.
1350 */
Prashant Gaikwad92fe58f2012-08-06 11:57:43 +05301351 clk_rate = tegra20_periph_clk_round_rate(hw, emc_rate, NULL);
Colin Cross6d296822010-11-22 18:37:54 -08001352
Stephen Warrene186ad72012-02-06 17:09:15 -08001353 /*
1354 * If this fails, and emc_rate > clk_rate, it's because the maximum
1355 * rate in the EMC tables is larger than the maximum rate of the EMC
1356 * clock. The EMC clock's max rate is the rate it was running when the
1357 * kernel booted. Such a mismatch is probably due to using the wrong
1358 * BCT, i.e. using a Tegra20 BCT with an EMC table written for Tegra25.
1359 */
1360 WARN_ONCE(emc_rate != clk_rate,
1361 "emc_rate %ld != clk_rate %ld",
1362 emc_rate, clk_rate);
1363
1364 return emc_rate;
Colin Cross6d296822010-11-22 18:37:54 -08001365}
1366
Prashant Gaikwad92fe58f2012-08-06 11:57:43 +05301367static int tegra20_emc_clk_set_rate(struct clk_hw *hw, unsigned long rate,
1368 unsigned long parent_rate)
Colin Cross6d296822010-11-22 18:37:54 -08001369{
1370 int ret;
Prashant Gaikwad92fe58f2012-08-06 11:57:43 +05301371
Colin Cross6d296822010-11-22 18:37:54 -08001372 /*
1373 * The Tegra2 memory controller has an interlock with the clock
1374 * block that allows memory shadowed registers to be updated,
1375 * and then transfer them to the main registers at the same
1376 * time as the clock update without glitches.
1377 */
1378 ret = tegra_emc_set_rate(rate);
1379 if (ret < 0)
1380 return ret;
1381
Prashant Gaikwad92fe58f2012-08-06 11:57:43 +05301382 ret = tegra20_periph_clk_set_rate(hw, rate, parent_rate);
Colin Cross6d296822010-11-22 18:37:54 -08001383 udelay(1);
1384
1385 return ret;
1386}
1387
Prashant Gaikwad86edb872012-08-06 11:57:40 +05301388struct clk_ops tegra_emc_clk_ops = {
Prashant Gaikwad92fe58f2012-08-06 11:57:43 +05301389 .init = tegra20_emc_clk_init,
1390 .is_enabled = tegra20_periph_clk_is_enabled,
1391 .enable = tegra20_periph_clk_enable,
1392 .disable = tegra20_periph_clk_disable,
1393 .set_parent = tegra20_periph_clk_set_parent,
1394 .get_parent = tegra20_periph_clk_get_parent,
1395 .set_rate = tegra20_emc_clk_set_rate,
1396 .round_rate = tegra20_emc_clk_round_rate,
1397 .recalc_rate = tegra20_periph_clk_recalc_rate,
Colin Cross6d296822010-11-22 18:37:54 -08001398};
1399
Colin Crossd8611962010-01-28 16:40:29 -08001400/* Clock doubler ops */
Prashant Gaikwad92fe58f2012-08-06 11:57:43 +05301401static int tegra20_clk_double_is_enabled(struct clk_hw *hw)
Colin Crossd8611962010-01-28 16:40:29 -08001402{
Prashant Gaikwad92fe58f2012-08-06 11:57:43 +05301403 struct clk_tegra *c = to_clk_tegra(hw);
1404
Colin Crossd8611962010-01-28 16:40:29 -08001405 c->state = ON;
Colin Cross1be3d052011-02-21 16:44:07 -08001406
1407 if (!c->u.periph.clk_num)
Prashant Gaikwad92fe58f2012-08-06 11:57:43 +05301408 goto out;
Colin Cross1be3d052011-02-21 16:44:07 -08001409
Colin Crossd8611962010-01-28 16:40:29 -08001410 if (!(clk_readl(CLK_OUT_ENB + PERIPH_CLK_TO_ENB_REG(c)) &
1411 PERIPH_CLK_TO_ENB_BIT(c)))
1412 c->state = OFF;
Prashant Gaikwad92fe58f2012-08-06 11:57:43 +05301413
1414out:
1415 return c->state;
Colin Crossd8611962010-01-28 16:40:29 -08001416};
1417
Prashant Gaikwad92fe58f2012-08-06 11:57:43 +05301418static unsigned long tegra20_clk_double_recalc_rate(struct clk_hw *hw,
1419 unsigned long prate)
Colin Cross71fc84c2010-06-07 20:49:46 -07001420{
Prashant Gaikwad92fe58f2012-08-06 11:57:43 +05301421 struct clk_tegra *c = to_clk_tegra(hw);
1422 u64 rate = prate;
1423
Colin Cross71fc84c2010-06-07 20:49:46 -07001424 c->mul = 2;
1425 c->div = 1;
Prashant Gaikwad92fe58f2012-08-06 11:57:43 +05301426
1427 rate *= c->mul;
1428 rate += c->div - 1; /* round up */
1429 do_div(rate, c->div);
1430
1431 return rate;
1432}
1433
1434static long tegra20_clk_double_round_rate(struct clk_hw *hw, unsigned long rate,
1435 unsigned long *prate)
1436{
1437 unsigned long output_rate = *prate;
1438
1439 do_div(output_rate, 2);
1440 return output_rate;
1441}
1442
1443static int tegra20_clk_double_set_rate(struct clk_hw *hw, unsigned long rate,
1444 unsigned long parent_rate)
1445{
1446 if (rate != 2 * parent_rate)
1447 return -EINVAL;
Colin Cross71fc84c2010-06-07 20:49:46 -07001448 return 0;
1449}
1450
Prashant Gaikwad86edb872012-08-06 11:57:40 +05301451struct clk_ops tegra_clk_double_ops = {
Prashant Gaikwad92fe58f2012-08-06 11:57:43 +05301452 .is_enabled = tegra20_clk_double_is_enabled,
1453 .enable = tegra20_periph_clk_enable,
1454 .disable = tegra20_periph_clk_disable,
1455 .set_rate = tegra20_clk_double_set_rate,
1456 .recalc_rate = tegra20_clk_double_recalc_rate,
1457 .round_rate = tegra20_clk_double_round_rate,
Colin Cross71fc84c2010-06-07 20:49:46 -07001458};
1459
Colin Crosscea62c82010-10-04 11:49:26 -07001460/* Audio sync clock ops */
Prashant Gaikwad92fe58f2012-08-06 11:57:43 +05301461static int tegra20_audio_sync_clk_is_enabled(struct clk_hw *hw)
Colin Cross71fc84c2010-06-07 20:49:46 -07001462{
Prashant Gaikwad92fe58f2012-08-06 11:57:43 +05301463 struct clk_tegra *c = to_clk_tegra(hw);
Colin Cross71fc84c2010-06-07 20:49:46 -07001464 u32 val = clk_readl(c->reg);
Prashant Gaikwad92fe58f2012-08-06 11:57:43 +05301465
Colin Cross71fc84c2010-06-07 20:49:46 -07001466 c->state = (val & (1<<4)) ? OFF : ON;
Prashant Gaikwad92fe58f2012-08-06 11:57:43 +05301467 return c->state;
Colin Cross71fc84c2010-06-07 20:49:46 -07001468}
1469
Prashant Gaikwad92fe58f2012-08-06 11:57:43 +05301470static int tegra20_audio_sync_clk_enable(struct clk_hw *hw)
Colin Cross71fc84c2010-06-07 20:49:46 -07001471{
Prashant Gaikwad92fe58f2012-08-06 11:57:43 +05301472 struct clk_tegra *c = to_clk_tegra(hw);
1473
Colin Cross71fc84c2010-06-07 20:49:46 -07001474 clk_writel(0, c->reg);
1475 return 0;
1476}
1477
Prashant Gaikwad92fe58f2012-08-06 11:57:43 +05301478static void tegra20_audio_sync_clk_disable(struct clk_hw *hw)
Colin Cross71fc84c2010-06-07 20:49:46 -07001479{
Prashant Gaikwad92fe58f2012-08-06 11:57:43 +05301480 struct clk_tegra *c = to_clk_tegra(hw);
Colin Cross71fc84c2010-06-07 20:49:46 -07001481 clk_writel(1, c->reg);
1482}
1483
Prashant Gaikwad92fe58f2012-08-06 11:57:43 +05301484static u8 tegra20_audio_sync_clk_get_parent(struct clk_hw *hw)
Colin Cross71fc84c2010-06-07 20:49:46 -07001485{
Prashant Gaikwad92fe58f2012-08-06 11:57:43 +05301486 struct clk_tegra *c = to_clk_tegra(hw);
1487 u32 val = clk_readl(c->reg);
1488 int source;
1489
1490 source = val & 0xf;
1491 return source;
1492}
1493
1494static int tegra20_audio_sync_clk_set_parent(struct clk_hw *hw, u8 index)
1495{
1496 struct clk_tegra *c = to_clk_tegra(hw);
Colin Cross71fc84c2010-06-07 20:49:46 -07001497 u32 val;
Colin Cross71fc84c2010-06-07 20:49:46 -07001498
Prashant Gaikwad92fe58f2012-08-06 11:57:43 +05301499 val = clk_readl(c->reg);
1500 val &= ~0xf;
1501 val |= index;
Colin Cross71fc84c2010-06-07 20:49:46 -07001502
Prashant Gaikwad92fe58f2012-08-06 11:57:43 +05301503 clk_writel(val, c->reg);
Colin Cross71fc84c2010-06-07 20:49:46 -07001504
Prashant Gaikwad92fe58f2012-08-06 11:57:43 +05301505 return 0;
Colin Cross71fc84c2010-06-07 20:49:46 -07001506}
1507
Prashant Gaikwad86edb872012-08-06 11:57:40 +05301508struct clk_ops tegra_audio_sync_clk_ops = {
Prashant Gaikwad92fe58f2012-08-06 11:57:43 +05301509 .is_enabled = tegra20_audio_sync_clk_is_enabled,
1510 .enable = tegra20_audio_sync_clk_enable,
1511 .disable = tegra20_audio_sync_clk_disable,
1512 .set_parent = tegra20_audio_sync_clk_set_parent,
1513 .get_parent = tegra20_audio_sync_clk_get_parent,
Colin Crossd8611962010-01-28 16:40:29 -08001514};
1515
Colin Crosscea62c82010-10-04 11:49:26 -07001516/* cdev1 and cdev2 (dap_mclk1 and dap_mclk2) ops */
1517
Prashant Gaikwad92fe58f2012-08-06 11:57:43 +05301518static int tegra20_cdev_clk_is_enabled(struct clk_hw *hw)
Colin Crosscea62c82010-10-04 11:49:26 -07001519{
Prashant Gaikwad92fe58f2012-08-06 11:57:43 +05301520 struct clk_tegra *c = to_clk_tegra(hw);
Colin Crosscea62c82010-10-04 11:49:26 -07001521 /* We could un-tristate the cdev1 or cdev2 pingroup here; this is
1522 * currently done in the pinmux code. */
1523 c->state = ON;
Colin Cross1be3d052011-02-21 16:44:07 -08001524
1525 BUG_ON(!c->u.periph.clk_num);
1526
Colin Crosscea62c82010-10-04 11:49:26 -07001527 if (!(clk_readl(CLK_OUT_ENB + PERIPH_CLK_TO_ENB_REG(c)) &
1528 PERIPH_CLK_TO_ENB_BIT(c)))
1529 c->state = OFF;
Prashant Gaikwad92fe58f2012-08-06 11:57:43 +05301530 return c->state;
Colin Crosscea62c82010-10-04 11:49:26 -07001531}
1532
Prashant Gaikwad92fe58f2012-08-06 11:57:43 +05301533static int tegra20_cdev_clk_enable(struct clk_hw *hw)
Colin Crosscea62c82010-10-04 11:49:26 -07001534{
Prashant Gaikwad92fe58f2012-08-06 11:57:43 +05301535 struct clk_tegra *c = to_clk_tegra(hw);
Colin Cross1be3d052011-02-21 16:44:07 -08001536 BUG_ON(!c->u.periph.clk_num);
1537
Colin Crosscea62c82010-10-04 11:49:26 -07001538 clk_writel(PERIPH_CLK_TO_ENB_BIT(c),
1539 CLK_OUT_ENB_SET + PERIPH_CLK_TO_ENB_SET_REG(c));
1540 return 0;
1541}
1542
Prashant Gaikwad92fe58f2012-08-06 11:57:43 +05301543static void tegra20_cdev_clk_disable(struct clk_hw *hw)
Colin Crosscea62c82010-10-04 11:49:26 -07001544{
Prashant Gaikwad92fe58f2012-08-06 11:57:43 +05301545 struct clk_tegra *c = to_clk_tegra(hw);
Colin Cross1be3d052011-02-21 16:44:07 -08001546 BUG_ON(!c->u.periph.clk_num);
1547
Colin Crosscea62c82010-10-04 11:49:26 -07001548 clk_writel(PERIPH_CLK_TO_ENB_BIT(c),
1549 CLK_OUT_ENB_CLR + PERIPH_CLK_TO_ENB_SET_REG(c));
1550}
1551
Prashant Gaikwad92fe58f2012-08-06 11:57:43 +05301552static unsigned long tegra20_cdev_recalc_rate(struct clk_hw *hw,
1553 unsigned long prate)
1554{
1555 return to_clk_tegra(hw)->fixed_rate;
1556}
1557
Prashant Gaikwad86edb872012-08-06 11:57:40 +05301558struct clk_ops tegra_cdev_clk_ops = {
Prashant Gaikwad92fe58f2012-08-06 11:57:43 +05301559 .is_enabled = tegra20_cdev_clk_is_enabled,
1560 .enable = tegra20_cdev_clk_enable,
1561 .disable = tegra20_cdev_clk_disable,
1562 .recalc_rate = tegra20_cdev_recalc_rate,
Colin Cross310992c2011-02-12 16:14:03 -08001563};
Joseph Lodab403e2012-08-16 17:31:48 +08001564
1565/* Tegra20 CPU clock and reset control functions */
1566static void tegra20_wait_cpu_in_reset(u32 cpu)
1567{
1568 unsigned int reg;
1569
1570 do {
1571 reg = readl(reg_clk_base +
1572 TEGRA_CLK_RST_CONTROLLER_RST_CPU_CMPLX_SET);
1573 cpu_relax();
1574 } while (!(reg & (1 << cpu))); /* check CPU been reset or not */
1575
1576 return;
1577}
1578
1579static void tegra20_put_cpu_in_reset(u32 cpu)
1580{
1581 writel(CPU_RESET(cpu),
1582 reg_clk_base + TEGRA_CLK_RST_CONTROLLER_RST_CPU_CMPLX_SET);
1583 dmb();
1584}
1585
1586static void tegra20_cpu_out_of_reset(u32 cpu)
1587{
1588 writel(CPU_RESET(cpu),
1589 reg_clk_base + TEGRA_CLK_RST_CONTROLLER_RST_CPU_CMPLX_CLR);
1590 wmb();
1591}
1592
1593static void tegra20_enable_cpu_clock(u32 cpu)
1594{
1595 unsigned int reg;
1596
1597 reg = readl(reg_clk_base + TEGRA_CLK_RST_CONTROLLER_CLK_CPU_CMPLX);
1598 writel(reg & ~CPU_CLOCK(cpu),
1599 reg_clk_base + TEGRA_CLK_RST_CONTROLLER_CLK_CPU_CMPLX);
1600 barrier();
1601 reg = readl(reg_clk_base + TEGRA_CLK_RST_CONTROLLER_CLK_CPU_CMPLX);
1602}
1603
1604static void tegra20_disable_cpu_clock(u32 cpu)
1605{
1606 unsigned int reg;
1607
1608 reg = readl(reg_clk_base + TEGRA_CLK_RST_CONTROLLER_CLK_CPU_CMPLX);
1609 writel(reg | CPU_CLOCK(cpu),
1610 reg_clk_base + TEGRA_CLK_RST_CONTROLLER_CLK_CPU_CMPLX);
1611}
1612
1613static struct tegra_cpu_car_ops tegra20_cpu_car_ops = {
1614 .wait_for_reset = tegra20_wait_cpu_in_reset,
1615 .put_in_reset = tegra20_put_cpu_in_reset,
1616 .out_of_reset = tegra20_cpu_out_of_reset,
1617 .enable_clock = tegra20_enable_cpu_clock,
1618 .disable_clock = tegra20_disable_cpu_clock,
1619};
1620
1621void __init tegra20_cpu_car_ops_init(void)
1622{
1623 tegra_cpu_car_ops = &tegra20_cpu_car_ops;
1624}