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