Commit | Line | Data |
---|---|---|
0d2fe946 GU |
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> | |
fa1fc246 GU |
14 | #include <linux/spi/spi.h> |
15 | #include <linux/gpio.h> | |
bea8bcb1 | 16 | #include <linux/fec.h> |
0d2fe946 GU |
17 | #include <asm/traps.h> |
18 | #include <asm/coldfire.h> | |
19 | #include <asm/mcfsim.h> | |
20 | #include <asm/mcfuart.h> | |
fa1fc246 | 21 | #include <asm/mcfqspi.h> |
0d2fe946 | 22 | |
b7ce7f0d | 23 | /* |
bea8bcb1 | 24 | * All current ColdFire parts contain from 2, 3, 4 or 10 UARTS. |
b7ce7f0d | 25 | */ |
0d2fe946 GU |
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 | }, | |
bea8bcb1 SK |
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 | }, | |
0d2fe946 GU |
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 | ||
ca6fafd1 | 92 | #if IS_ENABLED(CONFIG_FEC) |
bea8bcb1 SK |
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 | ||
b7ce7f0d GU |
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 = { | |
bea8bcb1 | 134 | .name = FEC_NAME, |
b7ce7f0d GU |
135 | .id = 0, |
136 | .num_resources = ARRAY_SIZE(mcf_fec0_resources), | |
137 | .resource = mcf_fec0_resources, | |
bea8bcb1 | 138 | .dev.platform_data = FEC_PDATA, |
b7ce7f0d GU |
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 = { | |
bea8bcb1 | 166 | .name = FEC_NAME, |
bfdd769a | 167 | .id = 1, |
b7ce7f0d GU |
168 | .num_resources = ARRAY_SIZE(mcf_fec1_resources), |
169 | .resource = mcf_fec1_resources, | |
bea8bcb1 | 170 | .dev.platform_data = FEC_PDATA, |
b7ce7f0d GU |
171 | }; |
172 | #endif /* MCFFEC_BASE1 */ | |
173 | #endif /* CONFIG_FEC */ | |
174 | ||
83ca6009 | 175 | #if IS_ENABLED(CONFIG_SPI_COLDFIRE_QSPI) |
fa1fc246 GU |
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 | }; | |
83ca6009 | 328 | #endif /* IS_ENABLED(CONFIG_SPI_COLDFIRE_QSPI) */ |
fa1fc246 | 329 | |
0d2fe946 GU |
330 | static struct platform_device *mcf_devices[] __initdata = { |
331 | &mcf_uart, | |
ca6fafd1 | 332 | #if IS_ENABLED(CONFIG_FEC) |
b7ce7f0d GU |
333 | &mcf_fec0, |
334 | #ifdef MCFFEC_BASE1 | |
335 | &mcf_fec1, | |
336 | #endif | |
337 | #endif | |
83ca6009 | 338 | #if IS_ENABLED(CONFIG_SPI_COLDFIRE_QSPI) |
fa1fc246 GU |
339 | &mcf_qspi, |
340 | #endif | |
0d2fe946 GU |
341 | }; |
342 | ||
55148f6f GU |
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 */ | |
c986a3d5 | 350 | writeb(MCFSIM_ICR_LEVEL6 | MCFSIM_ICR_PRI1, MCFSIM_UART1ICR); |
55148f6f GU |
351 | writeb(MCF_IRQ_UART0, MCFUART_BASE0 + MCFUART_UIVR); |
352 | mcf_mapirq2imr(MCF_IRQ_UART0, MCFINTC_UART0); | |
353 | ||
354 | /* UART1 interrupt setup */ | |
c986a3d5 | 355 | writeb(MCFSIM_ICR_LEVEL6 | MCFSIM_ICR_PRI2, MCFSIM_UART2ICR); |
55148f6f GU |
356 | writeb(MCF_IRQ_UART1, MCFUART_BASE1 + MCFUART_UIVR); |
357 | mcf_mapirq2imr(MCF_IRQ_UART1, MCFINTC_UART1); | |
358 | #endif | |
359 | } | |
360 | ||
0d2fe946 GU |
361 | static int __init mcf_init_devices(void) |
362 | { | |
55148f6f | 363 | mcf_uart_set_irq(); |
0d2fe946 GU |
364 | platform_add_devices(mcf_devices, ARRAY_SIZE(mcf_devices)); |
365 | return 0; | |
366 | } | |
367 | ||
368 | arch_initcall(mcf_init_devices); | |
369 |