]> git.karo-electronics.de Git - mv-sheeva.git/blob - arch/mips/ar7/platform.c
MIPS: AR7: Implement gpiolib
[mv-sheeva.git] / arch / mips / ar7 / platform.c
1 /*
2  * Copyright (C) 2006,2007 Felix Fietkau <nbd@openwrt.org>
3  * Copyright (C) 2006,2007 Eugene Konev <ejka@openwrt.org>
4  *
5  * This program is free software; you can redistribute it and/or modify
6  * it under the terms of the GNU General Public License as published by
7  * the Free Software Foundation; either version 2 of the License, or
8  * (at your option) any later version.
9  *
10  * This program is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  * GNU General Public License for more details.
14  *
15  * You should have received a copy of the GNU General Public License
16  * along with this program; if not, write to the Free Software
17  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
18  */
19
20 #include <linux/init.h>
21 #include <linux/types.h>
22 #include <linux/module.h>
23 #include <linux/delay.h>
24 #include <linux/dma-mapping.h>
25 #include <linux/platform_device.h>
26 #include <linux/mtd/physmap.h>
27 #include <linux/serial.h>
28 #include <linux/serial_8250.h>
29 #include <linux/ioport.h>
30 #include <linux/io.h>
31 #include <linux/vlynq.h>
32 #include <linux/leds.h>
33 #include <linux/string.h>
34 #include <linux/etherdevice.h>
35 #include <linux/phy.h>
36 #include <linux/phy_fixed.h>
37 #include <linux/gpio.h>
38
39 #include <asm/addrspace.h>
40 #include <asm/mach-ar7/ar7.h>
41 #include <asm/mach-ar7/gpio.h>
42 #include <asm/mach-ar7/prom.h>
43
44 struct plat_vlynq_data {
45         struct plat_vlynq_ops ops;
46         int gpio_bit;
47         int reset_bit;
48 };
49
50
51 static int vlynq_on(struct vlynq_device *dev)
52 {
53         int result;
54         struct plat_vlynq_data *pdata = dev->dev.platform_data;
55
56         result = gpio_request(pdata->gpio_bit, "vlynq");
57         if (result)
58                 goto out;
59
60         ar7_device_reset(pdata->reset_bit);
61
62         result = ar7_gpio_disable(pdata->gpio_bit);
63         if (result)
64                 goto out_enabled;
65
66         result = ar7_gpio_enable(pdata->gpio_bit);
67         if (result)
68                 goto out_enabled;
69
70         result = gpio_direction_output(pdata->gpio_bit, 0);
71         if (result)
72                 goto out_gpio_enabled;
73
74         msleep(50);
75
76         gpio_set_value(pdata->gpio_bit, 1);
77         msleep(50);
78
79         return 0;
80
81 out_gpio_enabled:
82         ar7_gpio_disable(pdata->gpio_bit);
83 out_enabled:
84         ar7_device_disable(pdata->reset_bit);
85         gpio_free(pdata->gpio_bit);
86 out:
87         return result;
88 }
89
90 static void vlynq_off(struct vlynq_device *dev)
91 {
92         struct plat_vlynq_data *pdata = dev->dev.platform_data;
93         ar7_gpio_disable(pdata->gpio_bit);
94         gpio_free(pdata->gpio_bit);
95         ar7_device_disable(pdata->reset_bit);
96 }
97
98 static struct resource physmap_flash_resource = {
99         .name = "mem",
100         .flags = IORESOURCE_MEM,
101         .start = 0x10000000,
102         .end = 0x107fffff,
103 };
104
105 static struct resource cpmac_low_res[] = {
106         {
107                 .name = "regs",
108                 .flags = IORESOURCE_MEM,
109                 .start = AR7_REGS_MAC0,
110                 .end = AR7_REGS_MAC0 + 0x7ff,
111         },
112         {
113                 .name = "irq",
114                 .flags = IORESOURCE_IRQ,
115                 .start = 27,
116                 .end = 27,
117         },
118 };
119
120 static struct resource cpmac_high_res[] = {
121         {
122                 .name = "regs",
123                 .flags = IORESOURCE_MEM,
124                 .start = AR7_REGS_MAC1,
125                 .end = AR7_REGS_MAC1 + 0x7ff,
126         },
127         {
128                 .name = "irq",
129                 .flags = IORESOURCE_IRQ,
130                 .start = 41,
131                 .end = 41,
132         },
133 };
134
135 static struct resource vlynq_low_res[] = {
136         {
137                 .name = "regs",
138                 .flags = IORESOURCE_MEM,
139                 .start = AR7_REGS_VLYNQ0,
140                 .end = AR7_REGS_VLYNQ0 + 0xff,
141         },
142         {
143                 .name = "irq",
144                 .flags = IORESOURCE_IRQ,
145                 .start = 29,
146                 .end = 29,
147         },
148         {
149                 .name = "mem",
150                 .flags = IORESOURCE_MEM,
151                 .start = 0x04000000,
152                 .end = 0x04ffffff,
153         },
154         {
155                 .name = "devirq",
156                 .flags = IORESOURCE_IRQ,
157                 .start = 80,
158                 .end = 111,
159         },
160 };
161
162 static struct resource vlynq_high_res[] = {
163         {
164                 .name = "regs",
165                 .flags = IORESOURCE_MEM,
166                 .start = AR7_REGS_VLYNQ1,
167                 .end = AR7_REGS_VLYNQ1 + 0xff,
168         },
169         {
170                 .name = "irq",
171                 .flags = IORESOURCE_IRQ,
172                 .start = 33,
173                 .end = 33,
174         },
175         {
176                 .name = "mem",
177                 .flags = IORESOURCE_MEM,
178                 .start = 0x0c000000,
179                 .end = 0x0cffffff,
180         },
181         {
182                 .name = "devirq",
183                 .flags = IORESOURCE_IRQ,
184                 .start = 112,
185                 .end = 143,
186         },
187 };
188
189 static struct resource usb_res[] = {
190         {
191                 .name = "regs",
192                 .flags = IORESOURCE_MEM,
193                 .start = AR7_REGS_USB,
194                 .end = AR7_REGS_USB + 0xff,
195         },
196         {
197                 .name = "irq",
198                 .flags = IORESOURCE_IRQ,
199                 .start = 32,
200                 .end = 32,
201         },
202         {
203                 .name = "mem",
204                 .flags = IORESOURCE_MEM,
205                 .start = 0x03400000,
206                 .end = 0x03401fff,
207         },
208 };
209
210 static struct physmap_flash_data physmap_flash_data = {
211         .width = 2,
212 };
213
214 static struct fixed_phy_status fixed_phy_status __initdata = {
215         .link = 1,
216         .speed = 100,
217         .duplex = 1,
218 };
219
220 static struct plat_cpmac_data cpmac_low_data = {
221         .reset_bit = 17,
222         .power_bit = 20,
223         .phy_mask = 0x80000000,
224 };
225
226 static struct plat_cpmac_data cpmac_high_data = {
227         .reset_bit = 21,
228         .power_bit = 22,
229         .phy_mask = 0x7fffffff,
230 };
231
232 static struct plat_vlynq_data vlynq_low_data = {
233         .ops.on = vlynq_on,
234         .ops.off = vlynq_off,
235         .reset_bit = 20,
236         .gpio_bit = 18,
237 };
238
239 static struct plat_vlynq_data vlynq_high_data = {
240         .ops.on = vlynq_on,
241         .ops.off = vlynq_off,
242         .reset_bit = 16,
243         .gpio_bit = 19,
244 };
245
246 static struct platform_device physmap_flash = {
247         .id = 0,
248         .name = "physmap-flash",
249         .dev.platform_data = &physmap_flash_data,
250         .resource = &physmap_flash_resource,
251         .num_resources = 1,
252 };
253
254 static u64 cpmac_dma_mask = DMA_BIT_MASK(32);
255 static struct platform_device cpmac_low = {
256         .id = 0,
257         .name = "cpmac",
258         .dev = {
259                 .dma_mask = &cpmac_dma_mask,
260                 .coherent_dma_mask = DMA_BIT_MASK(32),
261                 .platform_data = &cpmac_low_data,
262         },
263         .resource = cpmac_low_res,
264         .num_resources = ARRAY_SIZE(cpmac_low_res),
265 };
266
267 static struct platform_device cpmac_high = {
268         .id = 1,
269         .name = "cpmac",
270         .dev = {
271                 .dma_mask = &cpmac_dma_mask,
272                 .coherent_dma_mask = DMA_BIT_MASK(32),
273                 .platform_data = &cpmac_high_data,
274         },
275         .resource = cpmac_high_res,
276         .num_resources = ARRAY_SIZE(cpmac_high_res),
277 };
278
279 static struct platform_device vlynq_low = {
280         .id = 0,
281         .name = "vlynq",
282         .dev.platform_data = &vlynq_low_data,
283         .resource = vlynq_low_res,
284         .num_resources = ARRAY_SIZE(vlynq_low_res),
285 };
286
287 static struct platform_device vlynq_high = {
288         .id = 1,
289         .name = "vlynq",
290         .dev.platform_data = &vlynq_high_data,
291         .resource = vlynq_high_res,
292         .num_resources = ARRAY_SIZE(vlynq_high_res),
293 };
294
295
296 static struct gpio_led default_leds[] = {
297         {
298                 .name = "status",
299                 .gpio = 8,
300                 .active_low = 1,
301         },
302 };
303
304 static struct gpio_led dsl502t_leds[] = {
305         {
306                 .name = "status",
307                 .gpio = 9,
308                 .active_low = 1,
309         },
310         {
311                 .name = "ethernet",
312                 .gpio = 7,
313                 .active_low = 1,
314         },
315         {
316                 .name = "usb",
317                 .gpio = 12,
318                 .active_low = 1,
319         },
320 };
321
322 static struct gpio_led dg834g_leds[] = {
323         {
324                 .name = "ppp",
325                 .gpio = 6,
326                 .active_low = 1,
327         },
328         {
329                 .name = "status",
330                 .gpio = 7,
331                 .active_low = 1,
332         },
333         {
334                 .name = "adsl",
335                 .gpio = 8,
336                 .active_low = 1,
337         },
338         {
339                 .name = "wifi",
340                 .gpio = 12,
341                 .active_low = 1,
342         },
343         {
344                 .name = "power",
345                 .gpio = 14,
346                 .active_low = 1,
347                 .default_trigger = "default-on",
348         },
349 };
350
351 static struct gpio_led fb_sl_leds[] = {
352         {
353                 .name = "1",
354                 .gpio = 7,
355         },
356         {
357                 .name = "2",
358                 .gpio = 13,
359                 .active_low = 1,
360         },
361         {
362                 .name = "3",
363                 .gpio = 10,
364                 .active_low = 1,
365         },
366         {
367                 .name = "4",
368                 .gpio = 12,
369                 .active_low = 1,
370         },
371         {
372                 .name = "5",
373                 .gpio = 9,
374                 .active_low = 1,
375         },
376 };
377
378 static struct gpio_led fb_fon_leds[] = {
379         {
380                 .name = "1",
381                 .gpio = 8,
382         },
383         {
384                 .name = "2",
385                 .gpio = 3,
386                 .active_low = 1,
387         },
388         {
389                 .name = "3",
390                 .gpio = 5,
391         },
392         {
393                 .name = "4",
394                 .gpio = 4,
395                 .active_low = 1,
396         },
397         {
398                 .name = "5",
399                 .gpio = 11,
400                 .active_low = 1,
401         },
402 };
403
404 static struct gpio_led_platform_data ar7_led_data;
405
406 static struct platform_device ar7_gpio_leds = {
407         .name = "leds-gpio",
408         .id = -1,
409         .dev = {
410                 .platform_data = &ar7_led_data,
411         }
412 };
413
414 static struct platform_device ar7_udc = {
415         .id = -1,
416         .name = "ar7_udc",
417         .resource = usb_res,
418         .num_resources = ARRAY_SIZE(usb_res),
419 };
420
421 static struct resource ar7_wdt_res = {
422         .name = "regs",
423         .start = -1, /* Filled at runtime */
424         .end = -1, /* Filled at runtime */
425         .flags = IORESOURCE_MEM,
426 };
427
428 static struct platform_device ar7_wdt = {
429         .id = -1,
430         .name  = "ar7_wdt",
431         .resource = &ar7_wdt_res,
432         .num_resources = 1,
433 };
434
435 static inline unsigned char char2hex(char h)
436 {
437         switch (h) {
438         case '0': case '1': case '2': case '3': case '4':
439         case '5': case '6': case '7': case '8': case '9':
440                 return h - '0';
441         case 'A': case 'B': case 'C': case 'D': case 'E': case 'F':
442                 return h - 'A' + 10;
443         case 'a': case 'b': case 'c': case 'd': case 'e': case 'f':
444                 return h - 'a' + 10;
445         default:
446                 return 0;
447         }
448 }
449
450 static void cpmac_get_mac(int instance, unsigned char *dev_addr)
451 {
452         int i;
453         char name[5], default_mac[ETH_ALEN], *mac;
454
455         mac = NULL;
456         sprintf(name, "mac%c", 'a' + instance);
457         mac = prom_getenv(name);
458         if (!mac) {
459                 sprintf(name, "mac%c", 'a');
460                 mac = prom_getenv(name);
461         }
462         if (!mac) {
463                 random_ether_addr(default_mac);
464                 mac = default_mac;
465         }
466         for (i = 0; i < 6; i++)
467                 dev_addr[i] = (char2hex(mac[i * 3]) << 4) +
468                         char2hex(mac[i * 3 + 1]);
469 }
470
471 static void __init detect_leds(void)
472 {
473         char *prid, *usb_prod;
474
475         /* Default LEDs */
476         ar7_led_data.num_leds = ARRAY_SIZE(default_leds);
477         ar7_led_data.leds = default_leds;
478
479         /* FIXME: the whole thing is unreliable */
480         prid = prom_getenv("ProductID");
481         usb_prod = prom_getenv("usb_prod");
482
483         /* If we can't get the product id from PROM, use the default LEDs */
484         if (!prid)
485                 return;
486
487         if (strstr(prid, "Fritz_Box_FON")) {
488                 ar7_led_data.num_leds = ARRAY_SIZE(fb_fon_leds);
489                 ar7_led_data.leds = fb_fon_leds;
490         } else if (strstr(prid, "Fritz_Box_")) {
491                 ar7_led_data.num_leds = ARRAY_SIZE(fb_sl_leds);
492                 ar7_led_data.leds = fb_sl_leds;
493         } else if ((!strcmp(prid, "AR7RD") || !strcmp(prid, "AR7DB"))
494                 && usb_prod != NULL && strstr(usb_prod, "DSL-502T")) {
495                 ar7_led_data.num_leds = ARRAY_SIZE(dsl502t_leds);
496                 ar7_led_data.leds = dsl502t_leds;
497         } else if (strstr(prid, "DG834")) {
498                 ar7_led_data.num_leds = ARRAY_SIZE(dg834g_leds);
499                 ar7_led_data.leds = dg834g_leds;
500         }
501 }
502
503 static int __init ar7_register_devices(void)
504 {
505         u16 chip_id;
506         int res;
507         u32 *bootcr, val;
508 #ifdef CONFIG_SERIAL_8250
509         static struct uart_port uart_port[2] __initdata;
510
511         memset(uart_port, 0, sizeof(struct uart_port) * 2);
512
513         uart_port[0].type = PORT_16550A;
514         uart_port[0].line = 0;
515         uart_port[0].irq = AR7_IRQ_UART0;
516         uart_port[0].uartclk = ar7_bus_freq() / 2;
517         uart_port[0].iotype = UPIO_MEM32;
518         uart_port[0].mapbase = AR7_REGS_UART0;
519         uart_port[0].membase = ioremap(uart_port[0].mapbase, 256);
520         uart_port[0].regshift = 2;
521         res = early_serial_setup(&uart_port[0]);
522         if (res)
523                 return res;
524
525
526         /* Only TNETD73xx have a second serial port */
527         if (ar7_has_second_uart()) {
528                 uart_port[1].type = PORT_16550A;
529                 uart_port[1].line = 1;
530                 uart_port[1].irq = AR7_IRQ_UART1;
531                 uart_port[1].uartclk = ar7_bus_freq() / 2;
532                 uart_port[1].iotype = UPIO_MEM32;
533                 uart_port[1].mapbase = UR8_REGS_UART1;
534                 uart_port[1].membase = ioremap(uart_port[1].mapbase, 256);
535                 uart_port[1].regshift = 2;
536                 res = early_serial_setup(&uart_port[1]);
537                 if (res)
538                         return res;
539         }
540 #endif /* CONFIG_SERIAL_8250 */
541         res = platform_device_register(&physmap_flash);
542         if (res)
543                 return res;
544
545         ar7_device_disable(vlynq_low_data.reset_bit);
546         res = platform_device_register(&vlynq_low);
547         if (res)
548                 return res;
549
550         if (ar7_has_high_vlynq()) {
551                 ar7_device_disable(vlynq_high_data.reset_bit);
552                 res = platform_device_register(&vlynq_high);
553                 if (res)
554                         return res;
555         }
556
557         if (ar7_has_high_cpmac()) {
558                 res = fixed_phy_add(PHY_POLL, cpmac_high.id, &fixed_phy_status);
559                 if (res && res != -ENODEV)
560                         return res;
561                 cpmac_get_mac(1, cpmac_high_data.dev_addr);
562                 res = platform_device_register(&cpmac_high);
563                 if (res)
564                         return res;
565         } else {
566                 cpmac_low_data.phy_mask = 0xffffffff;
567         }
568
569         res = fixed_phy_add(PHY_POLL, cpmac_low.id, &fixed_phy_status);
570         if (res && res != -ENODEV)
571                 return res;
572
573         cpmac_get_mac(0, cpmac_low_data.dev_addr);
574         res = platform_device_register(&cpmac_low);
575         if (res)
576                 return res;
577
578         detect_leds();
579         res = platform_device_register(&ar7_gpio_leds);
580         if (res)
581                 return res;
582
583         res = platform_device_register(&ar7_udc);
584
585         chip_id = ar7_chip_id();
586         switch (chip_id) {
587         case AR7_CHIP_7100:
588         case AR7_CHIP_7200:
589                 ar7_wdt_res.start = AR7_REGS_WDT;
590                 break;
591         case AR7_CHIP_7300:
592                 ar7_wdt_res.start = UR8_REGS_WDT;
593                 break;
594         default:
595                 break;
596         }
597
598         ar7_wdt_res.end = ar7_wdt_res.start + 0x20;
599
600         bootcr = (u32 *)ioremap_nocache(AR7_REGS_DCL, 4);
601         val = *bootcr;
602         iounmap(bootcr);
603
604         /* Register watchdog only if enabled in hardware */
605         if (val & AR7_WDT_HW_ENA)
606                 res = platform_device_register(&ar7_wdt);
607
608         return res;
609 }
610 arch_initcall(ar7_register_devices);