diff options
Diffstat (limited to 'arch/m68k/coldfire/device.c')
-rw-r--r-- | arch/m68k/coldfire/device.c | 369 |
1 files changed, 369 insertions, 0 deletions
diff --git a/arch/m68k/coldfire/device.c b/arch/m68k/coldfire/device.c new file mode 100644 index 000000000000..71ea4c02795d --- /dev/null +++ b/arch/m68k/coldfire/device.c | |||
@@ -0,0 +1,369 @@ | |||
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 <asm/traps.h> | ||
18 | #include <asm/coldfire.h> | ||
19 | #include <asm/mcfsim.h> | ||
20 | #include <asm/mcfuart.h> | ||
21 | #include <asm/mcfqspi.h> | ||
22 | |||
23 | /* | ||
24 | * All current ColdFire parts contain from 2, 3, 4 or 10 UARTS. | ||
25 | */ | ||
26 | static struct mcf_platform_uart mcf_uart_platform_data[] = { | ||
27 | { | ||
28 | .mapbase = MCFUART_BASE0, | ||
29 | .irq = MCF_IRQ_UART0, | ||
30 | }, | ||
31 | { | ||
32 | .mapbase = MCFUART_BASE1, | ||
33 | .irq = MCF_IRQ_UART1, | ||
34 | }, | ||
35 | #ifdef MCFUART_BASE2 | ||
36 | { | ||
37 | .mapbase = MCFUART_BASE2, | ||
38 | .irq = MCF_IRQ_UART2, | ||
39 | }, | ||
40 | #endif | ||
41 | #ifdef MCFUART_BASE3 | ||
42 | { | ||
43 | .mapbase = MCFUART_BASE3, | ||
44 | .irq = MCF_IRQ_UART3, | ||
45 | }, | ||
46 | #endif | ||
47 | #ifdef MCFUART_BASE4 | ||
48 | { | ||
49 | .mapbase = MCFUART_BASE4, | ||
50 | .irq = MCF_IRQ_UART4, | ||
51 | }, | ||
52 | #endif | ||
53 | #ifdef MCFUART_BASE5 | ||
54 | { | ||
55 | .mapbase = MCFUART_BASE5, | ||
56 | .irq = MCF_IRQ_UART5, | ||
57 | }, | ||
58 | #endif | ||
59 | #ifdef MCFUART_BASE6 | ||
60 | { | ||
61 | .mapbase = MCFUART_BASE6, | ||
62 | .irq = MCF_IRQ_UART6, | ||
63 | }, | ||
64 | #endif | ||
65 | #ifdef MCFUART_BASE7 | ||
66 | { | ||
67 | .mapbase = MCFUART_BASE7, | ||
68 | .irq = MCF_IRQ_UART7, | ||
69 | }, | ||
70 | #endif | ||
71 | #ifdef MCFUART_BASE8 | ||
72 | { | ||
73 | .mapbase = MCFUART_BASE8, | ||
74 | .irq = MCF_IRQ_UART8, | ||
75 | }, | ||
76 | #endif | ||
77 | #ifdef MCFUART_BASE9 | ||
78 | { | ||
79 | .mapbase = MCFUART_BASE9, | ||
80 | .irq = MCF_IRQ_UART9, | ||
81 | }, | ||
82 | #endif | ||
83 | { }, | ||
84 | }; | ||
85 | |||
86 | static struct platform_device mcf_uart = { | ||
87 | .name = "mcfuart", | ||
88 | .id = 0, | ||
89 | .dev.platform_data = mcf_uart_platform_data, | ||
90 | }; | ||
91 | |||
92 | #ifdef CONFIG_FEC | ||
93 | |||
94 | #ifdef CONFIG_M5441x | ||
95 | #define FEC_NAME "enet-fec" | ||
96 | static struct fec_platform_data fec_pdata = { | ||
97 | .phy = PHY_INTERFACE_MODE_RMII, | ||
98 | }; | ||
99 | #define FEC_PDATA (&fec_pdata) | ||
100 | #else | ||
101 | #define FEC_NAME "fec" | ||
102 | #define FEC_PDATA NULL | ||
103 | #endif | ||
104 | |||
105 | /* | ||
106 | * Some ColdFire cores contain the Fast Ethernet Controller (FEC) | ||
107 | * block. It is Freescale's own hardware block. Some ColdFires | ||
108 | * have 2 of these. | ||
109 | */ | ||
110 | static struct resource mcf_fec0_resources[] = { | ||
111 | { | ||
112 | .start = MCFFEC_BASE0, | ||
113 | .end = MCFFEC_BASE0 + MCFFEC_SIZE0 - 1, | ||
114 | .flags = IORESOURCE_MEM, | ||
115 | }, | ||
116 | { | ||
117 | .start = MCF_IRQ_FECRX0, | ||
118 | .end = MCF_IRQ_FECRX0, | ||
119 | .flags = IORESOURCE_IRQ, | ||
120 | }, | ||
121 | { | ||
122 | .start = MCF_IRQ_FECTX0, | ||
123 | .end = MCF_IRQ_FECTX0, | ||
124 | .flags = IORESOURCE_IRQ, | ||
125 | }, | ||
126 | { | ||
127 | .start = MCF_IRQ_FECENTC0, | ||
128 | .end = MCF_IRQ_FECENTC0, | ||
129 | .flags = IORESOURCE_IRQ, | ||
130 | }, | ||
131 | }; | ||
132 | |||
133 | static struct platform_device mcf_fec0 = { | ||
134 | .name = FEC_NAME, | ||
135 | .id = 0, | ||
136 | .num_resources = ARRAY_SIZE(mcf_fec0_resources), | ||
137 | .resource = mcf_fec0_resources, | ||
138 | .dev.platform_data = FEC_PDATA, | ||
139 | }; | ||
140 | |||
141 | #ifdef MCFFEC_BASE1 | ||
142 | static struct resource mcf_fec1_resources[] = { | ||
143 | { | ||
144 | .start = MCFFEC_BASE1, | ||
145 | .end = MCFFEC_BASE1 + MCFFEC_SIZE1 - 1, | ||
146 | .flags = IORESOURCE_MEM, | ||
147 | }, | ||
148 | { | ||
149 | .start = MCF_IRQ_FECRX1, | ||
150 | .end = MCF_IRQ_FECRX1, | ||
151 | .flags = IORESOURCE_IRQ, | ||
152 | }, | ||
153 | { | ||
154 | .start = MCF_IRQ_FECTX1, | ||
155 | .end = MCF_IRQ_FECTX1, | ||
156 | .flags = IORESOURCE_IRQ, | ||
157 | }, | ||
158 | { | ||
159 | .start = MCF_IRQ_FECENTC1, | ||
160 | .end = MCF_IRQ_FECENTC1, | ||
161 | .flags = IORESOURCE_IRQ, | ||
162 | }, | ||
163 | }; | ||
164 | |||
165 | static struct platform_device mcf_fec1 = { | ||
166 | .name = FEC_NAME, | ||
167 | .id = 1, | ||
168 | .num_resources = ARRAY_SIZE(mcf_fec1_resources), | ||
169 | .resource = mcf_fec1_resources, | ||
170 | .dev.platform_data = FEC_PDATA, | ||
171 | }; | ||
172 | #endif /* MCFFEC_BASE1 */ | ||
173 | #endif /* CONFIG_FEC */ | ||
174 | |||
175 | #if IS_ENABLED(CONFIG_SPI_COLDFIRE_QSPI) | ||
176 | /* | ||
177 | * The ColdFire QSPI module is an SPI protocol hardware block used | ||
178 | * on a number of different ColdFire CPUs. | ||
179 | */ | ||
180 | static struct resource mcf_qspi_resources[] = { | ||
181 | { | ||
182 | .start = MCFQSPI_BASE, | ||
183 | .end = MCFQSPI_BASE + MCFQSPI_SIZE - 1, | ||
184 | .flags = IORESOURCE_MEM, | ||
185 | }, | ||
186 | { | ||
187 | .start = MCF_IRQ_QSPI, | ||
188 | .end = MCF_IRQ_QSPI, | ||
189 | .flags = IORESOURCE_IRQ, | ||
190 | }, | ||
191 | }; | ||
192 | |||
193 | static int mcf_cs_setup(struct mcfqspi_cs_control *cs_control) | ||
194 | { | ||
195 | int status; | ||
196 | |||
197 | status = gpio_request(MCFQSPI_CS0, "MCFQSPI_CS0"); | ||
198 | if (status) { | ||
199 | pr_debug("gpio_request for MCFQSPI_CS0 failed\n"); | ||
200 | goto fail0; | ||
201 | } | ||
202 | status = gpio_direction_output(MCFQSPI_CS0, 1); | ||
203 | if (status) { | ||
204 | pr_debug("gpio_direction_output for MCFQSPI_CS0 failed\n"); | ||
205 | goto fail1; | ||
206 | } | ||
207 | |||
208 | status = gpio_request(MCFQSPI_CS1, "MCFQSPI_CS1"); | ||
209 | if (status) { | ||
210 | pr_debug("gpio_request for MCFQSPI_CS1 failed\n"); | ||
211 | goto fail1; | ||
212 | } | ||
213 | status = gpio_direction_output(MCFQSPI_CS1, 1); | ||
214 | if (status) { | ||
215 | pr_debug("gpio_direction_output for MCFQSPI_CS1 failed\n"); | ||
216 | goto fail2; | ||
217 | } | ||
218 | |||
219 | status = gpio_request(MCFQSPI_CS2, "MCFQSPI_CS2"); | ||
220 | if (status) { | ||
221 | pr_debug("gpio_request for MCFQSPI_CS2 failed\n"); | ||
222 | goto fail2; | ||
223 | } | ||
224 | status = gpio_direction_output(MCFQSPI_CS2, 1); | ||
225 | if (status) { | ||
226 | pr_debug("gpio_direction_output for MCFQSPI_CS2 failed\n"); | ||
227 | goto fail3; | ||
228 | } | ||
229 | |||
230 | #ifdef MCFQSPI_CS3 | ||
231 | status = gpio_request(MCFQSPI_CS3, "MCFQSPI_CS3"); | ||
232 | if (status) { | ||
233 | pr_debug("gpio_request for MCFQSPI_CS3 failed\n"); | ||
234 | goto fail3; | ||
235 | } | ||
236 | status = gpio_direction_output(MCFQSPI_CS3, 1); | ||
237 | if (status) { | ||
238 | pr_debug("gpio_direction_output for MCFQSPI_CS3 failed\n"); | ||
239 | gpio_free(MCFQSPI_CS3); | ||
240 | goto fail3; | ||
241 | } | ||
242 | #endif | ||
243 | |||
244 | return 0; | ||
245 | |||
246 | fail3: | ||
247 | gpio_free(MCFQSPI_CS2); | ||
248 | fail2: | ||
249 | gpio_free(MCFQSPI_CS1); | ||
250 | fail1: | ||
251 | gpio_free(MCFQSPI_CS0); | ||
252 | fail0: | ||
253 | return status; | ||
254 | } | ||
255 | |||
256 | static void mcf_cs_teardown(struct mcfqspi_cs_control *cs_control) | ||
257 | { | ||
258 | #ifdef MCFQSPI_CS3 | ||
259 | gpio_free(MCFQSPI_CS3); | ||
260 | #endif | ||
261 | gpio_free(MCFQSPI_CS2); | ||
262 | gpio_free(MCFQSPI_CS1); | ||
263 | gpio_free(MCFQSPI_CS0); | ||
264 | } | ||
265 | |||
266 | static void mcf_cs_select(struct mcfqspi_cs_control *cs_control, | ||
267 | u8 chip_select, bool cs_high) | ||
268 | { | ||
269 | switch (chip_select) { | ||
270 | case 0: | ||
271 | gpio_set_value(MCFQSPI_CS0, cs_high); | ||
272 | break; | ||
273 | case 1: | ||
274 | gpio_set_value(MCFQSPI_CS1, cs_high); | ||
275 | break; | ||
276 | case 2: | ||
277 | gpio_set_value(MCFQSPI_CS2, cs_high); | ||
278 | break; | ||
279 | #ifdef MCFQSPI_CS3 | ||
280 | case 3: | ||
281 | gpio_set_value(MCFQSPI_CS3, cs_high); | ||
282 | break; | ||
283 | #endif | ||
284 | } | ||
285 | } | ||
286 | |||
287 | static void mcf_cs_deselect(struct mcfqspi_cs_control *cs_control, | ||
288 | u8 chip_select, bool cs_high) | ||
289 | { | ||
290 | switch (chip_select) { | ||
291 | case 0: | ||
292 | gpio_set_value(MCFQSPI_CS0, !cs_high); | ||
293 | break; | ||
294 | case 1: | ||
295 | gpio_set_value(MCFQSPI_CS1, !cs_high); | ||
296 | break; | ||
297 | case 2: | ||
298 | gpio_set_value(MCFQSPI_CS2, !cs_high); | ||
299 | break; | ||
300 | #ifdef MCFQSPI_CS3 | ||
301 | case 3: | ||
302 | gpio_set_value(MCFQSPI_CS3, !cs_high); | ||
303 | break; | ||
304 | #endif | ||
305 | } | ||
306 | } | ||
307 | |||
308 | static struct mcfqspi_cs_control mcf_cs_control = { | ||
309 | .setup = mcf_cs_setup, | ||
310 | .teardown = mcf_cs_teardown, | ||
311 | .select = mcf_cs_select, | ||
312 | .deselect = mcf_cs_deselect, | ||
313 | }; | ||
314 | |||
315 | static struct mcfqspi_platform_data mcf_qspi_data = { | ||
316 | .bus_num = 0, | ||
317 | .num_chipselect = 4, | ||
318 | .cs_control = &mcf_cs_control, | ||
319 | }; | ||
320 | |||
321 | static struct platform_device mcf_qspi = { | ||
322 | .name = "mcfqspi", | ||
323 | .id = 0, | ||
324 | .num_resources = ARRAY_SIZE(mcf_qspi_resources), | ||
325 | .resource = mcf_qspi_resources, | ||
326 | .dev.platform_data = &mcf_qspi_data, | ||
327 | }; | ||
328 | #endif /* IS_ENABLED(CONFIG_SPI_COLDFIRE_QSPI) */ | ||
329 | |||
330 | static struct platform_device *mcf_devices[] __initdata = { | ||
331 | &mcf_uart, | ||
332 | #ifdef CONFIG_FEC | ||
333 | &mcf_fec0, | ||
334 | #ifdef MCFFEC_BASE1 | ||
335 | &mcf_fec1, | ||
336 | #endif | ||
337 | #endif | ||
338 | #if IS_ENABLED(CONFIG_SPI_COLDFIRE_QSPI) | ||
339 | &mcf_qspi, | ||
340 | #endif | ||
341 | }; | ||
342 | |||
343 | /* | ||
344 | * Some ColdFire UARTs let you set the IRQ line to use. | ||
345 | */ | ||
346 | static void __init mcf_uart_set_irq(void) | ||
347 | { | ||
348 | #ifdef MCFUART_UIVR | ||
349 | /* UART0 interrupt setup */ | ||
350 | writeb(MCFSIM_ICR_LEVEL6 | MCFSIM_ICR_PRI1, MCFSIM_UART1ICR); | ||
351 | writeb(MCF_IRQ_UART0, MCFUART_BASE0 + MCFUART_UIVR); | ||
352 | mcf_mapirq2imr(MCF_IRQ_UART0, MCFINTC_UART0); | ||
353 | |||
354 | /* UART1 interrupt setup */ | ||
355 | writeb(MCFSIM_ICR_LEVEL6 | MCFSIM_ICR_PRI2, MCFSIM_UART2ICR); | ||
356 | writeb(MCF_IRQ_UART1, MCFUART_BASE1 + MCFUART_UIVR); | ||
357 | mcf_mapirq2imr(MCF_IRQ_UART1, MCFINTC_UART1); | ||
358 | #endif | ||
359 | } | ||
360 | |||
361 | static int __init mcf_init_devices(void) | ||
362 | { | ||
363 | mcf_uart_set_irq(); | ||
364 | platform_add_devices(mcf_devices, ARRAY_SIZE(mcf_devices)); | ||
365 | return 0; | ||
366 | } | ||
367 | |||
368 | arch_initcall(mcf_init_devices); | ||
369 | |||