nas100d-setup.c 7.9 KB
Newer Older
1 2 3 4 5
/*
 * arch/arm/mach-ixp4xx/nas100d-setup.c
 *
 * NAS 100d board-setup
 *
6 7 8
 * Copyright (C) 2008 Rod Whitby <rod@whitby.id.au>
 *
 * based on ixdp425-setup.c:
9
 *      Copyright (C) 2003-2004 MontaVista Software, Inc.
10 11 12 13
 * based on nas100d-power.c:
 *	Copyright (C) 2005 Tower Technologies
 * based on nas100d-io.c
 *	Copyright (C) 2004 Karen Spearel
14 15 16 17 18 19
 *
 * Author: Alessandro Zummo <a.zummo@towertech.it>
 * Author: Rod Whitby <rod@whitby.id.au>
 * Maintainers: http://www.nslu2-linux.org/
 *
 */
20
#include <linux/gpio.h>
21
#include <linux/if_ether.h>
22 23 24
#include <linux/irq.h>
#include <linux/jiffies.h>
#include <linux/timer.h>
25 26
#include <linux/serial.h>
#include <linux/serial_8250.h>
27
#include <linux/leds.h>
28
#include <linux/reboot.h>
29
#include <linux/i2c.h>
M
Michael-Luke Jones 已提交
30
#include <linux/i2c-gpio.h>
31
#include <linux/io.h>
32 33 34 35
#include <asm/mach-types.h>
#include <asm/mach/arch.h>
#include <asm/mach/flash.h>

36 37 38 39 40 41 42 43 44 45 46 47 48 49 50
#define NAS100D_SDA_PIN		5
#define NAS100D_SCL_PIN		6

/* Buttons */
#define NAS100D_PB_GPIO         14   /* power button */
#define NAS100D_RB_GPIO         4    /* reset button */

/* Power control */
#define NAS100D_PO_GPIO         12   /* power off */

/* LEDs */
#define NAS100D_LED_WLAN_GPIO	0
#define NAS100D_LED_DISK_GPIO	3
#define NAS100D_LED_PWR_GPIO	15

51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67
static struct flash_platform_data nas100d_flash_data = {
	.map_name		= "cfi_probe",
	.width			= 2,
};

static struct resource nas100d_flash_resource = {
	.flags			= IORESOURCE_MEM,
};

static struct platform_device nas100d_flash = {
	.name			= "IXP4XX-Flash",
	.id			= 0,
	.dev.platform_data	= &nas100d_flash_data,
	.num_resources		= 1,
	.resource		= &nas100d_flash_resource,
};

68 69
static struct i2c_board_info __initdata nas100d_i2c_board_info [] = {
	{
70
		I2C_BOARD_INFO("pcf8563", 0x51),
71 72 73
	},
};

74
static struct gpio_led nas100d_led_pins[] = {
75
	{
76
		.name		= "nas100d:green:wlan",
77 78
		.gpio		= NAS100D_LED_WLAN_GPIO,
		.active_low	= true,
79 80
	},
	{
81
		.name		= "nas100d:blue:power",  /* (off=flashing) */
82 83
		.gpio		= NAS100D_LED_PWR_GPIO,
		.active_low	= true,
84 85
	},
	{
86
		.name		= "nas100d:yellow:disk",
87 88
		.gpio		= NAS100D_LED_DISK_GPIO,
		.active_low	= true,
89 90 91
	},
};

92 93 94 95 96
static struct gpio_led_platform_data nas100d_led_data = {
	.num_leds		= ARRAY_SIZE(nas100d_led_pins),
	.leds			= nas100d_led_pins,
};

97
static struct platform_device nas100d_leds = {
98
	.name			= "leds-gpio",
99
	.id			= -1,
100
	.dev.platform_data	= &nas100d_led_data,
101 102
};

M
Michael-Luke Jones 已提交
103
static struct i2c_gpio_platform_data nas100d_i2c_gpio_data = {
104 105 106 107
	.sda_pin		= NAS100D_SDA_PIN,
	.scl_pin		= NAS100D_SCL_PIN,
};

M
Michael-Luke Jones 已提交
108 109
static struct platform_device nas100d_i2c_gpio = {
	.name			= "i2c-gpio",
110
	.id			= 0,
M
Michael-Luke Jones 已提交
111 112 113
	.dev	 = {
		.platform_data	= &nas100d_i2c_gpio_data,
	},
114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158
};

static struct resource nas100d_uart_resources[] = {
	{
		.start		= IXP4XX_UART1_BASE_PHYS,
		.end		= IXP4XX_UART1_BASE_PHYS + 0x0fff,
		.flags		= IORESOURCE_MEM,
	},
	{
		.start		= IXP4XX_UART2_BASE_PHYS,
		.end		= IXP4XX_UART2_BASE_PHYS + 0x0fff,
		.flags		= IORESOURCE_MEM,
	}
};

static struct plat_serial8250_port nas100d_uart_data[] = {
	{
		.mapbase	= IXP4XX_UART1_BASE_PHYS,
		.membase	= (char *)IXP4XX_UART1_BASE_VIRT + REG_OFFSET,
		.irq		= IRQ_IXP4XX_UART1,
		.flags		= UPF_BOOT_AUTOCONF,
		.iotype		= UPIO_MEM,
		.regshift	= 2,
		.uartclk	= IXP4XX_UART_XTAL,
	},
	{
		.mapbase	= IXP4XX_UART2_BASE_PHYS,
		.membase	= (char *)IXP4XX_UART2_BASE_VIRT + REG_OFFSET,
		.irq		= IRQ_IXP4XX_UART2,
		.flags		= UPF_BOOT_AUTOCONF,
		.iotype		= UPIO_MEM,
		.regshift	= 2,
		.uartclk	= IXP4XX_UART_XTAL,
	},
	{ }
};

static struct platform_device nas100d_uart = {
	.name			= "serial8250",
	.id			= PLAT8250_DEV_PLATFORM,
	.dev.platform_data	= nas100d_uart_data,
	.num_resources		= 2,
	.resource		= nas100d_uart_resources,
};

159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175
/* Built-in 10/100 Ethernet MAC interfaces */
static struct eth_plat_info nas100d_plat_eth[] = {
	{
		.phy		= 0,
		.rxq		= 3,
		.txreadyq	= 20,
	}
};

static struct platform_device nas100d_eth[] = {
	{
		.name			= "ixp4xx_eth",
		.id			= IXP4XX_ETH_NPEB,
		.dev.platform_data	= nas100d_plat_eth,
	}
};

176
static struct platform_device *nas100d_devices[] __initdata = {
M
Michael-Luke Jones 已提交
177
	&nas100d_i2c_gpio,
178
	&nas100d_flash,
179
	&nas100d_leds,
180
	&nas100d_eth[0],
181 182 183 184 185 186 187 188 189 190 191 192 193
};

static void nas100d_power_off(void)
{
	/* This causes the box to drop the power and go dead. */

	/* enable the pwr cntl gpio */
	gpio_line_config(NAS100D_PO_GPIO, IXP4XX_GPIO_OUT);

	/* do the deed */
	gpio_line_set(NAS100D_PO_GPIO, IXP4XX_GPIO_HIGH);
}

194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244
/* This is used to make sure the power-button pusher is serious.  The button
 * must be held until the value of this counter reaches zero.
 */
static int power_button_countdown;

/* Must hold the button down for at least this many counts to be processed */
#define PBUTTON_HOLDDOWN_COUNT 4 /* 2 secs */

static void nas100d_power_handler(unsigned long data);
static DEFINE_TIMER(nas100d_power_timer, nas100d_power_handler, 0, 0);

static void nas100d_power_handler(unsigned long data)
{
	/* This routine is called twice per second to check the
	 * state of the power button.
	 */

	if (gpio_get_value(NAS100D_PB_GPIO)) {

		/* IO Pin is 1 (button pushed) */
		if (power_button_countdown > 0)
			power_button_countdown--;

	} else {

		/* Done on button release, to allow for auto-power-on mods. */
		if (power_button_countdown == 0) {
			/* Signal init to do the ctrlaltdel action,
			 * this will bypass init if it hasn't started
			 * and do a kernel_restart.
			 */
			ctrl_alt_del();

			/* Change the state of the power LED to "blink" */
			gpio_line_set(NAS100D_LED_PWR_GPIO, IXP4XX_GPIO_LOW);
		} else {
			power_button_countdown = PBUTTON_HOLDDOWN_COUNT;
		}
	}

	mod_timer(&nas100d_power_timer, jiffies + msecs_to_jiffies(500));
}

static irqreturn_t nas100d_reset_handler(int irq, void *dev_id)
{
	/* This is the paper-clip reset, it shuts the machine down directly. */
	machine_power_off();

	return IRQ_HANDLED;
}

245 246
static void __init nas100d_init(void)
{
247 248 249
	uint8_t __iomem *f;
	int i;

250 251
	ixp4xx_sys_init();

252 253 254
	/* gpio 14 and 15 are _not_ clocks */
	*IXP4XX_GPIO_GPCLKR = 0;

255 256 257 258
	nas100d_flash_resource.start = IXP4XX_EXP_BUS_BASE(0);
	nas100d_flash_resource.end =
		IXP4XX_EXP_BUS_BASE(0) + ixp4xx_exp_bus_size - 1;

259 260 261
	i2c_register_board_info(0, nas100d_i2c_board_info,
				ARRAY_SIZE(nas100d_i2c_board_info));

262 263
	/*
	 * This is only useful on a modified machine, but it is valuable
264 265 266 267 268
	 * to have it first in order to see debug messages, and so that
	 * it does *not* get removed if platform_add_devices fails!
	 */
	(void)platform_device_register(&nas100d_uart);

269
	platform_add_devices(nas100d_devices, ARRAY_SIZE(nas100d_devices));
270

271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293
	pm_power_off = nas100d_power_off;

	if (request_irq(gpio_to_irq(NAS100D_RB_GPIO), &nas100d_reset_handler,
		IRQF_DISABLED | IRQF_TRIGGER_LOW,
		"NAS100D reset button", NULL) < 0) {

		printk(KERN_DEBUG "Reset Button IRQ %d not available\n",
			gpio_to_irq(NAS100D_RB_GPIO));
	}

	/* The power button on the Iomega NAS100d is on GPIO 14, but
	 * it cannot handle interrupts on that GPIO line.  So we'll
	 * have to poll it with a kernel timer.
	 */

	/* Make sure that the power button GPIO is set up as an input */
	gpio_line_config(NAS100D_PB_GPIO, IXP4XX_GPIO_IN);

	/* Set the initial value for the power button IRQ handler */
	power_button_countdown = PBUTTON_HOLDDOWN_COUNT;

	mod_timer(&nas100d_power_timer, jiffies + msecs_to_jiffies(500));

294 295 296 297 298 299 300 301 302 303 304 305 306 307 308
	/*
	 * Map in a portion of the flash and read the MAC address.
	 * Since it is stored in BE in the flash itself, we need to
	 * byteswap it if we're in LE mode.
	 */
	f = ioremap(IXP4XX_EXP_BUS_BASE(0), 0x1000000);
	if (f) {
		for (i = 0; i < 6; i++)
#ifdef __ARMEB__
			nas100d_plat_eth[0].hwaddr[i] = readb(f + 0xFC0FD8 + i);
#else
			nas100d_plat_eth[0].hwaddr[i] = readb(f + 0xFC0FD8 + (i^3));
#endif
		iounmap(f);
	}
J
Johannes Berg 已提交
309 310
	printk(KERN_INFO "NAS100D: Using MAC address %pM for port 0\n",
	       nas100d_plat_eth[0].hwaddr);
311

312 313 314 315
}

MACHINE_START(NAS100D, "Iomega NAS 100d")
	/* Maintainer: www.nslu2-linux.org */
316
	.atag_offset	= 0x100,
317
	.map_io		= ixp4xx_map_io,
318
	.init_early	= ixp4xx_init_early,
319 320 321
	.init_irq	= ixp4xx_init_irq,
	.timer          = &ixp4xx_timer,
	.init_machine	= nas100d_init,
322 323 324
#if defined(CONFIG_PCI)
	.dma_zone_size	= SZ_64M,
#endif
325
	.restart	= ixp4xx_restart,
326
MACHINE_END