Path: blob/master/arch/arm/mach-ixp4xx/dsmg600-setup.c
10817 views
/*1* DSM-G600 board-setup2*3* Copyright (C) 2008 Rod Whitby <[email protected]>4* Copyright (C) 2006 Tower Technologies5*6* based on ixdp425-setup.c:7* Copyright (C) 2003-2004 MontaVista Software, Inc.8* based on nslu2-power.c:9* Copyright (C) 2005 Tower Technologies10* based on nslu2-io.c:11* Copyright (C) 2004 Karen Spearel12*13* Author: Alessandro Zummo <[email protected]>14* Author: Michael Westerhof <[email protected]>15* Author: Rod Whitby <[email protected]>16* Maintainers: http://www.nslu2-linux.org/17*/1819#include <linux/irq.h>20#include <linux/jiffies.h>21#include <linux/timer.h>22#include <linux/serial.h>23#include <linux/serial_8250.h>24#include <linux/leds.h>25#include <linux/reboot.h>26#include <linux/i2c.h>27#include <linux/i2c-gpio.h>2829#include <asm/mach-types.h>30#include <asm/mach/arch.h>31#include <asm/mach/flash.h>32#include <asm/mach/time.h>33#include <asm/gpio.h>3435#define DSMG600_SDA_PIN 536#define DSMG600_SCL_PIN 43738/* DSM-G600 Timer Setting */39#define DSMG600_FREQ 660000004041/* Buttons */42#define DSMG600_PB_GPIO 15 /* power button */43#define DSMG600_RB_GPIO 3 /* reset button */4445/* Power control */46#define DSMG600_PO_GPIO 2 /* power off */4748/* LEDs */49#define DSMG600_LED_PWR_GPIO 050#define DSMG600_LED_WLAN_GPIO 145152static struct flash_platform_data dsmg600_flash_data = {53.map_name = "cfi_probe",54.width = 2,55};5657static struct resource dsmg600_flash_resource = {58.flags = IORESOURCE_MEM,59};6061static struct platform_device dsmg600_flash = {62.name = "IXP4XX-Flash",63.id = 0,64.dev.platform_data = &dsmg600_flash_data,65.num_resources = 1,66.resource = &dsmg600_flash_resource,67};6869static struct i2c_gpio_platform_data dsmg600_i2c_gpio_data = {70.sda_pin = DSMG600_SDA_PIN,71.scl_pin = DSMG600_SCL_PIN,72};7374static struct platform_device dsmg600_i2c_gpio = {75.name = "i2c-gpio",76.id = 0,77.dev = {78.platform_data = &dsmg600_i2c_gpio_data,79},80};8182static struct i2c_board_info __initdata dsmg600_i2c_board_info [] = {83{84I2C_BOARD_INFO("pcf8563", 0x51),85},86};8788static struct gpio_led dsmg600_led_pins[] = {89{90.name = "dsmg600:green:power",91.gpio = DSMG600_LED_PWR_GPIO,92},93{94.name = "dsmg600:green:wlan",95.gpio = DSMG600_LED_WLAN_GPIO,96.active_low = true,97},98};99100static struct gpio_led_platform_data dsmg600_led_data = {101.num_leds = ARRAY_SIZE(dsmg600_led_pins),102.leds = dsmg600_led_pins,103};104105static struct platform_device dsmg600_leds = {106.name = "leds-gpio",107.id = -1,108.dev.platform_data = &dsmg600_led_data,109};110111static struct resource dsmg600_uart_resources[] = {112{113.start = IXP4XX_UART1_BASE_PHYS,114.end = IXP4XX_UART1_BASE_PHYS + 0x0fff,115.flags = IORESOURCE_MEM,116},117{118.start = IXP4XX_UART2_BASE_PHYS,119.end = IXP4XX_UART2_BASE_PHYS + 0x0fff,120.flags = IORESOURCE_MEM,121}122};123124static struct plat_serial8250_port dsmg600_uart_data[] = {125{126.mapbase = IXP4XX_UART1_BASE_PHYS,127.membase = (char *)IXP4XX_UART1_BASE_VIRT + REG_OFFSET,128.irq = IRQ_IXP4XX_UART1,129.flags = UPF_BOOT_AUTOCONF,130.iotype = UPIO_MEM,131.regshift = 2,132.uartclk = IXP4XX_UART_XTAL,133},134{135.mapbase = IXP4XX_UART2_BASE_PHYS,136.membase = (char *)IXP4XX_UART2_BASE_VIRT + REG_OFFSET,137.irq = IRQ_IXP4XX_UART2,138.flags = UPF_BOOT_AUTOCONF,139.iotype = UPIO_MEM,140.regshift = 2,141.uartclk = IXP4XX_UART_XTAL,142},143{ }144};145146static struct platform_device dsmg600_uart = {147.name = "serial8250",148.id = PLAT8250_DEV_PLATFORM,149.dev.platform_data = dsmg600_uart_data,150.num_resources = ARRAY_SIZE(dsmg600_uart_resources),151.resource = dsmg600_uart_resources,152};153154static struct platform_device *dsmg600_devices[] __initdata = {155&dsmg600_i2c_gpio,156&dsmg600_flash,157&dsmg600_leds,158};159160static void dsmg600_power_off(void)161{162/* enable the pwr cntl gpio */163gpio_line_config(DSMG600_PO_GPIO, IXP4XX_GPIO_OUT);164165/* poweroff */166gpio_line_set(DSMG600_PO_GPIO, IXP4XX_GPIO_HIGH);167}168169/* This is used to make sure the power-button pusher is serious. The button170* must be held until the value of this counter reaches zero.171*/172static int power_button_countdown;173174/* Must hold the button down for at least this many counts to be processed */175#define PBUTTON_HOLDDOWN_COUNT 4 /* 2 secs */176177static void dsmg600_power_handler(unsigned long data);178static DEFINE_TIMER(dsmg600_power_timer, dsmg600_power_handler, 0, 0);179180static void dsmg600_power_handler(unsigned long data)181{182/* This routine is called twice per second to check the183* state of the power button.184*/185186if (gpio_get_value(DSMG600_PB_GPIO)) {187188/* IO Pin is 1 (button pushed) */189if (power_button_countdown > 0)190power_button_countdown--;191192} else {193194/* Done on button release, to allow for auto-power-on mods. */195if (power_button_countdown == 0) {196/* Signal init to do the ctrlaltdel action,197* this will bypass init if it hasn't started198* and do a kernel_restart.199*/200ctrl_alt_del();201202/* Change the state of the power LED to "blink" */203gpio_line_set(DSMG600_LED_PWR_GPIO, IXP4XX_GPIO_LOW);204} else {205power_button_countdown = PBUTTON_HOLDDOWN_COUNT;206}207}208209mod_timer(&dsmg600_power_timer, jiffies + msecs_to_jiffies(500));210}211212static irqreturn_t dsmg600_reset_handler(int irq, void *dev_id)213{214/* This is the paper-clip reset, it shuts the machine down directly. */215machine_power_off();216217return IRQ_HANDLED;218}219220static void __init dsmg600_timer_init(void)221{222/* The xtal on this machine is non-standard. */223ixp4xx_timer_freq = DSMG600_FREQ;224225/* Call standard timer_init function. */226ixp4xx_timer_init();227}228229static struct sys_timer dsmg600_timer = {230.init = dsmg600_timer_init,231};232233static void __init dsmg600_init(void)234{235ixp4xx_sys_init();236237/* Make sure that GPIO14 and GPIO15 are not used as clocks */238*IXP4XX_GPIO_GPCLKR = 0;239240dsmg600_flash_resource.start = IXP4XX_EXP_BUS_BASE(0);241dsmg600_flash_resource.end =242IXP4XX_EXP_BUS_BASE(0) + ixp4xx_exp_bus_size - 1;243244i2c_register_board_info(0, dsmg600_i2c_board_info,245ARRAY_SIZE(dsmg600_i2c_board_info));246247/* The UART is required on the DSM-G600 (Redboot cannot use the248* NIC) -- do it here so that it does *not* get removed if249* platform_add_devices fails!250*/251(void)platform_device_register(&dsmg600_uart);252253platform_add_devices(dsmg600_devices, ARRAY_SIZE(dsmg600_devices));254255pm_power_off = dsmg600_power_off;256257if (request_irq(gpio_to_irq(DSMG600_RB_GPIO), &dsmg600_reset_handler,258IRQF_DISABLED | IRQF_TRIGGER_LOW,259"DSM-G600 reset button", NULL) < 0) {260261printk(KERN_DEBUG "Reset Button IRQ %d not available\n",262gpio_to_irq(DSMG600_RB_GPIO));263}264265/* The power button on the D-Link DSM-G600 is on GPIO 15, but266* it cannot handle interrupts on that GPIO line. So we'll267* have to poll it with a kernel timer.268*/269270/* Make sure that the power button GPIO is set up as an input */271gpio_line_config(DSMG600_PB_GPIO, IXP4XX_GPIO_IN);272273/* Set the initial value for the power button IRQ handler */274power_button_countdown = PBUTTON_HOLDDOWN_COUNT;275276mod_timer(&dsmg600_power_timer, jiffies + msecs_to_jiffies(500));277}278279MACHINE_START(DSMG600, "D-Link DSM-G600 RevA")280/* Maintainer: www.nslu2-linux.org */281.boot_params = 0x00000100,282.map_io = ixp4xx_map_io,283.init_irq = ixp4xx_init_irq,284.timer = &dsmg600_timer,285.init_machine = dsmg600_init,286MACHINE_END287288289