1/* 2 * arch/arm/mach-ixp4xx/nas100d-setup.c 3 * 4 * NAS 100d board-setup 5 * 6 * Copyright (C) 2008 Rod Whitby <rod@whitby.id.au> 7 * 8 * based on ixdp425-setup.c: 9 * Copyright (C) 2003-2004 MontaVista Software, Inc. 10 * based on nas100d-power.c: 11 * Copyright (C) 2005 Tower Technologies 12 * based on nas100d-io.c 13 * Copyright (C) 2004 Karen Spearel 14 * 15 * Author: Alessandro Zummo <a.zummo@towertech.it> 16 * Author: Rod Whitby <rod@whitby.id.au> 17 * Maintainers: http://www.nslu2-linux.org/ 18 * 19 */ 20#include <linux/gpio.h> 21#include <linux/if_ether.h> 22#include <linux/irq.h> 23#include <linux/jiffies.h> 24#include <linux/timer.h> 25#include <linux/serial.h> 26#include <linux/serial_8250.h> 27#include <linux/leds.h> 28#include <linux/reboot.h> 29#include <linux/i2c.h> 30#include <linux/i2c-gpio.h> 31#include <linux/io.h> 32#include <asm/mach-types.h> 33#include <asm/mach/arch.h> 34#include <asm/mach/flash.h> 35 36#define NAS100D_SDA_PIN 5 37#define NAS100D_SCL_PIN 6 38 39/* Buttons */ 40#define NAS100D_PB_GPIO 14 /* power button */ 41#define NAS100D_RB_GPIO 4 /* reset button */ 42 43/* Power control */ 44#define NAS100D_PO_GPIO 12 /* power off */ 45 46/* LEDs */ 47#define NAS100D_LED_WLAN_GPIO 0 48#define NAS100D_LED_DISK_GPIO 3 49#define NAS100D_LED_PWR_GPIO 15 50 51static struct flash_platform_data nas100d_flash_data = { 52 .map_name = "cfi_probe", 53 .width = 2, 54}; 55 56static struct resource nas100d_flash_resource = { 57 .flags = IORESOURCE_MEM, 58}; 59 60static struct platform_device nas100d_flash = { 61 .name = "IXP4XX-Flash", 62 .id = 0, 63 .dev.platform_data = &nas100d_flash_data, 64 .num_resources = 1, 65 .resource = &nas100d_flash_resource, 66}; 67 68static struct i2c_board_info __initdata nas100d_i2c_board_info [] = { 69 { 70 I2C_BOARD_INFO("pcf8563", 0x51), 71 }, 72}; 73 74static struct gpio_led nas100d_led_pins[] = { 75 { 76 .name = "nas100d:green:wlan", 77 .gpio = NAS100D_LED_WLAN_GPIO, 78 .active_low = true, 79 }, 80 { 81 .name = "nas100d:blue:power", /* (off=flashing) */ 82 .gpio = NAS100D_LED_PWR_GPIO, 83 .active_low = true, 84 }, 85 { 86 .name = "nas100d:yellow:disk", 87 .gpio = NAS100D_LED_DISK_GPIO, 88 .active_low = true, 89 }, 90}; 91 92static struct gpio_led_platform_data nas100d_led_data = { 93 .num_leds = ARRAY_SIZE(nas100d_led_pins), 94 .leds = nas100d_led_pins, 95}; 96 97static struct platform_device nas100d_leds = { 98 .name = "leds-gpio", 99 .id = -1, 100 .dev.platform_data = &nas100d_led_data, 101}; 102 103static struct i2c_gpio_platform_data nas100d_i2c_gpio_data = { 104 .sda_pin = NAS100D_SDA_PIN, 105 .scl_pin = NAS100D_SCL_PIN, 106}; 107 108static struct platform_device nas100d_i2c_gpio = { 109 .name = "i2c-gpio", 110 .id = 0, 111 .dev = { 112 .platform_data = &nas100d_i2c_gpio_data, 113 }, 114}; 115 116static struct resource nas100d_uart_resources[] = { 117 { 118 .start = IXP4XX_UART1_BASE_PHYS, 119 .end = IXP4XX_UART1_BASE_PHYS + 0x0fff, 120 .flags = IORESOURCE_MEM, 121 }, 122 { 123 .start = IXP4XX_UART2_BASE_PHYS, 124 .end = IXP4XX_UART2_BASE_PHYS + 0x0fff, 125 .flags = IORESOURCE_MEM, 126 } 127}; 128 129static struct plat_serial8250_port nas100d_uart_data[] = { 130 { 131 .mapbase = IXP4XX_UART1_BASE_PHYS, 132 .membase = (char *)IXP4XX_UART1_BASE_VIRT + REG_OFFSET, 133 .irq = IRQ_IXP4XX_UART1, 134 .flags = UPF_BOOT_AUTOCONF, 135 .iotype = UPIO_MEM, 136 .regshift = 2, 137 .uartclk = IXP4XX_UART_XTAL, 138 }, 139 { 140 .mapbase = IXP4XX_UART2_BASE_PHYS, 141 .membase = (char *)IXP4XX_UART2_BASE_VIRT + REG_OFFSET, 142 .irq = IRQ_IXP4XX_UART2, 143 .flags = UPF_BOOT_AUTOCONF, 144 .iotype = UPIO_MEM, 145 .regshift = 2, 146 .uartclk = IXP4XX_UART_XTAL, 147 }, 148 { } 149}; 150 151static struct platform_device nas100d_uart = { 152 .name = "serial8250", 153 .id = PLAT8250_DEV_PLATFORM, 154 .dev.platform_data = nas100d_uart_data, 155 .num_resources = 2, 156 .resource = nas100d_uart_resources, 157}; 158 159/* Built-in 10/100 Ethernet MAC interfaces */ 160static struct eth_plat_info nas100d_plat_eth[] = { 161 { 162 .phy = 0, 163 .rxq = 3, 164 .txreadyq = 20, 165 } 166}; 167 168static struct platform_device nas100d_eth[] = { 169 { 170 .name = "ixp4xx_eth", 171 .id = IXP4XX_ETH_NPEB, 172 .dev.platform_data = nas100d_plat_eth, 173 } 174}; 175 176static struct platform_device *nas100d_devices[] __initdata = { 177 &nas100d_i2c_gpio, 178 &nas100d_flash, 179 &nas100d_leds, 180 &nas100d_eth[0], 181}; 182 183static void nas100d_power_off(void) 184{ 185 /* This causes the box to drop the power and go dead. */ 186 187 /* enable the pwr cntl gpio and assert power off */ 188 gpio_direction_output(NAS100D_PO_GPIO, 1); 189} 190 191/* This is used to make sure the power-button pusher is serious. The button 192 * must be held until the value of this counter reaches zero. 193 */ 194static int power_button_countdown; 195 196/* Must hold the button down for at least this many counts to be processed */ 197#define PBUTTON_HOLDDOWN_COUNT 4 /* 2 secs */ 198 199static void nas100d_power_handler(unsigned long data); 200static DEFINE_TIMER(nas100d_power_timer, nas100d_power_handler, 0, 0); 201 202static void nas100d_power_handler(unsigned long data) 203{ 204 /* This routine is called twice per second to check the 205 * state of the power button. 206 */ 207 208 if (gpio_get_value(NAS100D_PB_GPIO)) { 209 210 /* IO Pin is 1 (button pushed) */ 211 if (power_button_countdown > 0) 212 power_button_countdown--; 213 214 } else { 215 216 /* Done on button release, to allow for auto-power-on mods. */ 217 if (power_button_countdown == 0) { 218 /* Signal init to do the ctrlaltdel action, 219 * this will bypass init if it hasn't started 220 * and do a kernel_restart. 221 */ 222 ctrl_alt_del(); 223 224 /* Change the state of the power LED to "blink" */ 225 gpio_set_value(NAS100D_LED_PWR_GPIO, 0); 226 } else { 227 power_button_countdown = PBUTTON_HOLDDOWN_COUNT; 228 } 229 } 230 231 mod_timer(&nas100d_power_timer, jiffies + msecs_to_jiffies(500)); 232} 233 234static irqreturn_t nas100d_reset_handler(int irq, void *dev_id) 235{ 236 /* This is the paper-clip reset, it shuts the machine down directly. */ 237 machine_power_off(); 238 239 return IRQ_HANDLED; 240} 241 242static int __init nas100d_gpio_init(void) 243{ 244 if (!machine_is_nas100d()) 245 return 0; 246 247 /* 248 * The power button on the Iomega NAS100d is on GPIO 14, but 249 * it cannot handle interrupts on that GPIO line. So we'll 250 * have to poll it with a kernel timer. 251 */ 252 253 /* Request the power off GPIO */ 254 gpio_request(NAS100D_PO_GPIO, "power off"); 255 256 /* Make sure that the power button GPIO is set up as an input */ 257 gpio_request(NAS100D_PB_GPIO, "power button"); 258 gpio_direction_input(NAS100D_PB_GPIO); 259 260 /* Set the initial value for the power button IRQ handler */ 261 power_button_countdown = PBUTTON_HOLDDOWN_COUNT; 262 263 mod_timer(&nas100d_power_timer, jiffies + msecs_to_jiffies(500)); 264 265 return 0; 266} 267device_initcall(nas100d_gpio_init); 268 269static void __init nas100d_init(void) 270{ 271 uint8_t __iomem *f; 272 int i; 273 274 ixp4xx_sys_init(); 275 276 /* gpio 14 and 15 are _not_ clocks */ 277 *IXP4XX_GPIO_GPCLKR = 0; 278 279 nas100d_flash_resource.start = IXP4XX_EXP_BUS_BASE(0); 280 nas100d_flash_resource.end = 281 IXP4XX_EXP_BUS_BASE(0) + ixp4xx_exp_bus_size - 1; 282 283 i2c_register_board_info(0, nas100d_i2c_board_info, 284 ARRAY_SIZE(nas100d_i2c_board_info)); 285 286 /* 287 * This is only useful on a modified machine, but it is valuable 288 * to have it first in order to see debug messages, and so that 289 * it does *not* get removed if platform_add_devices fails! 290 */ 291 (void)platform_device_register(&nas100d_uart); 292 293 platform_add_devices(nas100d_devices, ARRAY_SIZE(nas100d_devices)); 294 295 pm_power_off = nas100d_power_off; 296 297 if (request_irq(gpio_to_irq(NAS100D_RB_GPIO), &nas100d_reset_handler, 298 IRQF_TRIGGER_LOW, "NAS100D reset button", NULL) < 0) { 299 300 printk(KERN_DEBUG "Reset Button IRQ %d not available\n", 301 gpio_to_irq(NAS100D_RB_GPIO)); 302 } 303 304 /* 305 * Map in a portion of the flash and read the MAC address. 306 * Since it is stored in BE in the flash itself, we need to 307 * byteswap it if we're in LE mode. 308 */ 309 f = ioremap(IXP4XX_EXP_BUS_BASE(0), 0x1000000); 310 if (f) { 311 for (i = 0; i < 6; i++) 312#ifdef __ARMEB__ 313 nas100d_plat_eth[0].hwaddr[i] = readb(f + 0xFC0FD8 + i); 314#else 315 nas100d_plat_eth[0].hwaddr[i] = readb(f + 0xFC0FD8 + (i^3)); 316#endif 317 iounmap(f); 318 } 319 printk(KERN_INFO "NAS100D: Using MAC address %pM for port 0\n", 320 nas100d_plat_eth[0].hwaddr); 321 322} 323 324MACHINE_START(NAS100D, "Iomega NAS 100d") 325 /* Maintainer: www.nslu2-linux.org */ 326 .atag_offset = 0x100, 327 .map_io = ixp4xx_map_io, 328 .init_early = ixp4xx_init_early, 329 .init_irq = ixp4xx_init_irq, 330 .init_time = ixp4xx_timer_init, 331 .init_machine = nas100d_init, 332#if defined(CONFIG_PCI) 333 .dma_zone_size = SZ_64M, 334#endif 335 .restart = ixp4xx_restart, 336MACHINE_END 337