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