blob: 9f24538bdc6d62cb90cbae9720606dfdaa056525 [file] [log] [blame]
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001/*
2 *
3 * Copyright (C) 2007 Google, Inc.
Duy Truong790f06d2013-02-13 16:38:12 -08004 * Copyright (c) 2007-2012, The Linux Foundation. All rights reserved.
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005 *
6 * This software is licensed under the terms of the GNU General Public
7 * License version 2, as published by the Free Software Foundation, and
8 * may be copied, distributed, and modified under those terms.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 */
16
17#include <linux/version.h>
18#include <linux/kernel.h>
Matt Wagantallbf430eb2012-03-22 11:45:49 -070019#include <linux/module.h>
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070020#include <linux/init.h>
21#include <linux/errno.h>
22#include <linux/string.h>
23#include <linux/delay.h>
24#include <linux/clk.h>
25#include <linux/cpufreq.h>
26#include <linux/mutex.h>
27#include <linux/io.h>
28#include <linux/sort.h>
Matt Wagantallbf430eb2012-03-22 11:45:49 -070029#include <linux/platform_device.h>
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070030#include <mach/board.h>
31#include <mach/msm_iomap.h>
32#include <asm/mach-types.h>
33
34#include "smd_private.h"
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070035#include "acpuclock.h"
36#include "spm.h"
37
Taniya Das298de8c2012-02-16 11:45:31 +053038#define SCSS_CLK_CTL_ADDR (MSM_ACC0_BASE + 0x04)
39#define SCSS_CLK_SEL_ADDR (MSM_ACC0_BASE + 0x08)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070040
41#define PLL2_L_VAL_ADDR (MSM_CLK_CTL_BASE + 0x33C)
42#define PLL2_M_VAL_ADDR (MSM_CLK_CTL_BASE + 0x340)
43#define PLL2_N_VAL_ADDR (MSM_CLK_CTL_BASE + 0x344)
44#define PLL2_CONFIG_ADDR (MSM_CLK_CTL_BASE + 0x34C)
45
46#define VREF_SEL 1 /* 0: 0.625V (50mV step), 1: 0.3125V (25mV step). */
47#define V_STEP (25 * (2 - VREF_SEL)) /* Minimum voltage step size. */
48#define VREG_DATA (VREG_CONFIG | (VREF_SEL << 5))
49#define VREG_CONFIG (BIT(7) | BIT(6)) /* Enable VREG, pull-down if disabled. */
50/* Cause a compile error if the voltage is not a multiple of the step size. */
51#define MV(mv) ((mv) / (!((mv) % V_STEP)))
52/* mv = (750mV + (raw * 25mV)) * (2 - VREF_SEL) */
53#define VDD_RAW(mv) (((MV(mv) / V_STEP) - 30) | VREG_DATA)
54
55#define MAX_AXI_KHZ 192000
56
57struct clock_state {
58 struct clkctl_acpu_speed *current_speed;
59 struct mutex lock;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070060 struct clk *ebi1_clk;
61};
62
63struct pll {
64 unsigned int l;
65 unsigned int m;
66 unsigned int n;
67 unsigned int pre_div;
68};
69
70struct clkctl_acpu_speed {
71 unsigned int use_for_scaling;
72 unsigned int acpu_clk_khz;
73 int src;
74 unsigned int acpu_src_sel;
75 unsigned int acpu_src_div;
76 unsigned int axi_clk_hz;
77 unsigned int vdd_mv;
78 unsigned int vdd_raw;
79 struct pll *pll_rate;
Taniya Dasbb0b6db2012-03-19 14:09:55 +053080 unsigned long lpj; /* loops_per_jiffy */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070081};
82
83static struct clock_state drv_state = { 0 };
84
85/* Switch to this when reprogramming PLL2 */
86static struct clkctl_acpu_speed *backup_s;
87
88static struct pll pll2_tbl[] = {
89 { 42, 0, 1, 0 }, /* 806 MHz */
90 { 53, 1, 3, 0 }, /* 1024 MHz */
91 { 125, 0, 1, 1 }, /* 1200 MHz */
92 { 73, 0, 1, 0 }, /* 1401 MHz */
93};
94
95/* Use negative numbers for sources that can't be enabled/disabled */
96
97enum acpuclk_source {
98 LPXO = -2,
99 AXI = -1,
100 PLL_0 = 0,
101 PLL_1,
102 PLL_2,
103 PLL_3,
104 MAX_SOURCE
105};
106
107static struct clk *acpuclk_sources[MAX_SOURCE];
108
109/*
110 * Each ACPU frequency has a certain minimum MSMC1 voltage requirement
111 * that is implicitly met by voting for a specific minimum AXI frequency.
112 * Do NOT change the AXI frequency unless you are _absoulutely_ sure you
113 * know all the h/w requirements.
114 */
115static struct clkctl_acpu_speed acpu_freq_tbl[] = {
116 { 0, 24576, LPXO, 0, 0, 30720000, 900, VDD_RAW(900) },
117 { 0, 61440, PLL_3, 5, 11, 61440000, 900, VDD_RAW(900) },
118 { 1, 122880, PLL_3, 5, 5, 61440000, 900, VDD_RAW(900) },
119 { 0, 184320, PLL_3, 5, 4, 61440000, 900, VDD_RAW(900) },
120 { 0, MAX_AXI_KHZ, AXI, 1, 0, 61440000, 900, VDD_RAW(900) },
121 { 1, 245760, PLL_3, 5, 2, 61440000, 900, VDD_RAW(900) },
122 { 1, 368640, PLL_3, 5, 1, 122800000, 900, VDD_RAW(900) },
123 /* AXI has MSMC1 implications. See above. */
124 { 1, 768000, PLL_1, 2, 0, 153600000, 1050, VDD_RAW(1050) },
125 /*
126 * AXI has MSMC1 implications. See above.
127 */
128 { 1, 806400, PLL_2, 3, 0, UINT_MAX, 1100, VDD_RAW(1100), &pll2_tbl[0]},
129 { 1, 1024000, PLL_2, 3, 0, UINT_MAX, 1200, VDD_RAW(1200), &pll2_tbl[1]},
130 { 1, 1200000, PLL_2, 3, 0, UINT_MAX, 1200, VDD_RAW(1200), &pll2_tbl[2]},
131 { 1, 1401600, PLL_2, 3, 0, UINT_MAX, 1250, VDD_RAW(1250), &pll2_tbl[3]},
132 { 0 }
133};
134
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700135static int acpuclk_set_acpu_vdd(struct clkctl_acpu_speed *s)
136{
137 int ret = msm_spm_set_vdd(0, s->vdd_raw);
138 if (ret)
139 return ret;
140
141 /* Wait for voltage to stabilize. */
Matt Wagantallec57f062011-08-16 23:54:46 -0700142 udelay(62);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700143 return 0;
144}
145
146/* Assumes PLL2 is off and the acpuclock isn't sourced from PLL2 */
147static void acpuclk_config_pll2(struct pll *pll)
148{
149 uint32_t config = readl_relaxed(PLL2_CONFIG_ADDR);
150
151 /* Make sure write to disable PLL_2 has completed
152 * before reconfiguring that PLL. */
153 mb();
154 writel_relaxed(pll->l, PLL2_L_VAL_ADDR);
155 writel_relaxed(pll->m, PLL2_M_VAL_ADDR);
156 writel_relaxed(pll->n, PLL2_N_VAL_ADDR);
157 if (pll->pre_div)
158 config |= BIT(15);
159 else
160 config &= ~BIT(15);
161 writel_relaxed(config, PLL2_CONFIG_ADDR);
162 /* Make sure PLL is programmed before returning. */
163 mb();
164}
165
166/* Set clock source and divider given a clock speed */
167static void acpuclk_set_src(const struct clkctl_acpu_speed *s)
168{
169 uint32_t reg_clksel, reg_clkctl, src_sel;
170
171 reg_clksel = readl_relaxed(SCSS_CLK_SEL_ADDR);
172
173 /* CLK_SEL_SRC1NO */
174 src_sel = reg_clksel & 1;
175
176 /* Program clock source and divider. */
177 reg_clkctl = readl_relaxed(SCSS_CLK_CTL_ADDR);
178 reg_clkctl &= ~(0xFF << (8 * src_sel));
179 reg_clkctl |= s->acpu_src_sel << (4 + 8 * src_sel);
180 reg_clkctl |= s->acpu_src_div << (0 + 8 * src_sel);
181 writel_relaxed(reg_clkctl, SCSS_CLK_CTL_ADDR);
182
183 /* Toggle clock source. */
184 reg_clksel ^= 1;
185
186 /* Program clock source selection. */
187 writel_relaxed(reg_clksel, SCSS_CLK_SEL_ADDR);
188
189 /* Make sure switch to new source is complete. */
190 mb();
191}
192
Matt Wagantall6d9ebee2011-08-26 12:15:24 -0700193static int acpuclk_7x30_set_rate(int cpu, unsigned long rate,
194 enum setrate_reason reason)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700195{
196 struct clkctl_acpu_speed *tgt_s, *strt_s;
197 int res, rc = 0;
198
199 if (reason == SETRATE_CPUFREQ)
200 mutex_lock(&drv_state.lock);
201
202 strt_s = drv_state.current_speed;
203
204 if (rate == strt_s->acpu_clk_khz)
205 goto out;
206
207 for (tgt_s = acpu_freq_tbl; tgt_s->acpu_clk_khz != 0; tgt_s++) {
208 if (tgt_s->acpu_clk_khz == rate)
209 break;
210 }
211 if (tgt_s->acpu_clk_khz == 0) {
212 rc = -EINVAL;
213 goto out;
214 }
215
216 if (reason == SETRATE_CPUFREQ) {
217 /* Increase VDD if needed. */
218 if (tgt_s->vdd_mv > strt_s->vdd_mv) {
219 rc = acpuclk_set_acpu_vdd(tgt_s);
220 if (rc < 0) {
221 pr_err("ACPU VDD increase to %d mV failed "
222 "(%d)\n", tgt_s->vdd_mv, rc);
223 goto out;
224 }
225 }
226 }
227
228 pr_debug("Switching from ACPU rate %u KHz -> %u KHz\n",
229 strt_s->acpu_clk_khz, tgt_s->acpu_clk_khz);
230
231 /* Increase the AXI bus frequency if needed. This must be done before
232 * increasing the ACPU frequency, since voting for high AXI rates
233 * implicitly takes care of increasing the MSMC1 voltage, as needed. */
234 if (tgt_s->axi_clk_hz > strt_s->axi_clk_hz) {
Matt Wagantalle0eecf02011-11-08 14:07:54 -0800235 rc = clk_set_rate(drv_state.ebi1_clk, tgt_s->axi_clk_hz);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700236 if (rc < 0) {
237 pr_err("Setting AXI min rate failed (%d)\n", rc);
238 goto out;
239 }
240 }
241
242 /* Move off of PLL2 if we're reprogramming it */
243 if (tgt_s->src == PLL_2 && strt_s->src == PLL_2) {
244 clk_enable(acpuclk_sources[backup_s->src]);
245 acpuclk_set_src(backup_s);
246 clk_disable(acpuclk_sources[strt_s->src]);
247 }
248
249 /* Reconfigure PLL2 if we're moving to it */
250 if (tgt_s->src == PLL_2)
251 acpuclk_config_pll2(tgt_s->pll_rate);
252
253 /* Make sure target PLL is on. */
254 if ((strt_s->src != tgt_s->src && tgt_s->src >= 0) ||
255 (tgt_s->src == PLL_2 && strt_s->src == PLL_2)) {
256 pr_debug("Enabling PLL %d\n", tgt_s->src);
257 clk_enable(acpuclk_sources[tgt_s->src]);
258 }
259
260 /* Perform the frequency switch */
261 acpuclk_set_src(tgt_s);
262 drv_state.current_speed = tgt_s;
Taniya Dasbb0b6db2012-03-19 14:09:55 +0530263 loops_per_jiffy = tgt_s->lpj;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700264
265 if (tgt_s->src == PLL_2 && strt_s->src == PLL_2)
266 clk_disable(acpuclk_sources[backup_s->src]);
267
268 /* Nothing else to do for SWFI. */
269 if (reason == SETRATE_SWFI)
270 goto out;
271
272 /* Turn off previous PLL if not used. */
273 if (strt_s->src != tgt_s->src && strt_s->src >= 0) {
274 pr_debug("Disabling PLL %d\n", strt_s->src);
275 clk_disable(acpuclk_sources[strt_s->src]);
276 }
277
278 /* Decrease the AXI bus frequency if we can. */
279 if (tgt_s->axi_clk_hz < strt_s->axi_clk_hz) {
Matt Wagantalle0eecf02011-11-08 14:07:54 -0800280 res = clk_set_rate(drv_state.ebi1_clk, tgt_s->axi_clk_hz);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700281 if (res < 0)
282 pr_warning("Setting AXI min rate failed (%d)\n", res);
283 }
284
285 /* Nothing else to do for power collapse. */
286 if (reason == SETRATE_PC)
287 goto out;
288
289 /* Drop VDD level if we can. */
290 if (tgt_s->vdd_mv < strt_s->vdd_mv) {
291 res = acpuclk_set_acpu_vdd(tgt_s);
292 if (res)
293 pr_warning("ACPU VDD decrease to %d mV failed (%d)\n",
294 tgt_s->vdd_mv, res);
295 }
296
297 pr_debug("ACPU speed change complete\n");
298out:
299 if (reason == SETRATE_CPUFREQ)
300 mutex_unlock(&drv_state.lock);
301
302 return rc;
303}
304
Matt Wagantall6d9ebee2011-08-26 12:15:24 -0700305static unsigned long acpuclk_7x30_get_rate(int cpu)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700306{
307 WARN_ONCE(drv_state.current_speed == NULL,
308 "acpuclk_get_rate: not initialized\n");
309 if (drv_state.current_speed)
310 return drv_state.current_speed->acpu_clk_khz;
311 else
312 return 0;
313}
314
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700315/*----------------------------------------------------------------------------
316 * Clock driver initialization
317 *---------------------------------------------------------------------------*/
318
Matt Wagantallbf430eb2012-03-22 11:45:49 -0700319static void __devinit acpuclk_hw_init(void)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700320{
321 struct clkctl_acpu_speed *s;
322 uint32_t div, sel, src_num;
323 uint32_t reg_clksel, reg_clkctl;
324 int res;
325 u8 pll2_l = readl_relaxed(PLL2_L_VAL_ADDR) & 0xFF;
326
327 drv_state.ebi1_clk = clk_get(NULL, "ebi1_clk");
328 BUG_ON(IS_ERR(drv_state.ebi1_clk));
329
330 reg_clksel = readl_relaxed(SCSS_CLK_SEL_ADDR);
331
332 /* Determine the ACPU clock rate. */
333 switch ((reg_clksel >> 1) & 0x3) {
334 case 0: /* Running off the output of the raw clock source mux. */
335 reg_clkctl = readl_relaxed(SCSS_CLK_CTL_ADDR);
336 src_num = reg_clksel & 0x1;
337 sel = (reg_clkctl >> (12 - (8 * src_num))) & 0x7;
338 div = (reg_clkctl >> (8 - (8 * src_num))) & 0xF;
339
340 /* Check frequency table for matching sel/div pair. */
341 for (s = acpu_freq_tbl; s->acpu_clk_khz != 0; s++) {
342 if (s->acpu_src_sel == sel && s->acpu_src_div == div)
343 break;
344 }
345 if (s->acpu_clk_khz == 0) {
346 pr_err("Error - ACPU clock reports invalid speed\n");
347 return;
348 }
349 break;
350 case 2: /* Running off of the SCPLL selected through the core mux. */
351 /* Switch to run off of the SCPLL selected through the raw
352 * clock source mux. */
353 for (s = acpu_freq_tbl; s->acpu_clk_khz != 0
354 && s->src != PLL_2 && s->acpu_src_div == 0; s++)
355 ;
356 if (s->acpu_clk_khz != 0) {
357 /* Program raw clock source mux. */
358 acpuclk_set_src(s);
359
360 /* Switch to raw clock source input of the core mux. */
361 reg_clksel = readl_relaxed(SCSS_CLK_SEL_ADDR);
362 reg_clksel &= ~(0x3 << 1);
363 writel_relaxed(reg_clksel, SCSS_CLK_SEL_ADDR);
364 break;
365 }
366 /* else fall through */
367 default:
368 pr_err("Error - ACPU clock reports invalid source\n");
369 return;
370 }
371
372 /* Look at PLL2's L val to determine what speed PLL2 is running at */
373 if (s->src == PLL_2)
374 for ( ; s->acpu_clk_khz; s++)
375 if (s->pll_rate && s->pll_rate->l == pll2_l)
376 break;
377
378 /* Set initial ACPU VDD. */
379 acpuclk_set_acpu_vdd(s);
380
381 drv_state.current_speed = s;
382
383 /* Initialize current PLL's reference count. */
384 if (s->src >= 0)
385 clk_enable(acpuclk_sources[s->src]);
386
Matt Wagantalle0eecf02011-11-08 14:07:54 -0800387 res = clk_set_rate(drv_state.ebi1_clk, s->axi_clk_hz);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700388 if (res < 0)
389 pr_warning("Setting AXI min rate failed!\n");
390
391 pr_info("ACPU running at %d KHz\n", s->acpu_clk_khz);
392
393 return;
394}
395
Taniya Dasbb0b6db2012-03-19 14:09:55 +0530396/* Initalize the lpj field in the acpu_freq_tbl. */
Matt Wagantallbf430eb2012-03-22 11:45:49 -0700397static void __devinit lpj_init(void)
Taniya Dasbb0b6db2012-03-19 14:09:55 +0530398{
399 int i;
400 const struct clkctl_acpu_speed *base_clk = drv_state.current_speed;
401
402 for (i = 0; acpu_freq_tbl[i].acpu_clk_khz; i++) {
403 acpu_freq_tbl[i].lpj = cpufreq_scale(loops_per_jiffy,
404 base_clk->acpu_clk_khz,
405 acpu_freq_tbl[i].acpu_clk_khz);
406 }
407}
408
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700409#ifdef CONFIG_CPU_FREQ_MSM
410static struct cpufreq_frequency_table cpufreq_tbl[ARRAY_SIZE(acpu_freq_tbl)];
411
412static void setup_cpufreq_table(void)
413{
414 unsigned i = 0;
415 const struct clkctl_acpu_speed *speed;
416
417 for (speed = acpu_freq_tbl; speed->acpu_clk_khz; speed++)
418 if (speed->use_for_scaling) {
419 cpufreq_tbl[i].index = i;
420 cpufreq_tbl[i].frequency = speed->acpu_clk_khz;
421 i++;
422 }
423 cpufreq_tbl[i].frequency = CPUFREQ_TABLE_END;
424
425 cpufreq_frequency_table_get_attr(cpufreq_tbl, smp_processor_id());
426}
427#else
428static inline void setup_cpufreq_table(void) { }
429#endif
430
431/*
432 * Truncate the frequency table at the current PLL2 rate and determine the
433 * backup PLL to use when scaling PLL2.
434 */
Matt Wagantallbf430eb2012-03-22 11:45:49 -0700435void __devinit pll2_fixup(void)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700436{
437 struct clkctl_acpu_speed *speed = acpu_freq_tbl;
438 u8 pll2_l = readl_relaxed(PLL2_L_VAL_ADDR) & 0xFF;
439
440 for ( ; speed->acpu_clk_khz; speed++) {
441 if (speed->src != PLL_2)
442 backup_s = speed;
443 if (speed->pll_rate && speed->pll_rate->l == pll2_l) {
444 speed++;
445 speed->acpu_clk_khz = 0;
446 return;
447 }
448 }
449
450 pr_err("Unknown PLL2 lval %d\n", pll2_l);
451 BUG();
452}
453
454#define RPM_BYPASS_MASK (1 << 3)
455#define PMIC_MODE_MASK (1 << 4)
456
Matt Wagantallbf430eb2012-03-22 11:45:49 -0700457static void __devinit populate_plls(void)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700458{
459 acpuclk_sources[PLL_1] = clk_get_sys("acpu", "pll1_clk");
460 BUG_ON(IS_ERR(acpuclk_sources[PLL_1]));
461 acpuclk_sources[PLL_2] = clk_get_sys("acpu", "pll2_clk");
462 BUG_ON(IS_ERR(acpuclk_sources[PLL_2]));
463 acpuclk_sources[PLL_3] = clk_get_sys("acpu", "pll3_clk");
464 BUG_ON(IS_ERR(acpuclk_sources[PLL_3]));
Stephen Boydbeb23f52012-01-25 10:09:30 -0800465 /*
466 * Prepare all the PLLs because we enable/disable them
467 * from atomic context and can't always ensure they're
468 * all prepared in non-atomic context.
469 */
470 BUG_ON(clk_prepare(acpuclk_sources[PLL_1]));
471 BUG_ON(clk_prepare(acpuclk_sources[PLL_2]));
472 BUG_ON(clk_prepare(acpuclk_sources[PLL_3]));
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700473}
474
Matt Wagantall6d9ebee2011-08-26 12:15:24 -0700475static struct acpuclk_data acpuclk_7x30_data = {
476 .set_rate = acpuclk_7x30_set_rate,
477 .get_rate = acpuclk_7x30_get_rate,
478 .power_collapse_khz = MAX_AXI_KHZ,
479 .wait_for_irq_khz = MAX_AXI_KHZ,
Matt Wagantallec57f062011-08-16 23:54:46 -0700480 .switch_time_us = 50,
Matt Wagantall6d9ebee2011-08-26 12:15:24 -0700481};
482
Matt Wagantallbf430eb2012-03-22 11:45:49 -0700483static int __devinit acpuclk_7x30_probe(struct platform_device *pdev)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700484{
Matt Wagantall6d9ebee2011-08-26 12:15:24 -0700485 pr_info("%s()\n", __func__);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700486
487 mutex_init(&drv_state.lock);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700488 pll2_fixup();
489 populate_plls();
Matt Wagantall6d9ebee2011-08-26 12:15:24 -0700490 acpuclk_hw_init();
Taniya Dasbb0b6db2012-03-19 14:09:55 +0530491 lpj_init();
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700492 setup_cpufreq_table();
Matt Wagantall6d9ebee2011-08-26 12:15:24 -0700493 acpuclk_register(&acpuclk_7x30_data);
494
495 return 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700496}
Matt Wagantallec57f062011-08-16 23:54:46 -0700497
Matt Wagantallbf430eb2012-03-22 11:45:49 -0700498static struct platform_driver acpuclk_7x30_driver = {
499 .probe = acpuclk_7x30_probe,
500 .driver = {
501 .name = "acpuclk-7x30",
502 .owner = THIS_MODULE,
503 },
Matt Wagantallec57f062011-08-16 23:54:46 -0700504};
Matt Wagantallbf430eb2012-03-22 11:45:49 -0700505
506static int __init acpuclk_7x30_init(void)
507{
508 return platform_driver_register(&acpuclk_7x30_driver);
509}
510postcore_initcall(acpuclk_7x30_init);