1/* 2 * arch/arm/mach-ixp4xx/fsg-setup.c 3 * 4 * FSG 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 nslu2-power.c 11 * Copyright (C) 2005 Tower Technologies 12 * 13 * Author: Rod Whitby <rod@whitby.id.au> 14 * Maintainers: http://www.nslu2-linux.org/ 15 * 16 */ 17 18#include <linux/if_ether.h> 19#include <linux/irq.h> 20#include <linux/serial.h> 21#include <linux/serial_8250.h> 22#include <linux/leds.h> 23#include <linux/reboot.h> 24#include <linux/i2c.h> 25#include <linux/i2c-gpio.h> 26#include <linux/io.h> 27#include <asm/mach-types.h> 28#include <asm/mach/arch.h> 29#include <asm/mach/flash.h> 30#include <asm/gpio.h> 31 32#define FSG_SDA_PIN 12 33#define FSG_SCL_PIN 13 34 35#define FSG_SB_GPIO 4 /* sync button */ 36#define FSG_RB_GPIO 9 /* reset button */ 37#define FSG_UB_GPIO 10 /* usb button */ 38 39static struct flash_platform_data fsg_flash_data = { 40 .map_name = "cfi_probe", 41 .width = 2, 42}; 43 44static struct resource fsg_flash_resource = { 45 .flags = IORESOURCE_MEM, 46}; 47 48static struct platform_device fsg_flash = { 49 .name = "IXP4XX-Flash", 50 .id = 0, 51 .dev = { 52 .platform_data = &fsg_flash_data, 53 }, 54 .num_resources = 1, 55 .resource = &fsg_flash_resource, 56}; 57 58static struct i2c_gpio_platform_data fsg_i2c_gpio_data = { 59 .sda_pin = FSG_SDA_PIN, 60 .scl_pin = FSG_SCL_PIN, 61}; 62 63static struct platform_device fsg_i2c_gpio = { 64 .name = "i2c-gpio", 65 .id = 0, 66 .dev = { 67 .platform_data = &fsg_i2c_gpio_data, 68 }, 69}; 70 71static struct i2c_board_info __initdata fsg_i2c_board_info [] = { 72 { 73 I2C_BOARD_INFO("isl1208", 0x6f), 74 }, 75}; 76 77static struct resource fsg_uart_resources[] = { 78 { 79 .start = IXP4XX_UART1_BASE_PHYS, 80 .end = IXP4XX_UART1_BASE_PHYS + 0x0fff, 81 .flags = IORESOURCE_MEM, 82 }, 83 { 84 .start = IXP4XX_UART2_BASE_PHYS, 85 .end = IXP4XX_UART2_BASE_PHYS + 0x0fff, 86 .flags = IORESOURCE_MEM, 87 } 88}; 89 90static struct plat_serial8250_port fsg_uart_data[] = { 91 { 92 .mapbase = IXP4XX_UART1_BASE_PHYS, 93 .membase = (char *)IXP4XX_UART1_BASE_VIRT + REG_OFFSET, 94 .irq = IRQ_IXP4XX_UART1, 95 .flags = UPF_BOOT_AUTOCONF | UPF_SKIP_TEST, 96 .iotype = UPIO_MEM, 97 .regshift = 2, 98 .uartclk = IXP4XX_UART_XTAL, 99 }, 100 { 101 .mapbase = IXP4XX_UART2_BASE_PHYS, 102 .membase = (char *)IXP4XX_UART2_BASE_VIRT + REG_OFFSET, 103 .irq = IRQ_IXP4XX_UART2, 104 .flags = UPF_BOOT_AUTOCONF | UPF_SKIP_TEST, 105 .iotype = UPIO_MEM, 106 .regshift = 2, 107 .uartclk = IXP4XX_UART_XTAL, 108 }, 109 { } 110}; 111 112static struct platform_device fsg_uart = { 113 .name = "serial8250", 114 .id = PLAT8250_DEV_PLATFORM, 115 .dev = { 116 .platform_data = fsg_uart_data, 117 }, 118 .num_resources = ARRAY_SIZE(fsg_uart_resources), 119 .resource = fsg_uart_resources, 120}; 121 122static struct platform_device fsg_leds = { 123 .name = "fsg-led", 124 .id = -1, 125}; 126 127/* Built-in 10/100 Ethernet MAC interfaces */ 128static struct eth_plat_info fsg_plat_eth[] = { 129 { 130 .phy = 5, 131 .rxq = 3, 132 .txreadyq = 20, 133 }, { 134 .phy = 4, 135 .rxq = 4, 136 .txreadyq = 21, 137 } 138}; 139 140static struct platform_device fsg_eth[] = { 141 { 142 .name = "ixp4xx_eth", 143 .id = IXP4XX_ETH_NPEB, 144 .dev = { 145 .platform_data = fsg_plat_eth, 146 }, 147 }, { 148 .name = "ixp4xx_eth", 149 .id = IXP4XX_ETH_NPEC, 150 .dev = { 151 .platform_data = fsg_plat_eth + 1, 152 }, 153 } 154}; 155 156static struct platform_device *fsg_devices[] __initdata = { 157 &fsg_i2c_gpio, 158 &fsg_flash, 159 &fsg_leds, 160 &fsg_eth[0], 161 &fsg_eth[1], 162}; 163 164static irqreturn_t fsg_power_handler(int irq, void *dev_id) 165{ 166 /* Signal init to do the ctrlaltdel action, this will bypass init if 167 * it hasn't started and do a kernel_restart. 168 */ 169 ctrl_alt_del(); 170 171 return IRQ_HANDLED; 172} 173 174static irqreturn_t fsg_reset_handler(int irq, void *dev_id) 175{ 176 /* This is the paper-clip reset which does an emergency reboot. */ 177 printk(KERN_INFO "Restarting system.\n"); 178 machine_restart(NULL); 179 180 /* This should never be reached. */ 181 return IRQ_HANDLED; 182} 183 184static void __init fsg_init(void) 185{ 186 uint8_t __iomem *f; 187 188 ixp4xx_sys_init(); 189 190 fsg_flash_resource.start = IXP4XX_EXP_BUS_BASE(0); 191 fsg_flash_resource.end = 192 IXP4XX_EXP_BUS_BASE(0) + ixp4xx_exp_bus_size - 1; 193 194 *IXP4XX_EXP_CS0 |= IXP4XX_FLASH_WRITABLE; 195 *IXP4XX_EXP_CS1 = *IXP4XX_EXP_CS0; 196 197 /* Configure CS2 for operation, 8bit and writable */ 198 *IXP4XX_EXP_CS2 = 0xbfff0002; 199 200 i2c_register_board_info(0, fsg_i2c_board_info, 201 ARRAY_SIZE(fsg_i2c_board_info)); 202 203 /* This is only useful on a modified machine, but it is valuable 204 * to have it first in order to see debug messages, and so that 205 * it does *not* get removed if platform_add_devices fails! 206 */ 207 (void)platform_device_register(&fsg_uart); 208 209 platform_add_devices(fsg_devices, ARRAY_SIZE(fsg_devices)); 210 211 if (request_irq(gpio_to_irq(FSG_RB_GPIO), &fsg_reset_handler, 212 IRQF_DISABLED | IRQF_TRIGGER_LOW, 213 "FSG reset button", NULL) < 0) { 214 215 printk(KERN_DEBUG "Reset Button IRQ %d not available\n", 216 gpio_to_irq(FSG_RB_GPIO)); 217 } 218 219 if (request_irq(gpio_to_irq(FSG_SB_GPIO), &fsg_power_handler, 220 IRQF_DISABLED | IRQF_TRIGGER_LOW, 221 "FSG power button", NULL) < 0) { 222 223 printk(KERN_DEBUG "Power Button IRQ %d not available\n", 224 gpio_to_irq(FSG_SB_GPIO)); 225 } 226 227 /* 228 * Map in a portion of the flash and read the MAC addresses. 229 * Since it is stored in BE in the flash itself, we need to 230 * byteswap it if we're in LE mode. 231 */ 232 f = ioremap(IXP4XX_EXP_BUS_BASE(0), 0x400000); 233 if (f) { 234#ifdef __ARMEB__ 235 int i; 236 for (i = 0; i < 6; i++) { 237 fsg_plat_eth[0].hwaddr[i] = readb(f + 0x3C0422 + i); 238 fsg_plat_eth[1].hwaddr[i] = readb(f + 0x3C043B + i); 239 } 240#else 241 242 /* 243 Endian-swapped reads from unaligned addresses are 244 required to extract the two MACs from the big-endian 245 Redboot config area in flash. 246 */ 247 248 fsg_plat_eth[0].hwaddr[0] = readb(f + 0x3C0421); 249 fsg_plat_eth[0].hwaddr[1] = readb(f + 0x3C0420); 250 fsg_plat_eth[0].hwaddr[2] = readb(f + 0x3C0427); 251 fsg_plat_eth[0].hwaddr[3] = readb(f + 0x3C0426); 252 fsg_plat_eth[0].hwaddr[4] = readb(f + 0x3C0425); 253 fsg_plat_eth[0].hwaddr[5] = readb(f + 0x3C0424); 254 255 fsg_plat_eth[1].hwaddr[0] = readb(f + 0x3C0439); 256 fsg_plat_eth[1].hwaddr[1] = readb(f + 0x3C043F); 257 fsg_plat_eth[1].hwaddr[2] = readb(f + 0x3C043E); 258 fsg_plat_eth[1].hwaddr[3] = readb(f + 0x3C043D); 259 fsg_plat_eth[1].hwaddr[4] = readb(f + 0x3C043C); 260 fsg_plat_eth[1].hwaddr[5] = readb(f + 0x3C0443); 261#endif 262 iounmap(f); 263 } 264 printk(KERN_INFO "FSG: Using MAC address %pM for port 0\n", 265 fsg_plat_eth[0].hwaddr); 266 printk(KERN_INFO "FSG: Using MAC address %pM for port 1\n", 267 fsg_plat_eth[1].hwaddr); 268 269} 270 271MACHINE_START(FSG, "Freecom FSG-3") 272 /* Maintainer: www.nslu2-linux.org */ 273 .phys_io = IXP4XX_PERIPHERAL_BASE_PHYS, 274 .io_pg_offst = ((IXP4XX_PERIPHERAL_BASE_VIRT) >> 18) & 0xfffc, 275 .map_io = ixp4xx_map_io, 276 .init_irq = ixp4xx_init_irq, 277 .timer = &ixp4xx_timer, 278 .boot_params = 0x0100, 279 .init_machine = fsg_init, 280MACHINE_END 281