1/*
2 * device.c  -- common ColdFire SoC device support
3 *
4 * (C) Copyright 2011, Greg Ungerer <gerg@uclinux.org>
5 *
6 * This file is subject to the terms and conditions of the GNU General Public
7 * License.  See the file COPYING in the main directory of this archive
8 * for more details.
9 */
10
11#include <linux/kernel.h>
12#include <linux/init.h>
13#include <linux/io.h>
14#include <linux/spi/spi.h>
15#include <linux/gpio.h>
16#include <linux/fec.h>
17#include <linux/dmaengine.h>
18#include <asm/traps.h>
19#include <asm/coldfire.h>
20#include <asm/mcfsim.h>
21#include <asm/mcfuart.h>
22#include <asm/mcfqspi.h>
23#include <linux/platform_data/edma.h>
24#include <linux/platform_data/dma-mcf-edma.h>
25#include <linux/platform_data/mmc-esdhc-mcf.h>
26
27/*
28 *	All current ColdFire parts contain from 2, 3, 4 or 10 UARTS.
29 */
30static struct mcf_platform_uart mcf_uart_platform_data[] = {
31	{
32		.mapbase	= MCFUART_BASE0,
33		.irq		= MCF_IRQ_UART0,
34	},
35	{
36		.mapbase	= MCFUART_BASE1,
37		.irq		= MCF_IRQ_UART1,
38	},
39#ifdef MCFUART_BASE2
40	{
41		.mapbase	= MCFUART_BASE2,
42		.irq		= MCF_IRQ_UART2,
43	},
44#endif
45#ifdef MCFUART_BASE3
46	{
47		.mapbase	= MCFUART_BASE3,
48		.irq		= MCF_IRQ_UART3,
49	},
50#endif
51#ifdef MCFUART_BASE4
52	{
53		.mapbase	= MCFUART_BASE4,
54		.irq		= MCF_IRQ_UART4,
55	},
56#endif
57#ifdef MCFUART_BASE5
58	{
59		.mapbase	= MCFUART_BASE5,
60		.irq		= MCF_IRQ_UART5,
61	},
62#endif
63#ifdef MCFUART_BASE6
64	{
65		.mapbase	= MCFUART_BASE6,
66		.irq		= MCF_IRQ_UART6,
67	},
68#endif
69#ifdef MCFUART_BASE7
70	{
71		.mapbase	= MCFUART_BASE7,
72		.irq		= MCF_IRQ_UART7,
73	},
74#endif
75#ifdef MCFUART_BASE8
76	{
77		.mapbase	= MCFUART_BASE8,
78		.irq		= MCF_IRQ_UART8,
79	},
80#endif
81#ifdef MCFUART_BASE9
82	{
83		.mapbase	= MCFUART_BASE9,
84		.irq		= MCF_IRQ_UART9,
85	},
86#endif
87	{ },
88};
89
90static struct platform_device mcf_uart = {
91	.name			= "mcfuart",
92	.id			= 0,
93	.dev.platform_data	= mcf_uart_platform_data,
94};
95
96#if IS_ENABLED(CONFIG_FEC)
97
98#ifdef CONFIG_M5441x
99#define FEC_NAME	"enet-fec"
100static struct fec_platform_data fec_pdata = {
101	.phy		= PHY_INTERFACE_MODE_RMII,
102};
103#define FEC_PDATA	(&fec_pdata)
104#else
105#define FEC_NAME	"fec"
106#define FEC_PDATA	NULL
107#endif
108
109/*
110 *	Some ColdFire cores contain the Fast Ethernet Controller (FEC)
111 *	block. It is Freescale's own hardware block. Some ColdFires
112 *	have 2 of these.
113 */
114static struct resource mcf_fec0_resources[] = {
115	{
116		.start		= MCFFEC_BASE0,
117		.end		= MCFFEC_BASE0 + MCFFEC_SIZE0 - 1,
118		.flags		= IORESOURCE_MEM,
119	},
120	{
121		.start		= MCF_IRQ_FECRX0,
122		.end		= MCF_IRQ_FECRX0,
123		.flags		= IORESOURCE_IRQ,
124	},
125	{
126		.start		= MCF_IRQ_FECTX0,
127		.end		= MCF_IRQ_FECTX0,
128		.flags		= IORESOURCE_IRQ,
129	},
130	{
131		.start		= MCF_IRQ_FECENTC0,
132		.end		= MCF_IRQ_FECENTC0,
133		.flags		= IORESOURCE_IRQ,
134	},
135};
136
137static struct platform_device mcf_fec0 = {
138	.name			= FEC_NAME,
139	.id			= 0,
140	.num_resources		= ARRAY_SIZE(mcf_fec0_resources),
141	.resource		= mcf_fec0_resources,
142	.dev = {
143		.dma_mask		= &mcf_fec0.dev.coherent_dma_mask,
144		.coherent_dma_mask	= DMA_BIT_MASK(32),
145		.platform_data		= FEC_PDATA,
146	}
147};
148
149#ifdef MCFFEC_BASE1
150static struct resource mcf_fec1_resources[] = {
151	{
152		.start		= MCFFEC_BASE1,
153		.end		= MCFFEC_BASE1 + MCFFEC_SIZE1 - 1,
154		.flags		= IORESOURCE_MEM,
155	},
156	{
157		.start		= MCF_IRQ_FECRX1,
158		.end		= MCF_IRQ_FECRX1,
159		.flags		= IORESOURCE_IRQ,
160	},
161	{
162		.start		= MCF_IRQ_FECTX1,
163		.end		= MCF_IRQ_FECTX1,
164		.flags		= IORESOURCE_IRQ,
165	},
166	{
167		.start		= MCF_IRQ_FECENTC1,
168		.end		= MCF_IRQ_FECENTC1,
169		.flags		= IORESOURCE_IRQ,
170	},
171};
172
173static struct platform_device mcf_fec1 = {
174	.name			= FEC_NAME,
175	.id			= 1,
176	.num_resources		= ARRAY_SIZE(mcf_fec1_resources),
177	.resource		= mcf_fec1_resources,
178	.dev = {
179		.dma_mask		= &mcf_fec1.dev.coherent_dma_mask,
180		.coherent_dma_mask	= DMA_BIT_MASK(32),
181		.platform_data		= FEC_PDATA,
182	}
183};
184#endif /* MCFFEC_BASE1 */
185#endif /* CONFIG_FEC */
186
187#if IS_ENABLED(CONFIG_SPI_COLDFIRE_QSPI)
188/*
189 *	The ColdFire QSPI module is an SPI protocol hardware block used
190 *	on a number of different ColdFire CPUs.
191 */
192static struct resource mcf_qspi_resources[] = {
193	{
194		.start		= MCFQSPI_BASE,
195		.end		= MCFQSPI_BASE + MCFQSPI_SIZE - 1,
196		.flags		= IORESOURCE_MEM,
197	},
198	{
199		.start		= MCF_IRQ_QSPI,
200		.end		= MCF_IRQ_QSPI,
201		.flags		= IORESOURCE_IRQ,
202	},
203};
204
205static int mcf_cs_setup(struct mcfqspi_cs_control *cs_control)
206{
207	int status;
208
209	status = gpio_request(MCFQSPI_CS0, "MCFQSPI_CS0");
210	if (status) {
211		pr_debug("gpio_request for MCFQSPI_CS0 failed\n");
212		goto fail0;
213	}
214	status = gpio_direction_output(MCFQSPI_CS0, 1);
215	if (status) {
216		pr_debug("gpio_direction_output for MCFQSPI_CS0 failed\n");
217		goto fail1;
218	}
219
220	status = gpio_request(MCFQSPI_CS1, "MCFQSPI_CS1");
221	if (status) {
222		pr_debug("gpio_request for MCFQSPI_CS1 failed\n");
223		goto fail1;
224	}
225	status = gpio_direction_output(MCFQSPI_CS1, 1);
226	if (status) {
227		pr_debug("gpio_direction_output for MCFQSPI_CS1 failed\n");
228		goto fail2;
229	}
230
231	status = gpio_request(MCFQSPI_CS2, "MCFQSPI_CS2");
232	if (status) {
233		pr_debug("gpio_request for MCFQSPI_CS2 failed\n");
234		goto fail2;
235	}
236	status = gpio_direction_output(MCFQSPI_CS2, 1);
237	if (status) {
238		pr_debug("gpio_direction_output for MCFQSPI_CS2 failed\n");
239		goto fail3;
240	}
241
242#ifdef MCFQSPI_CS3
243	status = gpio_request(MCFQSPI_CS3, "MCFQSPI_CS3");
244	if (status) {
245		pr_debug("gpio_request for MCFQSPI_CS3 failed\n");
246		goto fail3;
247	}
248	status = gpio_direction_output(MCFQSPI_CS3, 1);
249	if (status) {
250		pr_debug("gpio_direction_output for MCFQSPI_CS3 failed\n");
251		gpio_free(MCFQSPI_CS3);
252		goto fail3;
253	}
254#endif
255
256	return 0;
257
258fail3:
259	gpio_free(MCFQSPI_CS2);
260fail2:
261	gpio_free(MCFQSPI_CS1);
262fail1:
263	gpio_free(MCFQSPI_CS0);
264fail0:
265	return status;
266}
267
268static void mcf_cs_teardown(struct mcfqspi_cs_control *cs_control)
269{
270#ifdef MCFQSPI_CS3
271	gpio_free(MCFQSPI_CS3);
272#endif
273	gpio_free(MCFQSPI_CS2);
274	gpio_free(MCFQSPI_CS1);
275	gpio_free(MCFQSPI_CS0);
276}
277
278static void mcf_cs_select(struct mcfqspi_cs_control *cs_control,
279			  u8 chip_select, bool cs_high)
280{
281	switch (chip_select) {
282	case 0:
283		gpio_set_value(MCFQSPI_CS0, cs_high);
284		break;
285	case 1:
286		gpio_set_value(MCFQSPI_CS1, cs_high);
287		break;
288	case 2:
289		gpio_set_value(MCFQSPI_CS2, cs_high);
290		break;
291#ifdef MCFQSPI_CS3
292	case 3:
293		gpio_set_value(MCFQSPI_CS3, cs_high);
294		break;
295#endif
296	}
297}
298
299static void mcf_cs_deselect(struct mcfqspi_cs_control *cs_control,
300			    u8 chip_select, bool cs_high)
301{
302	switch (chip_select) {
303	case 0:
304		gpio_set_value(MCFQSPI_CS0, !cs_high);
305		break;
306	case 1:
307		gpio_set_value(MCFQSPI_CS1, !cs_high);
308		break;
309	case 2:
310		gpio_set_value(MCFQSPI_CS2, !cs_high);
311		break;
312#ifdef MCFQSPI_CS3
313	case 3:
314		gpio_set_value(MCFQSPI_CS3, !cs_high);
315		break;
316#endif
317	}
318}
319
320static struct mcfqspi_cs_control mcf_cs_control = {
321	.setup			= mcf_cs_setup,
322	.teardown		= mcf_cs_teardown,
323	.select			= mcf_cs_select,
324	.deselect		= mcf_cs_deselect,
325};
326
327static struct mcfqspi_platform_data mcf_qspi_data = {
328	.bus_num		= 0,
329	.num_chipselect		= 4,
330	.cs_control		= &mcf_cs_control,
331};
332
333static struct platform_device mcf_qspi = {
334	.name			= "mcfqspi",
335	.id			= 0,
336	.num_resources		= ARRAY_SIZE(mcf_qspi_resources),
337	.resource		= mcf_qspi_resources,
338	.dev.platform_data	= &mcf_qspi_data,
339};
340#endif /* IS_ENABLED(CONFIG_SPI_COLDFIRE_QSPI) */
341
342#if IS_ENABLED(CONFIG_I2C_IMX)
343static struct resource mcf_i2c0_resources[] = {
344	{
345		.start          = MCFI2C_BASE0,
346		.end            = MCFI2C_BASE0 + MCFI2C_SIZE0 - 1,
347		.flags          = IORESOURCE_MEM,
348	},
349	{
350		.start          = MCF_IRQ_I2C0,
351		.end            = MCF_IRQ_I2C0,
352		.flags          = IORESOURCE_IRQ,
353	},
354};
355
356static struct platform_device mcf_i2c0 = {
357	.name                   = "imx1-i2c",
358	.id                     = 0,
359	.num_resources          = ARRAY_SIZE(mcf_i2c0_resources),
360	.resource               = mcf_i2c0_resources,
361};
362#ifdef MCFI2C_BASE1
363
364static struct resource mcf_i2c1_resources[] = {
365	{
366		.start          = MCFI2C_BASE1,
367		.end            = MCFI2C_BASE1 + MCFI2C_SIZE1 - 1,
368		.flags          = IORESOURCE_MEM,
369	},
370	{
371		.start          = MCF_IRQ_I2C1,
372		.end            = MCF_IRQ_I2C1,
373		.flags          = IORESOURCE_IRQ,
374	},
375};
376
377static struct platform_device mcf_i2c1 = {
378	.name                   = "imx1-i2c",
379	.id                     = 1,
380	.num_resources          = ARRAY_SIZE(mcf_i2c1_resources),
381	.resource               = mcf_i2c1_resources,
382};
383
384#endif /* MCFI2C_BASE1 */
385
386#ifdef MCFI2C_BASE2
387
388static struct resource mcf_i2c2_resources[] = {
389	{
390		.start          = MCFI2C_BASE2,
391		.end            = MCFI2C_BASE2 + MCFI2C_SIZE2 - 1,
392		.flags          = IORESOURCE_MEM,
393	},
394	{
395		.start          = MCF_IRQ_I2C2,
396		.end            = MCF_IRQ_I2C2,
397		.flags          = IORESOURCE_IRQ,
398	},
399};
400
401static struct platform_device mcf_i2c2 = {
402	.name                   = "imx1-i2c",
403	.id                     = 2,
404	.num_resources          = ARRAY_SIZE(mcf_i2c2_resources),
405	.resource               = mcf_i2c2_resources,
406};
407
408#endif /* MCFI2C_BASE2 */
409
410#ifdef MCFI2C_BASE3
411
412static struct resource mcf_i2c3_resources[] = {
413	{
414		.start          = MCFI2C_BASE3,
415		.end            = MCFI2C_BASE3 + MCFI2C_SIZE3 - 1,
416		.flags          = IORESOURCE_MEM,
417	},
418	{
419		.start          = MCF_IRQ_I2C3,
420		.end            = MCF_IRQ_I2C3,
421		.flags          = IORESOURCE_IRQ,
422	},
423};
424
425static struct platform_device mcf_i2c3 = {
426	.name                   = "imx1-i2c",
427	.id                     = 3,
428	.num_resources          = ARRAY_SIZE(mcf_i2c3_resources),
429	.resource               = mcf_i2c3_resources,
430};
431
432#endif /* MCFI2C_BASE3 */
433
434#ifdef MCFI2C_BASE4
435
436static struct resource mcf_i2c4_resources[] = {
437	{
438		.start          = MCFI2C_BASE4,
439		.end            = MCFI2C_BASE4 + MCFI2C_SIZE4 - 1,
440		.flags          = IORESOURCE_MEM,
441	},
442	{
443		.start          = MCF_IRQ_I2C4,
444		.end            = MCF_IRQ_I2C4,
445		.flags          = IORESOURCE_IRQ,
446	},
447};
448
449static struct platform_device mcf_i2c4 = {
450	.name                   = "imx1-i2c",
451	.id                     = 4,
452	.num_resources          = ARRAY_SIZE(mcf_i2c4_resources),
453	.resource               = mcf_i2c4_resources,
454};
455
456#endif /* MCFI2C_BASE4 */
457
458#ifdef MCFI2C_BASE5
459
460static struct resource mcf_i2c5_resources[] = {
461	{
462		.start          = MCFI2C_BASE5,
463		.end            = MCFI2C_BASE5 + MCFI2C_SIZE5 - 1,
464		.flags          = IORESOURCE_MEM,
465	},
466	{
467		.start          = MCF_IRQ_I2C5,
468		.end            = MCF_IRQ_I2C5,
469		.flags          = IORESOURCE_IRQ,
470	},
471};
472
473static struct platform_device mcf_i2c5 = {
474	.name                   = "imx1-i2c",
475	.id                     = 5,
476	.num_resources          = ARRAY_SIZE(mcf_i2c5_resources),
477	.resource               = mcf_i2c5_resources,
478};
479
480#endif /* MCFI2C_BASE5 */
481#endif /* IS_ENABLED(CONFIG_I2C_IMX) */
482
483#ifdef MCFEDMA_BASE
484
485static const struct dma_slave_map mcf_edma_map[] = {
486	{ "dreq0", "rx-tx", MCF_EDMA_FILTER_PARAM(0) },
487	{ "dreq1", "rx-tx", MCF_EDMA_FILTER_PARAM(1) },
488	{ "uart.0", "rx", MCF_EDMA_FILTER_PARAM(2) },
489	{ "uart.0", "tx", MCF_EDMA_FILTER_PARAM(3) },
490	{ "uart.1", "rx", MCF_EDMA_FILTER_PARAM(4) },
491	{ "uart.1", "tx", MCF_EDMA_FILTER_PARAM(5) },
492	{ "uart.2", "rx", MCF_EDMA_FILTER_PARAM(6) },
493	{ "uart.2", "tx", MCF_EDMA_FILTER_PARAM(7) },
494	{ "timer0", "rx-tx", MCF_EDMA_FILTER_PARAM(8) },
495	{ "timer1", "rx-tx", MCF_EDMA_FILTER_PARAM(9) },
496	{ "timer2", "rx-tx", MCF_EDMA_FILTER_PARAM(10) },
497	{ "timer3", "rx-tx", MCF_EDMA_FILTER_PARAM(11) },
498	{ "fsl-dspi.0", "rx", MCF_EDMA_FILTER_PARAM(12) },
499	{ "fsl-dspi.0", "tx", MCF_EDMA_FILTER_PARAM(13) },
500	{ "fsl-dspi.1", "rx", MCF_EDMA_FILTER_PARAM(14) },
501	{ "fsl-dspi.1", "tx", MCF_EDMA_FILTER_PARAM(15) },
502};
503
504static struct mcf_edma_platform_data mcf_edma_data = {
505	.dma_channels		= 64,
506	.slave_map		= mcf_edma_map,
507	.slavecnt		= ARRAY_SIZE(mcf_edma_map),
508};
509
510static struct resource mcf_edma_resources[] = {
511	{
512		.start		= MCFEDMA_BASE,
513		.end		= MCFEDMA_BASE + MCFEDMA_SIZE - 1,
514		.flags		= IORESOURCE_MEM,
515	},
516	{
517		.start		= MCFEDMA_IRQ_INTR0,
518		.end		= MCFEDMA_IRQ_INTR0 + 15,
519		.flags		= IORESOURCE_IRQ,
520		.name		= "edma-tx-00-15",
521	},
522	{
523		.start		= MCFEDMA_IRQ_INTR16,
524		.end		= MCFEDMA_IRQ_INTR16 + 39,
525		.flags		= IORESOURCE_IRQ,
526		.name		= "edma-tx-16-55",
527	},
528	{
529		.start		= MCFEDMA_IRQ_INTR56,
530		.end		= MCFEDMA_IRQ_INTR56,
531		.flags		= IORESOURCE_IRQ,
532		.name		= "edma-tx-56-63",
533	},
534	{
535		.start		= MCFEDMA_IRQ_ERR,
536		.end		= MCFEDMA_IRQ_ERR,
537		.flags		= IORESOURCE_IRQ,
538		.name		= "edma-err",
539	},
540};
541
542static u64 mcf_edma_dmamask = DMA_BIT_MASK(32);
543
544static struct platform_device mcf_edma = {
545	.name			= "mcf-edma",
546	.id			= 0,
547	.num_resources		= ARRAY_SIZE(mcf_edma_resources),
548	.resource		= mcf_edma_resources,
549	.dev = {
550		.dma_mask = &mcf_edma_dmamask,
551		.coherent_dma_mask = DMA_BIT_MASK(32),
552		.platform_data = &mcf_edma_data,
553	}
554};
555#endif /* MCFEDMA_BASE */
556
557#ifdef MCFSDHC_BASE
558static struct mcf_esdhc_platform_data mcf_esdhc_data = {
559	.max_bus_width = 4,
560	.cd_type = ESDHC_CD_NONE,
561};
562
563static struct resource mcf_esdhc_resources[] = {
564	{
565		.start = MCFSDHC_BASE,
566		.end = MCFSDHC_BASE + MCFSDHC_SIZE - 1,
567		.flags = IORESOURCE_MEM,
568	}, {
569		.start = MCF_IRQ_SDHC,
570		.end = MCF_IRQ_SDHC,
571		.flags = IORESOURCE_IRQ,
572	},
573};
574
575static struct platform_device mcf_esdhc = {
576	.name			= "sdhci-esdhc-mcf",
577	.id			= 0,
578	.num_resources		= ARRAY_SIZE(mcf_esdhc_resources),
579	.resource		= mcf_esdhc_resources,
580	.dev.platform_data	= &mcf_esdhc_data,
581};
582#endif /* MCFSDHC_BASE */
583
584#ifdef MCFFLEXCAN_SIZE
585
586#include <linux/can/platform/flexcan.h>
587
588static struct flexcan_platform_data mcf5441x_flexcan_info = {
589	.clk_src = 1,
590	.clock_frequency = 120000000,
591};
592
593static struct resource mcf5441x_flexcan0_resource[] = {
594	{
595		.start = MCFFLEXCAN_BASE0,
596		.end = MCFFLEXCAN_BASE0 + MCFFLEXCAN_SIZE,
597		.flags = IORESOURCE_MEM,
598	},
599	{
600		.start = MCF_IRQ_IFL0,
601		.end = MCF_IRQ_IFL0,
602		.flags = IORESOURCE_IRQ,
603	},
604	{
605		.start = MCF_IRQ_BOFF0,
606		.end = MCF_IRQ_BOFF0,
607		.flags = IORESOURCE_IRQ,
608	},
609	{
610		.start = MCF_IRQ_ERR0,
611		.end = MCF_IRQ_ERR0,
612		.flags = IORESOURCE_IRQ,
613	},
614};
615
616static struct platform_device mcf_flexcan0 = {
617	.name = "flexcan-mcf5441x",
618	.id = 0,
619	.num_resources = ARRAY_SIZE(mcf5441x_flexcan0_resource),
620	.resource = mcf5441x_flexcan0_resource,
621	.dev.platform_data = &mcf5441x_flexcan_info,
622};
623#endif /* MCFFLEXCAN_SIZE */
624
625static struct platform_device *mcf_devices[] __initdata = {
626	&mcf_uart,
627#if IS_ENABLED(CONFIG_FEC)
628	&mcf_fec0,
629#ifdef MCFFEC_BASE1
630	&mcf_fec1,
631#endif
632#endif
633#if IS_ENABLED(CONFIG_SPI_COLDFIRE_QSPI)
634	&mcf_qspi,
635#endif
636#if IS_ENABLED(CONFIG_I2C_IMX)
637	&mcf_i2c0,
638#ifdef MCFI2C_BASE1
639	&mcf_i2c1,
640#endif
641#ifdef MCFI2C_BASE2
642	&mcf_i2c2,
643#endif
644#ifdef MCFI2C_BASE3
645	&mcf_i2c3,
646#endif
647#ifdef MCFI2C_BASE4
648	&mcf_i2c4,
649#endif
650#ifdef MCFI2C_BASE5
651	&mcf_i2c5,
652#endif
653#endif
654#ifdef MCFEDMA_BASE
655	&mcf_edma,
656#endif
657#ifdef MCFSDHC_BASE
658	&mcf_esdhc,
659#endif
660#ifdef MCFFLEXCAN_SIZE
661	&mcf_flexcan0,
662#endif
663};
664
665/*
666 *	Some ColdFire UARTs let you set the IRQ line to use.
667 */
668static void __init mcf_uart_set_irq(void)
669{
670#ifdef MCFUART_UIVR
671	/* UART0 interrupt setup */
672	writeb(MCFSIM_ICR_LEVEL6 | MCFSIM_ICR_PRI1, MCFSIM_UART1ICR);
673	writeb(MCF_IRQ_UART0, MCFUART_BASE0 + MCFUART_UIVR);
674	mcf_mapirq2imr(MCF_IRQ_UART0, MCFINTC_UART0);
675
676	/* UART1 interrupt setup */
677	writeb(MCFSIM_ICR_LEVEL6 | MCFSIM_ICR_PRI2, MCFSIM_UART2ICR);
678	writeb(MCF_IRQ_UART1, MCFUART_BASE1 + MCFUART_UIVR);
679	mcf_mapirq2imr(MCF_IRQ_UART1, MCFINTC_UART1);
680#endif
681}
682
683static int __init mcf_init_devices(void)
684{
685	mcf_uart_set_irq();
686	platform_add_devices(mcf_devices, ARRAY_SIZE(mcf_devices));
687	return 0;
688}
689
690arch_initcall(mcf_init_devices);
691