wgt634u.c 4.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174
  1. /*
  2. * This file is subject to the terms and conditions of the GNU General Public
  3. * License. See the file "COPYING" in the main directory of this archive
  4. * for more details.
  5. *
  6. * Copyright (C) 2007 Aurelien Jarno <aurelien@aurel32.net>
  7. */
  8. #include <linux/platform_device.h>
  9. #include <linux/module.h>
  10. #include <linux/leds.h>
  11. #include <linux/mtd/physmap.h>
  12. #include <linux/ssb/ssb.h>
  13. #include <linux/ssb/ssb_embedded.h>
  14. #include <linux/interrupt.h>
  15. #include <linux/reboot.h>
  16. #include <linux/gpio.h>
  17. #include <asm/mach-bcm47xx/bcm47xx.h>
  18. /* GPIO definitions for the WGT634U */
  19. #define WGT634U_GPIO_LED 3
  20. #define WGT634U_GPIO_RESET 2
  21. #define WGT634U_GPIO_TP1 7
  22. #define WGT634U_GPIO_TP2 6
  23. #define WGT634U_GPIO_TP3 5
  24. #define WGT634U_GPIO_TP4 4
  25. #define WGT634U_GPIO_TP5 1
  26. static struct gpio_led wgt634u_leds[] = {
  27. {
  28. .name = "power",
  29. .gpio = WGT634U_GPIO_LED,
  30. .active_low = 1,
  31. .default_trigger = "heartbeat",
  32. },
  33. };
  34. static struct gpio_led_platform_data wgt634u_led_data = {
  35. .num_leds = ARRAY_SIZE(wgt634u_leds),
  36. .leds = wgt634u_leds,
  37. };
  38. static struct platform_device wgt634u_gpio_leds = {
  39. .name = "leds-gpio",
  40. .id = -1,
  41. .dev = {
  42. .platform_data = &wgt634u_led_data,
  43. }
  44. };
  45. /* 8MiB flash. The struct mtd_partition matches original Netgear WGT634U
  46. firmware. */
  47. static struct mtd_partition wgt634u_partitions[] = {
  48. {
  49. .name = "cfe",
  50. .offset = 0,
  51. .size = 0x60000, /* 384k */
  52. .mask_flags = MTD_WRITEABLE /* force read-only */
  53. },
  54. {
  55. .name = "config",
  56. .offset = 0x60000,
  57. .size = 0x20000 /* 128k */
  58. },
  59. {
  60. .name = "linux",
  61. .offset = 0x80000,
  62. .size = 0x140000 /* 1280k */
  63. },
  64. {
  65. .name = "jffs",
  66. .offset = 0x1c0000,
  67. .size = 0x620000 /* 6272k */
  68. },
  69. {
  70. .name = "nvram",
  71. .offset = 0x7e0000,
  72. .size = 0x20000 /* 128k */
  73. },
  74. };
  75. static struct physmap_flash_data wgt634u_flash_data = {
  76. .parts = wgt634u_partitions,
  77. .nr_parts = ARRAY_SIZE(wgt634u_partitions)
  78. };
  79. static struct resource wgt634u_flash_resource = {
  80. .flags = IORESOURCE_MEM,
  81. };
  82. static struct platform_device wgt634u_flash = {
  83. .name = "physmap-flash",
  84. .id = 0,
  85. .dev = { .platform_data = &wgt634u_flash_data, },
  86. .resource = &wgt634u_flash_resource,
  87. .num_resources = 1,
  88. };
  89. /* Platform devices */
  90. static struct platform_device *wgt634u_devices[] __initdata = {
  91. &wgt634u_flash,
  92. &wgt634u_gpio_leds,
  93. };
  94. static irqreturn_t gpio_interrupt(int irq, void *ignored)
  95. {
  96. int state;
  97. /* Interrupts are shared, check if the current one is
  98. a GPIO interrupt. */
  99. if (!ssb_chipco_irq_status(&bcm47xx_bus.ssb.chipco,
  100. SSB_CHIPCO_IRQ_GPIO))
  101. return IRQ_NONE;
  102. state = gpio_get_value(WGT634U_GPIO_RESET);
  103. /* Interrupt are level triggered, revert the interrupt polarity
  104. to clear the interrupt. */
  105. ssb_gpio_polarity(&bcm47xx_bus.ssb, 1 << WGT634U_GPIO_RESET,
  106. state ? 1 << WGT634U_GPIO_RESET : 0);
  107. if (!state) {
  108. printk(KERN_INFO "Reset button pressed");
  109. ctrl_alt_del();
  110. }
  111. return IRQ_HANDLED;
  112. }
  113. static int __init wgt634u_init(void)
  114. {
  115. /* There is no easy way to detect that we are running on a WGT634U
  116. * machine. Use the MAC address as an heuristic. Netgear Inc. has
  117. * been allocated ranges 00:09:5b:xx:xx:xx and 00:0f:b5:xx:xx:xx.
  118. */
  119. u8 *et0mac;
  120. if (bcm47xx_bus_type != BCM47XX_BUS_TYPE_SSB)
  121. return -ENODEV;
  122. et0mac = bcm47xx_bus.ssb.sprom.et0mac;
  123. if (et0mac[0] == 0x00 &&
  124. ((et0mac[1] == 0x09 && et0mac[2] == 0x5b) ||
  125. (et0mac[1] == 0x0f && et0mac[2] == 0xb5))) {
  126. struct ssb_mipscore *mcore = &bcm47xx_bus.ssb.mipscore;
  127. printk(KERN_INFO "WGT634U machine detected.\n");
  128. if (!request_irq(gpio_to_irq(WGT634U_GPIO_RESET),
  129. gpio_interrupt, IRQF_SHARED,
  130. "WGT634U GPIO", &bcm47xx_bus.ssb.chipco)) {
  131. gpio_direction_input(WGT634U_GPIO_RESET);
  132. ssb_gpio_intmask(&bcm47xx_bus.ssb,
  133. 1 << WGT634U_GPIO_RESET,
  134. 1 << WGT634U_GPIO_RESET);
  135. ssb_chipco_irq_mask(&bcm47xx_bus.ssb.chipco,
  136. SSB_CHIPCO_IRQ_GPIO,
  137. SSB_CHIPCO_IRQ_GPIO);
  138. }
  139. wgt634u_flash_data.width = mcore->pflash.buswidth;
  140. wgt634u_flash_resource.start = mcore->pflash.window;
  141. wgt634u_flash_resource.end = mcore->pflash.window
  142. + mcore->pflash.window_size
  143. - 1;
  144. return platform_add_devices(wgt634u_devices,
  145. ARRAY_SIZE(wgt634u_devices));
  146. } else
  147. return -ENODEV;
  148. }
  149. module_init(wgt634u_init);