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