1 | // SPDX-License-Identifier: GPL-2.0-or-later |
2 | /* |
3 | * Copyright (C) 2006,2007 Felix Fietkau <nbd@openwrt.org> |
4 | * Copyright (C) 2006,2007 Eugene Konev <ejka@openwrt.org> |
5 | */ |
6 | |
7 | #include <linux/init.h> |
8 | #include <linux/types.h> |
9 | #include <linux/delay.h> |
10 | #include <linux/dma-mapping.h> |
11 | #include <linux/platform_device.h> |
12 | #include <linux/mtd/physmap.h> |
13 | #include <linux/serial.h> |
14 | #include <linux/serial_8250.h> |
15 | #include <linux/ioport.h> |
16 | #include <linux/io.h> |
17 | #include <linux/vlynq.h> |
18 | #include <linux/leds.h> |
19 | #include <linux/string.h> |
20 | #include <linux/etherdevice.h> |
21 | #include <linux/phy.h> |
22 | #include <linux/phy_fixed.h> |
23 | #include <linux/gpio.h> |
24 | #include <linux/clk.h> |
25 | |
26 | #include <asm/addrspace.h> |
27 | #include <asm/mach-ar7/ar7.h> |
28 | #include <asm/mach-ar7/prom.h> |
29 | |
30 | /***************************************************************************** |
31 | * VLYNQ Bus |
32 | ****************************************************************************/ |
33 | struct plat_vlynq_data { |
34 | struct plat_vlynq_ops ops; |
35 | int gpio_bit; |
36 | int reset_bit; |
37 | }; |
38 | |
39 | static int vlynq_on(struct vlynq_device *dev) |
40 | { |
41 | int ret; |
42 | struct plat_vlynq_data *pdata = dev->dev.platform_data; |
43 | |
44 | ret = gpio_request(gpio: pdata->gpio_bit, label: "vlynq" ); |
45 | if (ret) |
46 | goto out; |
47 | |
48 | ar7_device_reset(pdata->reset_bit); |
49 | |
50 | ret = ar7_gpio_disable(pdata->gpio_bit); |
51 | if (ret) |
52 | goto out_enabled; |
53 | |
54 | ret = ar7_gpio_enable(pdata->gpio_bit); |
55 | if (ret) |
56 | goto out_enabled; |
57 | |
58 | ret = gpio_direction_output(gpio: pdata->gpio_bit, value: 0); |
59 | if (ret) |
60 | goto out_gpio_enabled; |
61 | |
62 | msleep(msecs: 50); |
63 | |
64 | gpio_set_value(gpio: pdata->gpio_bit, value: 1); |
65 | |
66 | msleep(msecs: 50); |
67 | |
68 | return 0; |
69 | |
70 | out_gpio_enabled: |
71 | ar7_gpio_disable(pdata->gpio_bit); |
72 | out_enabled: |
73 | ar7_device_disable(pdata->reset_bit); |
74 | gpio_free(gpio: pdata->gpio_bit); |
75 | out: |
76 | return ret; |
77 | } |
78 | |
79 | static void vlynq_off(struct vlynq_device *dev) |
80 | { |
81 | struct plat_vlynq_data *pdata = dev->dev.platform_data; |
82 | |
83 | ar7_gpio_disable(pdata->gpio_bit); |
84 | gpio_free(gpio: pdata->gpio_bit); |
85 | ar7_device_disable(pdata->reset_bit); |
86 | } |
87 | |
88 | static struct resource vlynq_low_res[] = { |
89 | { |
90 | .name = "regs" , |
91 | .flags = IORESOURCE_MEM, |
92 | .start = AR7_REGS_VLYNQ0, |
93 | .end = AR7_REGS_VLYNQ0 + 0xff, |
94 | }, |
95 | { |
96 | .name = "irq" , |
97 | .flags = IORESOURCE_IRQ, |
98 | .start = 29, |
99 | .end = 29, |
100 | }, |
101 | { |
102 | .name = "mem" , |
103 | .flags = IORESOURCE_MEM, |
104 | .start = 0x04000000, |
105 | .end = 0x04ffffff, |
106 | }, |
107 | { |
108 | .name = "devirq" , |
109 | .flags = IORESOURCE_IRQ, |
110 | .start = 80, |
111 | .end = 111, |
112 | }, |
113 | }; |
114 | |
115 | static struct resource vlynq_high_res[] = { |
116 | { |
117 | .name = "regs" , |
118 | .flags = IORESOURCE_MEM, |
119 | .start = AR7_REGS_VLYNQ1, |
120 | .end = AR7_REGS_VLYNQ1 + 0xff, |
121 | }, |
122 | { |
123 | .name = "irq" , |
124 | .flags = IORESOURCE_IRQ, |
125 | .start = 33, |
126 | .end = 33, |
127 | }, |
128 | { |
129 | .name = "mem" , |
130 | .flags = IORESOURCE_MEM, |
131 | .start = 0x0c000000, |
132 | .end = 0x0cffffff, |
133 | }, |
134 | { |
135 | .name = "devirq" , |
136 | .flags = IORESOURCE_IRQ, |
137 | .start = 112, |
138 | .end = 143, |
139 | }, |
140 | }; |
141 | |
142 | static struct plat_vlynq_data vlynq_low_data = { |
143 | .ops = { |
144 | .on = vlynq_on, |
145 | .off = vlynq_off, |
146 | }, |
147 | .reset_bit = 20, |
148 | .gpio_bit = 18, |
149 | }; |
150 | |
151 | static struct plat_vlynq_data vlynq_high_data = { |
152 | .ops = { |
153 | .on = vlynq_on, |
154 | .off = vlynq_off, |
155 | }, |
156 | .reset_bit = 16, |
157 | .gpio_bit = 19, |
158 | }; |
159 | |
160 | static struct platform_device vlynq_low = { |
161 | .id = 0, |
162 | .name = "vlynq" , |
163 | .dev = { |
164 | .platform_data = &vlynq_low_data, |
165 | }, |
166 | .resource = vlynq_low_res, |
167 | .num_resources = ARRAY_SIZE(vlynq_low_res), |
168 | }; |
169 | |
170 | static struct platform_device vlynq_high = { |
171 | .id = 1, |
172 | .name = "vlynq" , |
173 | .dev = { |
174 | .platform_data = &vlynq_high_data, |
175 | }, |
176 | .resource = vlynq_high_res, |
177 | .num_resources = ARRAY_SIZE(vlynq_high_res), |
178 | }; |
179 | |
180 | /***************************************************************************** |
181 | * Flash |
182 | ****************************************************************************/ |
183 | static struct resource physmap_flash_resource = { |
184 | .name = "mem" , |
185 | .flags = IORESOURCE_MEM, |
186 | .start = 0x10000000, |
187 | .end = 0x107fffff, |
188 | }; |
189 | |
190 | static const char *ar7_probe_types[] = { "ar7part" , NULL }; |
191 | |
192 | static struct physmap_flash_data physmap_flash_data = { |
193 | .width = 2, |
194 | .part_probe_types = ar7_probe_types, |
195 | }; |
196 | |
197 | static struct platform_device physmap_flash = { |
198 | .name = "physmap-flash" , |
199 | .dev = { |
200 | .platform_data = &physmap_flash_data, |
201 | }, |
202 | .resource = &physmap_flash_resource, |
203 | .num_resources = 1, |
204 | }; |
205 | |
206 | /***************************************************************************** |
207 | * Ethernet |
208 | ****************************************************************************/ |
209 | static struct resource cpmac_low_res[] = { |
210 | { |
211 | .name = "regs" , |
212 | .flags = IORESOURCE_MEM, |
213 | .start = AR7_REGS_MAC0, |
214 | .end = AR7_REGS_MAC0 + 0x7ff, |
215 | }, |
216 | { |
217 | .name = "irq" , |
218 | .flags = IORESOURCE_IRQ, |
219 | .start = 27, |
220 | .end = 27, |
221 | }, |
222 | }; |
223 | |
224 | static struct resource cpmac_high_res[] = { |
225 | { |
226 | .name = "regs" , |
227 | .flags = IORESOURCE_MEM, |
228 | .start = AR7_REGS_MAC1, |
229 | .end = AR7_REGS_MAC1 + 0x7ff, |
230 | }, |
231 | { |
232 | .name = "irq" , |
233 | .flags = IORESOURCE_IRQ, |
234 | .start = 41, |
235 | .end = 41, |
236 | }, |
237 | }; |
238 | |
239 | static struct fixed_phy_status fixed_phy_status __initdata = { |
240 | .link = 1, |
241 | .speed = 100, |
242 | .duplex = 1, |
243 | }; |
244 | |
245 | static struct plat_cpmac_data cpmac_low_data = { |
246 | .reset_bit = 17, |
247 | .power_bit = 20, |
248 | .phy_mask = 0x80000000, |
249 | }; |
250 | |
251 | static struct plat_cpmac_data cpmac_high_data = { |
252 | .reset_bit = 21, |
253 | .power_bit = 22, |
254 | .phy_mask = 0x7fffffff, |
255 | }; |
256 | |
257 | static u64 cpmac_dma_mask = DMA_BIT_MASK(32); |
258 | |
259 | static struct platform_device cpmac_low = { |
260 | .id = 0, |
261 | .name = "cpmac" , |
262 | .dev = { |
263 | .dma_mask = &cpmac_dma_mask, |
264 | .coherent_dma_mask = DMA_BIT_MASK(32), |
265 | .platform_data = &cpmac_low_data, |
266 | }, |
267 | .resource = cpmac_low_res, |
268 | .num_resources = ARRAY_SIZE(cpmac_low_res), |
269 | }; |
270 | |
271 | static struct platform_device cpmac_high = { |
272 | .id = 1, |
273 | .name = "cpmac" , |
274 | .dev = { |
275 | .dma_mask = &cpmac_dma_mask, |
276 | .coherent_dma_mask = DMA_BIT_MASK(32), |
277 | .platform_data = &cpmac_high_data, |
278 | }, |
279 | .resource = cpmac_high_res, |
280 | .num_resources = ARRAY_SIZE(cpmac_high_res), |
281 | }; |
282 | |
283 | static void __init cpmac_get_mac(int instance, unsigned char *dev_addr) |
284 | { |
285 | char name[5], *mac; |
286 | |
287 | sprintf(buf: name, fmt: "mac%c" , 'a' + instance); |
288 | mac = prom_getenv(name); |
289 | if (!mac && instance) { |
290 | sprintf(buf: name, fmt: "mac%c" , 'a'); |
291 | mac = prom_getenv(name); |
292 | } |
293 | |
294 | if (mac) { |
295 | if (!mac_pton(s: mac, mac: dev_addr)) { |
296 | pr_warn("cannot parse mac address, using random address\n" ); |
297 | eth_random_addr(addr: dev_addr); |
298 | } |
299 | } else |
300 | eth_random_addr(addr: dev_addr); |
301 | } |
302 | |
303 | /***************************************************************************** |
304 | * USB |
305 | ****************************************************************************/ |
306 | static struct resource usb_res[] = { |
307 | { |
308 | .name = "regs" , |
309 | .flags = IORESOURCE_MEM, |
310 | .start = AR7_REGS_USB, |
311 | .end = AR7_REGS_USB + 0xff, |
312 | }, |
313 | { |
314 | .name = "irq" , |
315 | .flags = IORESOURCE_IRQ, |
316 | .start = 32, |
317 | .end = 32, |
318 | }, |
319 | { |
320 | .name = "mem" , |
321 | .flags = IORESOURCE_MEM, |
322 | .start = 0x03400000, |
323 | .end = 0x03401fff, |
324 | }, |
325 | }; |
326 | |
327 | static struct platform_device ar7_udc = { |
328 | .name = "ar7_udc" , |
329 | .resource = usb_res, |
330 | .num_resources = ARRAY_SIZE(usb_res), |
331 | }; |
332 | |
333 | /***************************************************************************** |
334 | * LEDs |
335 | ****************************************************************************/ |
336 | static const struct gpio_led default_leds[] = { |
337 | { |
338 | .name = "status" , |
339 | .gpio = 8, |
340 | .active_low = 1, |
341 | }, |
342 | }; |
343 | |
344 | static const struct gpio_led titan_leds[] = { |
345 | { .name = "status" , .gpio = 8, .active_low = 1, }, |
346 | { .name = "wifi" , .gpio = 13, .active_low = 1, }, |
347 | }; |
348 | |
349 | static const struct gpio_led dsl502t_leds[] = { |
350 | { |
351 | .name = "status" , |
352 | .gpio = 9, |
353 | .active_low = 1, |
354 | }, |
355 | { |
356 | .name = "ethernet" , |
357 | .gpio = 7, |
358 | .active_low = 1, |
359 | }, |
360 | { |
361 | .name = "usb" , |
362 | .gpio = 12, |
363 | .active_low = 1, |
364 | }, |
365 | }; |
366 | |
367 | static const struct gpio_led dg834g_leds[] = { |
368 | { |
369 | .name = "ppp" , |
370 | .gpio = 6, |
371 | .active_low = 1, |
372 | }, |
373 | { |
374 | .name = "status" , |
375 | .gpio = 7, |
376 | .active_low = 1, |
377 | }, |
378 | { |
379 | .name = "adsl" , |
380 | .gpio = 8, |
381 | .active_low = 1, |
382 | }, |
383 | { |
384 | .name = "wifi" , |
385 | .gpio = 12, |
386 | .active_low = 1, |
387 | }, |
388 | { |
389 | .name = "power" , |
390 | .gpio = 14, |
391 | .active_low = 1, |
392 | .default_trigger = "default-on" , |
393 | }, |
394 | }; |
395 | |
396 | static const struct gpio_led fb_sl_leds[] = { |
397 | { |
398 | .name = "1" , |
399 | .gpio = 7, |
400 | }, |
401 | { |
402 | .name = "2" , |
403 | .gpio = 13, |
404 | .active_low = 1, |
405 | }, |
406 | { |
407 | .name = "3" , |
408 | .gpio = 10, |
409 | .active_low = 1, |
410 | }, |
411 | { |
412 | .name = "4" , |
413 | .gpio = 12, |
414 | .active_low = 1, |
415 | }, |
416 | { |
417 | .name = "5" , |
418 | .gpio = 9, |
419 | .active_low = 1, |
420 | }, |
421 | }; |
422 | |
423 | static const struct gpio_led fb_fon_leds[] = { |
424 | { |
425 | .name = "1" , |
426 | .gpio = 8, |
427 | }, |
428 | { |
429 | .name = "2" , |
430 | .gpio = 3, |
431 | .active_low = 1, |
432 | }, |
433 | { |
434 | .name = "3" , |
435 | .gpio = 5, |
436 | }, |
437 | { |
438 | .name = "4" , |
439 | .gpio = 4, |
440 | .active_low = 1, |
441 | }, |
442 | { |
443 | .name = "5" , |
444 | .gpio = 11, |
445 | .active_low = 1, |
446 | }, |
447 | }; |
448 | |
449 | static const struct gpio_led gt701_leds[] = { |
450 | { |
451 | .name = "inet:green" , |
452 | .gpio = 13, |
453 | .active_low = 1, |
454 | }, |
455 | { |
456 | .name = "usb" , |
457 | .gpio = 12, |
458 | .active_low = 1, |
459 | }, |
460 | { |
461 | .name = "inet:red" , |
462 | .gpio = 9, |
463 | .active_low = 1, |
464 | }, |
465 | { |
466 | .name = "power:red" , |
467 | .gpio = 7, |
468 | .active_low = 1, |
469 | }, |
470 | { |
471 | .name = "power:green" , |
472 | .gpio = 8, |
473 | .active_low = 1, |
474 | .default_trigger = "default-on" , |
475 | }, |
476 | { |
477 | .name = "ethernet" , |
478 | .gpio = 10, |
479 | .active_low = 1, |
480 | }, |
481 | }; |
482 | |
483 | static struct gpio_led_platform_data ar7_led_data; |
484 | |
485 | static struct platform_device ar7_gpio_leds = { |
486 | .name = "leds-gpio" , |
487 | .dev = { |
488 | .platform_data = &ar7_led_data, |
489 | } |
490 | }; |
491 | |
492 | static void __init detect_leds(void) |
493 | { |
494 | char *prid, *usb_prod; |
495 | |
496 | /* Default LEDs */ |
497 | ar7_led_data.num_leds = ARRAY_SIZE(default_leds); |
498 | ar7_led_data.leds = default_leds; |
499 | |
500 | /* FIXME: the whole thing is unreliable */ |
501 | prid = prom_getenv("ProductID" ); |
502 | usb_prod = prom_getenv("usb_prod" ); |
503 | |
504 | /* If we can't get the product id from PROM, use the default LEDs */ |
505 | if (!prid) |
506 | return; |
507 | |
508 | if (strstr(prid, "Fritz_Box_FON" )) { |
509 | ar7_led_data.num_leds = ARRAY_SIZE(fb_fon_leds); |
510 | ar7_led_data.leds = fb_fon_leds; |
511 | } else if (strstr(prid, "Fritz_Box_" )) { |
512 | ar7_led_data.num_leds = ARRAY_SIZE(fb_sl_leds); |
513 | ar7_led_data.leds = fb_sl_leds; |
514 | } else if ((!strcmp(prid, "AR7RD" ) || !strcmp(prid, "AR7DB" )) |
515 | && usb_prod != NULL && strstr(usb_prod, "DSL-502T" )) { |
516 | ar7_led_data.num_leds = ARRAY_SIZE(dsl502t_leds); |
517 | ar7_led_data.leds = dsl502t_leds; |
518 | } else if (strstr(prid, "DG834" )) { |
519 | ar7_led_data.num_leds = ARRAY_SIZE(dg834g_leds); |
520 | ar7_led_data.leds = dg834g_leds; |
521 | } else if (strstr(prid, "CYWM" ) || strstr(prid, "CYWL" )) { |
522 | ar7_led_data.num_leds = ARRAY_SIZE(titan_leds); |
523 | ar7_led_data.leds = titan_leds; |
524 | } else if (strstr(prid, "GT701" )) { |
525 | ar7_led_data.num_leds = ARRAY_SIZE(gt701_leds); |
526 | ar7_led_data.leds = gt701_leds; |
527 | } |
528 | } |
529 | |
530 | /***************************************************************************** |
531 | * Watchdog |
532 | ****************************************************************************/ |
533 | static struct resource ar7_wdt_res = { |
534 | .name = "regs" , |
535 | .flags = IORESOURCE_MEM, |
536 | .start = -1, /* Filled at runtime */ |
537 | .end = -1, /* Filled at runtime */ |
538 | }; |
539 | |
540 | static struct platform_device ar7_wdt = { |
541 | .name = "ar7_wdt" , |
542 | .resource = &ar7_wdt_res, |
543 | .num_resources = 1, |
544 | }; |
545 | |
546 | /***************************************************************************** |
547 | * Init |
548 | ****************************************************************************/ |
549 | static int __init ar7_register_uarts(void) |
550 | { |
551 | #ifdef CONFIG_SERIAL_8250 |
552 | static struct uart_port uart_port __initdata; |
553 | struct clk *bus_clk; |
554 | int res; |
555 | |
556 | memset(&uart_port, 0, sizeof(struct uart_port)); |
557 | |
558 | bus_clk = clk_get(NULL, id: "bus" ); |
559 | if (IS_ERR(ptr: bus_clk)) |
560 | panic(fmt: "unable to get bus clk" ); |
561 | |
562 | uart_port.type = PORT_AR7; |
563 | uart_port.uartclk = clk_get_rate(clk: bus_clk) / 2; |
564 | uart_port.iotype = UPIO_MEM32; |
565 | uart_port.flags = UPF_FIXED_TYPE | UPF_BOOT_AUTOCONF; |
566 | uart_port.regshift = 2; |
567 | |
568 | uart_port.line = 0; |
569 | uart_port.irq = AR7_IRQ_UART0; |
570 | uart_port.mapbase = AR7_REGS_UART0; |
571 | uart_port.membase = ioremap(offset: uart_port.mapbase, size: 256); |
572 | |
573 | res = early_serial_setup(port: &uart_port); |
574 | if (res) |
575 | return res; |
576 | |
577 | /* Only TNETD73xx have a second serial port */ |
578 | if (ar7_has_second_uart()) { |
579 | uart_port.line = 1; |
580 | uart_port.irq = AR7_IRQ_UART1; |
581 | uart_port.mapbase = UR8_REGS_UART1; |
582 | uart_port.membase = ioremap(offset: uart_port.mapbase, size: 256); |
583 | |
584 | res = early_serial_setup(port: &uart_port); |
585 | if (res) |
586 | return res; |
587 | } |
588 | #endif |
589 | |
590 | return 0; |
591 | } |
592 | |
593 | static void __init titan_fixup_devices(void) |
594 | { |
595 | /* Set vlynq0 data */ |
596 | vlynq_low_data.reset_bit = 15; |
597 | vlynq_low_data.gpio_bit = 14; |
598 | |
599 | /* Set vlynq1 data */ |
600 | vlynq_high_data.reset_bit = 16; |
601 | vlynq_high_data.gpio_bit = 7; |
602 | |
603 | /* Set vlynq0 resources */ |
604 | vlynq_low_res[0].start = TITAN_REGS_VLYNQ0; |
605 | vlynq_low_res[0].end = TITAN_REGS_VLYNQ0 + 0xff; |
606 | vlynq_low_res[1].start = 33; |
607 | vlynq_low_res[1].end = 33; |
608 | vlynq_low_res[2].start = 0x0c000000; |
609 | vlynq_low_res[2].end = 0x0fffffff; |
610 | vlynq_low_res[3].start = 80; |
611 | vlynq_low_res[3].end = 111; |
612 | |
613 | /* Set vlynq1 resources */ |
614 | vlynq_high_res[0].start = TITAN_REGS_VLYNQ1; |
615 | vlynq_high_res[0].end = TITAN_REGS_VLYNQ1 + 0xff; |
616 | vlynq_high_res[1].start = 34; |
617 | vlynq_high_res[1].end = 34; |
618 | vlynq_high_res[2].start = 0x40000000; |
619 | vlynq_high_res[2].end = 0x43ffffff; |
620 | vlynq_high_res[3].start = 112; |
621 | vlynq_high_res[3].end = 143; |
622 | |
623 | /* Set cpmac0 data */ |
624 | cpmac_low_data.phy_mask = 0x40000000; |
625 | |
626 | /* Set cpmac1 data */ |
627 | cpmac_high_data.phy_mask = 0x80000000; |
628 | |
629 | /* Set cpmac0 resources */ |
630 | cpmac_low_res[0].start = TITAN_REGS_MAC0; |
631 | cpmac_low_res[0].end = TITAN_REGS_MAC0 + 0x7ff; |
632 | |
633 | /* Set cpmac1 resources */ |
634 | cpmac_high_res[0].start = TITAN_REGS_MAC1; |
635 | cpmac_high_res[0].end = TITAN_REGS_MAC1 + 0x7ff; |
636 | } |
637 | |
638 | static int __init ar7_register_devices(void) |
639 | { |
640 | void __iomem *bootcr; |
641 | u32 val; |
642 | int res; |
643 | |
644 | res = ar7_gpio_init(); |
645 | if (res) |
646 | pr_warn("unable to register gpios: %d\n" , res); |
647 | |
648 | res = ar7_register_uarts(); |
649 | if (res) |
650 | pr_err("unable to setup uart(s): %d\n" , res); |
651 | |
652 | res = platform_device_register(&physmap_flash); |
653 | if (res) |
654 | pr_warn("unable to register physmap-flash: %d\n" , res); |
655 | |
656 | if (ar7_is_titan()) |
657 | titan_fixup_devices(); |
658 | |
659 | ar7_device_disable(vlynq_low_data.reset_bit); |
660 | res = platform_device_register(&vlynq_low); |
661 | if (res) |
662 | pr_warn("unable to register vlynq-low: %d\n" , res); |
663 | |
664 | if (ar7_has_high_vlynq()) { |
665 | ar7_device_disable(vlynq_high_data.reset_bit); |
666 | res = platform_device_register(&vlynq_high); |
667 | if (res) |
668 | pr_warn("unable to register vlynq-high: %d\n" , res); |
669 | } |
670 | |
671 | if (ar7_has_high_cpmac()) { |
672 | res = fixed_phy_add(PHY_POLL, phy_id: cpmac_high.id, |
673 | status: &fixed_phy_status); |
674 | if (!res) { |
675 | cpmac_get_mac(instance: 1, dev_addr: cpmac_high_data.dev_addr); |
676 | |
677 | res = platform_device_register(&cpmac_high); |
678 | if (res) |
679 | pr_warn("unable to register cpmac-high: %d\n" , |
680 | res); |
681 | } else |
682 | pr_warn("unable to add cpmac-high phy: %d\n" , res); |
683 | } else |
684 | cpmac_low_data.phy_mask = 0xffffffff; |
685 | |
686 | res = fixed_phy_add(PHY_POLL, phy_id: cpmac_low.id, status: &fixed_phy_status); |
687 | if (!res) { |
688 | cpmac_get_mac(instance: 0, dev_addr: cpmac_low_data.dev_addr); |
689 | res = platform_device_register(&cpmac_low); |
690 | if (res) |
691 | pr_warn("unable to register cpmac-low: %d\n" , res); |
692 | } else |
693 | pr_warn("unable to add cpmac-low phy: %d\n" , res); |
694 | |
695 | detect_leds(); |
696 | res = platform_device_register(&ar7_gpio_leds); |
697 | if (res) |
698 | pr_warn("unable to register leds: %d\n" , res); |
699 | |
700 | res = platform_device_register(&ar7_udc); |
701 | if (res) |
702 | pr_warn("unable to register usb slave: %d\n" , res); |
703 | |
704 | /* Register watchdog only if enabled in hardware */ |
705 | bootcr = ioremap(offset: AR7_REGS_DCL, size: 4); |
706 | val = readl(addr: bootcr); |
707 | iounmap(addr: bootcr); |
708 | if (val & AR7_WDT_HW_ENA) { |
709 | if (ar7_has_high_vlynq()) |
710 | ar7_wdt_res.start = UR8_REGS_WDT; |
711 | else |
712 | ar7_wdt_res.start = AR7_REGS_WDT; |
713 | |
714 | ar7_wdt_res.end = ar7_wdt_res.start + 0x20; |
715 | res = platform_device_register(&ar7_wdt); |
716 | if (res) |
717 | pr_warn("unable to register watchdog: %d\n" , res); |
718 | } |
719 | |
720 | return 0; |
721 | } |
722 | device_initcall(ar7_register_devices); |
723 | |