Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
awilliam
GitHub Repository: awilliam/linux-vfio
Path: blob/master/arch/arm/mach-mxs/clock-mx23.c
10817 views
1
/*
2
* Copyright (C) 2009-2010 Freescale Semiconductor, Inc. All Rights Reserved.
3
*
4
* This program is free software; you can redistribute it and/or modify
5
* it under the terms of the GNU General Public License as published by
6
* the Free Software Foundation; either version 2 of the License, or
7
* (at your option) any later version.
8
*
9
* This program is distributed in the hope that it will be useful,
10
* but WITHOUT ANY WARRANTY; without even the implied warranty of
11
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12
* GNU General Public License for more details.
13
*
14
* You should have received a copy of the GNU General Public License along
15
* with this program; if not, write to the Free Software Foundation, Inc.,
16
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
17
*/
18
19
#include <linux/mm.h>
20
#include <linux/delay.h>
21
#include <linux/clk.h>
22
#include <linux/io.h>
23
#include <linux/jiffies.h>
24
#include <linux/clkdev.h>
25
26
#include <asm/clkdev.h>
27
#include <asm/div64.h>
28
29
#include <mach/mx23.h>
30
#include <mach/common.h>
31
#include <mach/clock.h>
32
33
#include "regs-clkctrl-mx23.h"
34
35
#define CLKCTRL_BASE_ADDR MX23_IO_ADDRESS(MX23_CLKCTRL_BASE_ADDR)
36
#define DIGCTRL_BASE_ADDR MX23_IO_ADDRESS(MX23_DIGCTL_BASE_ADDR)
37
38
#define PARENT_RATE_SHIFT 8
39
40
static int _raw_clk_enable(struct clk *clk)
41
{
42
u32 reg;
43
44
if (clk->enable_reg) {
45
reg = __raw_readl(clk->enable_reg);
46
reg &= ~(1 << clk->enable_shift);
47
__raw_writel(reg, clk->enable_reg);
48
}
49
50
return 0;
51
}
52
53
static void _raw_clk_disable(struct clk *clk)
54
{
55
u32 reg;
56
57
if (clk->enable_reg) {
58
reg = __raw_readl(clk->enable_reg);
59
reg |= 1 << clk->enable_shift;
60
__raw_writel(reg, clk->enable_reg);
61
}
62
}
63
64
/*
65
* ref_xtal_clk
66
*/
67
static unsigned long ref_xtal_clk_get_rate(struct clk *clk)
68
{
69
return 24000000;
70
}
71
72
static struct clk ref_xtal_clk = {
73
.get_rate = ref_xtal_clk_get_rate,
74
};
75
76
/*
77
* pll_clk
78
*/
79
static unsigned long pll_clk_get_rate(struct clk *clk)
80
{
81
return 480000000;
82
}
83
84
static int pll_clk_enable(struct clk *clk)
85
{
86
__raw_writel(BM_CLKCTRL_PLLCTRL0_POWER |
87
BM_CLKCTRL_PLLCTRL0_EN_USB_CLKS,
88
CLKCTRL_BASE_ADDR + HW_CLKCTRL_PLLCTRL0_SET);
89
90
/* Only a 10us delay is need. PLLCTRL1 LOCK bitfied is only a timer
91
* and is incorrect (excessive). Per definition of the PLLCTRL0
92
* POWER field, waiting at least 10us.
93
*/
94
udelay(10);
95
96
return 0;
97
}
98
99
static void pll_clk_disable(struct clk *clk)
100
{
101
__raw_writel(BM_CLKCTRL_PLLCTRL0_POWER |
102
BM_CLKCTRL_PLLCTRL0_EN_USB_CLKS,
103
CLKCTRL_BASE_ADDR + HW_CLKCTRL_PLLCTRL0_CLR);
104
}
105
106
static struct clk pll_clk = {
107
.get_rate = pll_clk_get_rate,
108
.enable = pll_clk_enable,
109
.disable = pll_clk_disable,
110
.parent = &ref_xtal_clk,
111
};
112
113
/*
114
* ref_clk
115
*/
116
#define _CLK_GET_RATE_REF(name, sr, ss) \
117
static unsigned long name##_get_rate(struct clk *clk) \
118
{ \
119
unsigned long parent_rate; \
120
u32 reg, div; \
121
\
122
reg = __raw_readl(CLKCTRL_BASE_ADDR + HW_CLKCTRL_##sr); \
123
div = (reg >> BP_CLKCTRL_##sr##_##ss##FRAC) & 0x3f; \
124
parent_rate = clk_get_rate(clk->parent); \
125
\
126
return SH_DIV((parent_rate >> PARENT_RATE_SHIFT) * 18, \
127
div, PARENT_RATE_SHIFT); \
128
}
129
130
_CLK_GET_RATE_REF(ref_cpu_clk, FRAC, CPU)
131
_CLK_GET_RATE_REF(ref_emi_clk, FRAC, EMI)
132
_CLK_GET_RATE_REF(ref_pix_clk, FRAC, PIX)
133
_CLK_GET_RATE_REF(ref_io_clk, FRAC, IO)
134
135
#define _DEFINE_CLOCK_REF(name, er, es) \
136
static struct clk name = { \
137
.enable_reg = CLKCTRL_BASE_ADDR + HW_CLKCTRL_##er, \
138
.enable_shift = BP_CLKCTRL_##er##_CLKGATE##es, \
139
.get_rate = name##_get_rate, \
140
.enable = _raw_clk_enable, \
141
.disable = _raw_clk_disable, \
142
.parent = &pll_clk, \
143
}
144
145
_DEFINE_CLOCK_REF(ref_cpu_clk, FRAC, CPU);
146
_DEFINE_CLOCK_REF(ref_emi_clk, FRAC, EMI);
147
_DEFINE_CLOCK_REF(ref_pix_clk, FRAC, PIX);
148
_DEFINE_CLOCK_REF(ref_io_clk, FRAC, IO);
149
150
/*
151
* General clocks
152
*
153
* clk_get_rate
154
*/
155
static unsigned long rtc_clk_get_rate(struct clk *clk)
156
{
157
/* ref_xtal_clk is implemented as the only parent */
158
return clk_get_rate(clk->parent) / 768;
159
}
160
161
static unsigned long clk32k_clk_get_rate(struct clk *clk)
162
{
163
return clk->parent->get_rate(clk->parent) / 750;
164
}
165
166
#define _CLK_GET_RATE(name, rs) \
167
static unsigned long name##_get_rate(struct clk *clk) \
168
{ \
169
u32 reg, div; \
170
\
171
reg = __raw_readl(CLKCTRL_BASE_ADDR + HW_CLKCTRL_##rs); \
172
\
173
if (clk->parent == &ref_xtal_clk) \
174
div = (reg & BM_CLKCTRL_##rs##_DIV_XTAL) >> \
175
BP_CLKCTRL_##rs##_DIV_XTAL; \
176
else \
177
div = (reg & BM_CLKCTRL_##rs##_DIV_##rs) >> \
178
BP_CLKCTRL_##rs##_DIV_##rs; \
179
\
180
if (!div) \
181
return -EINVAL; \
182
\
183
return clk_get_rate(clk->parent) / div; \
184
}
185
186
_CLK_GET_RATE(cpu_clk, CPU)
187
_CLK_GET_RATE(emi_clk, EMI)
188
189
#define _CLK_GET_RATE1(name, rs) \
190
static unsigned long name##_get_rate(struct clk *clk) \
191
{ \
192
u32 reg, div; \
193
\
194
reg = __raw_readl(CLKCTRL_BASE_ADDR + HW_CLKCTRL_##rs); \
195
div = (reg & BM_CLKCTRL_##rs##_DIV) >> BP_CLKCTRL_##rs##_DIV; \
196
\
197
if (!div) \
198
return -EINVAL; \
199
\
200
return clk_get_rate(clk->parent) / div; \
201
}
202
203
_CLK_GET_RATE1(hbus_clk, HBUS)
204
_CLK_GET_RATE1(xbus_clk, XBUS)
205
_CLK_GET_RATE1(ssp_clk, SSP)
206
_CLK_GET_RATE1(gpmi_clk, GPMI)
207
_CLK_GET_RATE1(lcdif_clk, PIX)
208
209
#define _CLK_GET_RATE_STUB(name) \
210
static unsigned long name##_get_rate(struct clk *clk) \
211
{ \
212
return clk_get_rate(clk->parent); \
213
}
214
215
_CLK_GET_RATE_STUB(uart_clk)
216
_CLK_GET_RATE_STUB(audio_clk)
217
_CLK_GET_RATE_STUB(pwm_clk)
218
219
/*
220
* clk_set_rate
221
*/
222
static int cpu_clk_set_rate(struct clk *clk, unsigned long rate)
223
{
224
u32 reg, bm_busy, div_max, d, f, div, frac;
225
unsigned long diff, parent_rate, calc_rate;
226
int i;
227
228
parent_rate = clk_get_rate(clk->parent);
229
230
if (clk->parent == &ref_xtal_clk) {
231
div_max = BM_CLKCTRL_CPU_DIV_XTAL >> BP_CLKCTRL_CPU_DIV_XTAL;
232
bm_busy = BM_CLKCTRL_CPU_BUSY_REF_XTAL;
233
div = DIV_ROUND_UP(parent_rate, rate);
234
if (div == 0 || div > div_max)
235
return -EINVAL;
236
} else {
237
div_max = BM_CLKCTRL_CPU_DIV_CPU >> BP_CLKCTRL_CPU_DIV_CPU;
238
bm_busy = BM_CLKCTRL_CPU_BUSY_REF_CPU;
239
rate >>= PARENT_RATE_SHIFT;
240
parent_rate >>= PARENT_RATE_SHIFT;
241
diff = parent_rate;
242
div = frac = 1;
243
for (d = 1; d <= div_max; d++) {
244
f = parent_rate * 18 / d / rate;
245
if ((parent_rate * 18 / d) % rate)
246
f++;
247
if (f < 18 || f > 35)
248
continue;
249
250
calc_rate = parent_rate * 18 / f / d;
251
if (calc_rate > rate)
252
continue;
253
254
if (rate - calc_rate < diff) {
255
frac = f;
256
div = d;
257
diff = rate - calc_rate;
258
}
259
260
if (diff == 0)
261
break;
262
}
263
264
if (diff == parent_rate)
265
return -EINVAL;
266
267
reg = __raw_readl(CLKCTRL_BASE_ADDR + HW_CLKCTRL_FRAC);
268
reg &= ~BM_CLKCTRL_FRAC_CPUFRAC;
269
reg |= frac;
270
__raw_writel(reg, CLKCTRL_BASE_ADDR + HW_CLKCTRL_FRAC);
271
}
272
273
reg = __raw_readl(CLKCTRL_BASE_ADDR + HW_CLKCTRL_CPU);
274
reg &= ~BM_CLKCTRL_CPU_DIV_CPU;
275
reg |= div << BP_CLKCTRL_CPU_DIV_CPU;
276
__raw_writel(reg, CLKCTRL_BASE_ADDR + HW_CLKCTRL_CPU);
277
278
for (i = 10000; i; i--)
279
if (!(__raw_readl(CLKCTRL_BASE_ADDR +
280
HW_CLKCTRL_CPU) & bm_busy))
281
break;
282
if (!i) {
283
pr_err("%s: divider writing timeout\n", __func__);
284
return -ETIMEDOUT;
285
}
286
287
return 0;
288
}
289
290
#define _CLK_SET_RATE(name, dr) \
291
static int name##_set_rate(struct clk *clk, unsigned long rate) \
292
{ \
293
u32 reg, div_max, div; \
294
unsigned long parent_rate; \
295
int i; \
296
\
297
parent_rate = clk_get_rate(clk->parent); \
298
div_max = BM_CLKCTRL_##dr##_DIV >> BP_CLKCTRL_##dr##_DIV; \
299
\
300
div = DIV_ROUND_UP(parent_rate, rate); \
301
if (div == 0 || div > div_max) \
302
return -EINVAL; \
303
\
304
reg = __raw_readl(CLKCTRL_BASE_ADDR + HW_CLKCTRL_##dr); \
305
reg &= ~BM_CLKCTRL_##dr##_DIV; \
306
reg |= div << BP_CLKCTRL_##dr##_DIV; \
307
if (reg & (1 << clk->enable_shift)) { \
308
pr_err("%s: clock is gated\n", __func__); \
309
return -EINVAL; \
310
} \
311
__raw_writel(reg, CLKCTRL_BASE_ADDR + HW_CLKCTRL_##dr); \
312
\
313
for (i = 10000; i; i--) \
314
if (!(__raw_readl(CLKCTRL_BASE_ADDR + \
315
HW_CLKCTRL_##dr) & BM_CLKCTRL_##dr##_BUSY)) \
316
break; \
317
if (!i) { \
318
pr_err("%s: divider writing timeout\n", __func__); \
319
return -ETIMEDOUT; \
320
} \
321
\
322
return 0; \
323
}
324
325
_CLK_SET_RATE(xbus_clk, XBUS)
326
_CLK_SET_RATE(ssp_clk, SSP)
327
_CLK_SET_RATE(gpmi_clk, GPMI)
328
_CLK_SET_RATE(lcdif_clk, PIX)
329
330
#define _CLK_SET_RATE_STUB(name) \
331
static int name##_set_rate(struct clk *clk, unsigned long rate) \
332
{ \
333
return -EINVAL; \
334
}
335
336
_CLK_SET_RATE_STUB(emi_clk)
337
_CLK_SET_RATE_STUB(uart_clk)
338
_CLK_SET_RATE_STUB(audio_clk)
339
_CLK_SET_RATE_STUB(pwm_clk)
340
_CLK_SET_RATE_STUB(clk32k_clk)
341
342
/*
343
* clk_set_parent
344
*/
345
#define _CLK_SET_PARENT(name, bit) \
346
static int name##_set_parent(struct clk *clk, struct clk *parent) \
347
{ \
348
if (parent != clk->parent) { \
349
__raw_writel(BM_CLKCTRL_CLKSEQ_BYPASS_##bit, \
350
CLKCTRL_BASE_ADDR + HW_CLKCTRL_CLKSEQ_TOG); \
351
clk->parent = parent; \
352
} \
353
\
354
return 0; \
355
}
356
357
_CLK_SET_PARENT(cpu_clk, CPU)
358
_CLK_SET_PARENT(emi_clk, EMI)
359
_CLK_SET_PARENT(ssp_clk, SSP)
360
_CLK_SET_PARENT(gpmi_clk, GPMI)
361
_CLK_SET_PARENT(lcdif_clk, PIX)
362
363
#define _CLK_SET_PARENT_STUB(name) \
364
static int name##_set_parent(struct clk *clk, struct clk *parent) \
365
{ \
366
if (parent != clk->parent) \
367
return -EINVAL; \
368
else \
369
return 0; \
370
}
371
372
_CLK_SET_PARENT_STUB(uart_clk)
373
_CLK_SET_PARENT_STUB(audio_clk)
374
_CLK_SET_PARENT_STUB(pwm_clk)
375
_CLK_SET_PARENT_STUB(clk32k_clk)
376
377
/*
378
* clk definition
379
*/
380
static struct clk cpu_clk = {
381
.get_rate = cpu_clk_get_rate,
382
.set_rate = cpu_clk_set_rate,
383
.set_parent = cpu_clk_set_parent,
384
.parent = &ref_cpu_clk,
385
};
386
387
static struct clk hbus_clk = {
388
.get_rate = hbus_clk_get_rate,
389
.parent = &cpu_clk,
390
};
391
392
static struct clk xbus_clk = {
393
.get_rate = xbus_clk_get_rate,
394
.set_rate = xbus_clk_set_rate,
395
.parent = &ref_xtal_clk,
396
};
397
398
static struct clk rtc_clk = {
399
.get_rate = rtc_clk_get_rate,
400
.parent = &ref_xtal_clk,
401
};
402
403
/* usb_clk gate is controlled in DIGCTRL other than CLKCTRL */
404
static struct clk usb_clk = {
405
.enable_reg = DIGCTRL_BASE_ADDR,
406
.enable_shift = 2,
407
.enable = _raw_clk_enable,
408
.disable = _raw_clk_disable,
409
.parent = &pll_clk,
410
};
411
412
#define _DEFINE_CLOCK(name, er, es, p) \
413
static struct clk name = { \
414
.enable_reg = CLKCTRL_BASE_ADDR + HW_CLKCTRL_##er, \
415
.enable_shift = BP_CLKCTRL_##er##_##es, \
416
.get_rate = name##_get_rate, \
417
.set_rate = name##_set_rate, \
418
.set_parent = name##_set_parent, \
419
.enable = _raw_clk_enable, \
420
.disable = _raw_clk_disable, \
421
.parent = p, \
422
}
423
424
_DEFINE_CLOCK(emi_clk, EMI, CLKGATE, &ref_xtal_clk);
425
_DEFINE_CLOCK(ssp_clk, SSP, CLKGATE, &ref_xtal_clk);
426
_DEFINE_CLOCK(gpmi_clk, GPMI, CLKGATE, &ref_xtal_clk);
427
_DEFINE_CLOCK(lcdif_clk, PIX, CLKGATE, &ref_xtal_clk);
428
_DEFINE_CLOCK(uart_clk, XTAL, UART_CLK_GATE, &ref_xtal_clk);
429
_DEFINE_CLOCK(audio_clk, XTAL, FILT_CLK24M_GATE, &ref_xtal_clk);
430
_DEFINE_CLOCK(pwm_clk, XTAL, PWM_CLK24M_GATE, &ref_xtal_clk);
431
_DEFINE_CLOCK(clk32k_clk, XTAL, TIMROT_CLK32K_GATE, &ref_xtal_clk);
432
433
#define _REGISTER_CLOCK(d, n, c) \
434
{ \
435
.dev_id = d, \
436
.con_id = n, \
437
.clk = &c, \
438
},
439
440
static struct clk_lookup lookups[] = {
441
/* for amba bus driver */
442
_REGISTER_CLOCK("duart", "apb_pclk", xbus_clk)
443
/* for amba-pl011 driver */
444
_REGISTER_CLOCK("duart", NULL, uart_clk)
445
_REGISTER_CLOCK("mxs-auart.0", NULL, uart_clk)
446
_REGISTER_CLOCK("rtc", NULL, rtc_clk)
447
_REGISTER_CLOCK("mxs-dma-apbh", NULL, hbus_clk)
448
_REGISTER_CLOCK("mxs-dma-apbx", NULL, xbus_clk)
449
_REGISTER_CLOCK("mxs-mmc.0", NULL, ssp_clk)
450
_REGISTER_CLOCK("mxs-mmc.1", NULL, ssp_clk)
451
_REGISTER_CLOCK(NULL, "usb", usb_clk)
452
_REGISTER_CLOCK(NULL, "audio", audio_clk)
453
_REGISTER_CLOCK("mxs-pwm.0", NULL, pwm_clk)
454
_REGISTER_CLOCK("mxs-pwm.1", NULL, pwm_clk)
455
_REGISTER_CLOCK("mxs-pwm.2", NULL, pwm_clk)
456
_REGISTER_CLOCK("mxs-pwm.3", NULL, pwm_clk)
457
_REGISTER_CLOCK("mxs-pwm.4", NULL, pwm_clk)
458
_REGISTER_CLOCK("imx23-fb", NULL, lcdif_clk)
459
};
460
461
static int clk_misc_init(void)
462
{
463
u32 reg;
464
int i;
465
466
/* Fix up parent per register setting */
467
reg = __raw_readl(CLKCTRL_BASE_ADDR + HW_CLKCTRL_CLKSEQ);
468
cpu_clk.parent = (reg & BM_CLKCTRL_CLKSEQ_BYPASS_CPU) ?
469
&ref_xtal_clk : &ref_cpu_clk;
470
emi_clk.parent = (reg & BM_CLKCTRL_CLKSEQ_BYPASS_EMI) ?
471
&ref_xtal_clk : &ref_emi_clk;
472
ssp_clk.parent = (reg & BM_CLKCTRL_CLKSEQ_BYPASS_SSP) ?
473
&ref_xtal_clk : &ref_io_clk;
474
gpmi_clk.parent = (reg & BM_CLKCTRL_CLKSEQ_BYPASS_GPMI) ?
475
&ref_xtal_clk : &ref_io_clk;
476
lcdif_clk.parent = (reg & BM_CLKCTRL_CLKSEQ_BYPASS_PIX) ?
477
&ref_xtal_clk : &ref_pix_clk;
478
479
/* Use int div over frac when both are available */
480
__raw_writel(BM_CLKCTRL_CPU_DIV_XTAL_FRAC_EN,
481
CLKCTRL_BASE_ADDR + HW_CLKCTRL_CPU_CLR);
482
__raw_writel(BM_CLKCTRL_CPU_DIV_CPU_FRAC_EN,
483
CLKCTRL_BASE_ADDR + HW_CLKCTRL_CPU_CLR);
484
__raw_writel(BM_CLKCTRL_HBUS_DIV_FRAC_EN,
485
CLKCTRL_BASE_ADDR + HW_CLKCTRL_HBUS_CLR);
486
487
reg = __raw_readl(CLKCTRL_BASE_ADDR + HW_CLKCTRL_XBUS);
488
reg &= ~BM_CLKCTRL_XBUS_DIV_FRAC_EN;
489
__raw_writel(reg, CLKCTRL_BASE_ADDR + HW_CLKCTRL_XBUS);
490
491
reg = __raw_readl(CLKCTRL_BASE_ADDR + HW_CLKCTRL_SSP);
492
reg &= ~BM_CLKCTRL_SSP_DIV_FRAC_EN;
493
__raw_writel(reg, CLKCTRL_BASE_ADDR + HW_CLKCTRL_SSP);
494
495
reg = __raw_readl(CLKCTRL_BASE_ADDR + HW_CLKCTRL_GPMI);
496
reg &= ~BM_CLKCTRL_GPMI_DIV_FRAC_EN;
497
__raw_writel(reg, CLKCTRL_BASE_ADDR + HW_CLKCTRL_GPMI);
498
499
reg = __raw_readl(CLKCTRL_BASE_ADDR + HW_CLKCTRL_PIX);
500
reg &= ~BM_CLKCTRL_PIX_DIV_FRAC_EN;
501
__raw_writel(reg, CLKCTRL_BASE_ADDR + HW_CLKCTRL_PIX);
502
503
/*
504
* Set safe hbus clock divider. A divider of 3 ensure that
505
* the Vddd voltage required for the cpu clock is sufficiently
506
* high for the hbus clock.
507
*/
508
reg = __raw_readl(CLKCTRL_BASE_ADDR + HW_CLKCTRL_HBUS);
509
reg &= BM_CLKCTRL_HBUS_DIV;
510
reg |= 3 << BP_CLKCTRL_HBUS_DIV;
511
__raw_writel(reg, CLKCTRL_BASE_ADDR + HW_CLKCTRL_HBUS);
512
513
for (i = 10000; i; i--)
514
if (!(__raw_readl(CLKCTRL_BASE_ADDR +
515
HW_CLKCTRL_HBUS) & BM_CLKCTRL_HBUS_BUSY))
516
break;
517
if (!i) {
518
pr_err("%s: divider writing timeout\n", __func__);
519
return -ETIMEDOUT;
520
}
521
522
/* Gate off cpu clock in WFI for power saving */
523
__raw_writel(BM_CLKCTRL_CPU_INTERRUPT_WAIT,
524
CLKCTRL_BASE_ADDR + HW_CLKCTRL_CPU_SET);
525
526
/*
527
* 480 MHz seems too high to be ssp clock source directly,
528
* so set frac to get a 288 MHz ref_io.
529
*/
530
reg = __raw_readl(CLKCTRL_BASE_ADDR + HW_CLKCTRL_FRAC);
531
reg &= ~BM_CLKCTRL_FRAC_IOFRAC;
532
reg |= 30 << BP_CLKCTRL_FRAC_IOFRAC;
533
__raw_writel(reg, CLKCTRL_BASE_ADDR + HW_CLKCTRL_FRAC);
534
535
return 0;
536
}
537
538
int __init mx23_clocks_init(void)
539
{
540
clk_misc_init();
541
542
/*
543
* source ssp clock from ref_io than ref_xtal,
544
* as ref_xtal only provides 24 MHz as maximum.
545
*/
546
clk_set_parent(&ssp_clk, &ref_io_clk);
547
548
clk_enable(&cpu_clk);
549
clk_enable(&hbus_clk);
550
clk_enable(&xbus_clk);
551
clk_enable(&emi_clk);
552
clk_enable(&uart_clk);
553
554
clkdev_add_table(lookups, ARRAY_SIZE(lookups));
555
556
mxs_timer_init(&clk32k_clk, MX23_INT_TIMER0);
557
558
return 0;
559
}
560
561