Linux-2.6.12-rc2

Initial git repository build. I'm not bothering with the full history,
even though we have it. We can create a separate "historical" git
archive of that later if we want to, and in the meantime it's about
3.2GB when imported into git - space that would just make the early
git days unnecessarily complicated, when we don't have a lot of good
infrastructure for it.

Let it rip!
diff --git a/arch/arm/mach-imx/Kconfig b/arch/arm/mach-imx/Kconfig
new file mode 100644
index 0000000..ec85813
--- /dev/null
+++ b/arch/arm/mach-imx/Kconfig
@@ -0,0 +1,10 @@
+menu "IMX Implementations"
+	depends on ARCH_IMX
+
+config ARCH_MX1ADS
+	bool "mx1ads"
+	depends on ARCH_IMX
+	help
+	  Say Y here if you are using the Motorola MX1ADS board
+
+endmenu
diff --git a/arch/arm/mach-imx/Makefile b/arch/arm/mach-imx/Makefile
new file mode 100644
index 0000000..0b27d79f
--- /dev/null
+++ b/arch/arm/mach-imx/Makefile
@@ -0,0 +1,19 @@
+#
+# Makefile for the linux kernel.
+#
+# Note! Dependencies are done automagically by 'make dep', which also
+# removes any old dependencies. DON'T put your own dependencies here
+# unless it's something special (ie not a .c file).
+
+# Object file lists.
+
+obj-y			+= irq.o time.o dma.o generic.o
+
+# Specific board support
+obj-$(CONFIG_ARCH_MX1ADS) += mx1ads.o
+
+# Support for blinky lights
+led-y := leds.o
+
+obj-$(CONFIG_LEDS)	+=  $(led-y)
+led-$(CONFIG_ARCH_MX1ADS) += leds-mx1ads.o
diff --git a/arch/arm/mach-imx/Makefile.boot b/arch/arm/mach-imx/Makefile.boot
new file mode 100644
index 0000000..fd72ce5
--- /dev/null
+++ b/arch/arm/mach-imx/Makefile.boot
@@ -0,0 +1,2 @@
+    zreladdr-$(CONFIG_ARCH_MX1ADS)	:= 0x08008000
+
diff --git a/arch/arm/mach-imx/dma.c b/arch/arm/mach-imx/dma.c
new file mode 100644
index 0000000..71a59e1
--- /dev/null
+++ b/arch/arm/mach-imx/dma.c
@@ -0,0 +1,203 @@
+/*
+ *  linux/arch/arm/mach-imx/dma.c
+ *
+ *  imx DMA registration and IRQ dispatching
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License version 2 as
+ *  published by the Free Software Foundation.
+ *
+ *  03/03/2004 Sascha Hauer <sascha@saschahauer.de>
+ *             initial version heavily inspired by
+ *             linux/arch/arm/mach-pxa/dma.c
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/interrupt.h>
+#include <linux/errno.h>
+
+#include <asm/system.h>
+#include <asm/irq.h>
+#include <asm/hardware.h>
+#include <asm/dma.h>
+
+static struct dma_channel {
+	char *name;
+	void (*irq_handler) (int, void *, struct pt_regs *);
+	void (*err_handler) (int, void *, struct pt_regs *);
+	void *data;
+} dma_channels[11];
+
+/* set err_handler to NULL to have the standard info-only error handler */
+int
+imx_request_dma(char *name, imx_dma_prio prio,
+		void (*irq_handler) (int, void *, struct pt_regs *),
+		void (*err_handler) (int, void *, struct pt_regs *), void *data)
+{
+	unsigned long flags;
+	int i, found = 0;
+
+	/* basic sanity checks */
+	if (!name || !irq_handler)
+		return -EINVAL;
+
+	local_irq_save(flags);
+
+	/* try grabbing a DMA channel with the requested priority */
+	for (i = prio; i < prio + (prio == DMA_PRIO_LOW) ? 8 : 4; i++) {
+		if (!dma_channels[i].name) {
+			found = 1;
+			break;
+		}
+	}
+
+	if (!found) {
+		/* requested prio group is full, try hier priorities */
+		for (i = prio - 1; i >= 0; i--) {
+			if (!dma_channels[i].name) {
+				found = 1;
+				break;
+			}
+		}
+	}
+
+	if (found) {
+		DIMR &= ~(1 << i);
+		dma_channels[i].name = name;
+		dma_channels[i].irq_handler = irq_handler;
+		dma_channels[i].err_handler = err_handler;
+		dma_channels[i].data = data;
+	} else {
+		printk(KERN_WARNING "No more available DMA channels for %s\n",
+		       name);
+		i = -ENODEV;
+	}
+
+	local_irq_restore(flags);
+	return i;
+}
+
+void
+imx_free_dma(int dma_ch)
+{
+	unsigned long flags;
+
+	if (!dma_channels[dma_ch].name) {
+		printk(KERN_CRIT
+		       "%s: trying to free channel %d which is already freed\n",
+		       __FUNCTION__, dma_ch);
+		return;
+	}
+
+	local_irq_save(flags);
+	DIMR &= ~(1 << dma_ch);
+	dma_channels[dma_ch].name = NULL;
+	local_irq_restore(flags);
+}
+
+static irqreturn_t
+dma_err_handler(int irq, void *dev_id, struct pt_regs *regs)
+{
+	int i, disr = DISR;
+	struct dma_channel *channel;
+	unsigned int err_mask = DBTOSR | DRTOSR | DSESR | DBOSR;
+
+	DISR = disr;
+	for (i = 0; i < 11; i++) {
+		channel = &dma_channels[i];
+
+		if ( (err_mask & 1<<i) && channel->name && channel->err_handler) {
+			channel->err_handler(i, channel->data, regs);
+			continue;
+		}
+
+		if (DBTOSR & (1 << i)) {
+			printk(KERN_WARNING
+			       "Burst timeout on channel %d (%s)\n",
+			       i, channel->name);
+			DBTOSR |= (1 << i);
+		}
+		if (DRTOSR & (1 << i)) {
+			printk(KERN_WARNING
+			       "Request timeout on channel %d (%s)\n",
+			       i, channel->name);
+			DRTOSR |= (1 << i);
+		}
+		if (DSESR & (1 << i)) {
+			printk(KERN_WARNING
+			       "Transfer timeout on channel %d (%s)\n",
+			       i, channel->name);
+			DSESR |= (1 << i);
+		}
+		if (DBOSR & (1 << i)) {
+			printk(KERN_WARNING
+			       "Buffer overflow timeout on channel %d (%s)\n",
+			       i, channel->name);
+			DBOSR |= (1 << i);
+		}
+	}
+	return IRQ_HANDLED;
+}
+
+static irqreturn_t
+dma_irq_handler(int irq, void *dev_id, struct pt_regs *regs)
+{
+	int i, disr = DISR;
+
+	DISR = disr;
+	for (i = 0; i < 11; i++) {
+		if (disr & (1 << i)) {
+			struct dma_channel *channel = &dma_channels[i];
+			if (channel->name && channel->irq_handler) {
+				channel->irq_handler(i, channel->data, regs);
+			} else {
+				/*
+				 * IRQ for an unregistered DMA channel:
+				 * let's clear the interrupts and disable it.
+				 */
+				printk(KERN_WARNING
+				       "spurious IRQ for DMA channel %d\n", i);
+			}
+		}
+	}
+	return IRQ_HANDLED;
+}
+
+static int __init
+imx_dma_init(void)
+{
+	int ret;
+
+	/* reset DMA module */
+	DCR = DCR_DRST;
+
+	ret = request_irq(DMA_INT, dma_irq_handler, 0, "DMA", NULL);
+	if (ret) {
+		printk(KERN_CRIT "Wow!  Can't register IRQ for DMA\n");
+		return ret;
+	}
+
+	ret = request_irq(DMA_ERR, dma_err_handler, 0, "DMA", NULL);
+	if (ret) {
+		printk(KERN_CRIT "Wow!  Can't register ERRIRQ for DMA\n");
+		free_irq(DMA_INT, NULL);
+	}
+
+	/* enable DMA module */
+	DCR = DCR_DEN;
+
+	/* clear all interrupts */
+	DISR = 0x3ff;
+
+	/* enable interrupts */
+	DIMR = 0;
+
+	return ret;
+}
+
+arch_initcall(imx_dma_init);
+
+EXPORT_SYMBOL(imx_request_dma);
+EXPORT_SYMBOL(imx_free_dma);
diff --git a/arch/arm/mach-imx/generic.c b/arch/arm/mach-imx/generic.c
new file mode 100644
index 0000000..54377d0
--- /dev/null
+++ b/arch/arm/mach-imx/generic.c
@@ -0,0 +1,274 @@
+/*
+ *  arch/arm/mach-imx/generic.c
+ *
+ *  author: Sascha Hauer
+ *  Created: april 20th, 2004
+ *  Copyright: Synertronixx GmbH
+ *
+ *  Common code for i.MX machines
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ */
+#include <linux/device.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <asm/hardware.h>
+
+#include <asm/mach/map.h>
+
+void imx_gpio_mode(int gpio_mode)
+{
+	unsigned int pin = gpio_mode & GPIO_PIN_MASK;
+	unsigned int port = (gpio_mode & GPIO_PORT_MASK) >> 5;
+	unsigned int ocr = (gpio_mode & GPIO_OCR_MASK) >> 10;
+	unsigned int tmp;
+
+	/* Pullup enable */
+	if(gpio_mode & GPIO_PUEN)
+		PUEN(port) |= (1<<pin);
+	else
+		PUEN(port) &= ~(1<<pin);
+
+	/* Data direction */
+	if(gpio_mode & GPIO_OUT)
+		DDIR(port) |= 1<<pin;
+	else
+		DDIR(port) &= ~(1<<pin);
+
+	/* Primary / alternate function */
+	if(gpio_mode & GPIO_AF)
+		GPR(port) |= (1<<pin);
+	else
+		GPR(port) &= ~(1<<pin);
+
+	/* use as gpio? */
+	if( ocr == 3 )
+		GIUS(port) |= (1<<pin);
+	else
+		GIUS(port) &= ~(1<<pin);
+
+	/* Output / input configuration */
+	/* FIXME: I'm not very sure about OCR and ICONF, someone
+	 * should have a look over it
+	 */
+	if(pin<16) {
+		tmp = OCR1(port);
+		tmp &= ~( 3<<(pin*2));
+		tmp |= (ocr << (pin*2));
+		OCR1(port) = tmp;
+
+		if( gpio_mode &	GPIO_AOUT )
+			ICONFA1(port) &= ~( 3<<(pin*2));
+		if( gpio_mode &	GPIO_BOUT )
+			ICONFB1(port) &= ~( 3<<(pin*2));
+	} else {
+		tmp = OCR2(port);
+		tmp &= ~( 3<<((pin-16)*2));
+		tmp |= (ocr << ((pin-16)*2));
+		OCR2(port) = tmp;
+
+		if( gpio_mode &	GPIO_AOUT )
+			ICONFA2(port) &= ~( 3<<((pin-16)*2));
+		if( gpio_mode &	GPIO_BOUT )
+			ICONFB2(port) &= ~( 3<<((pin-16)*2));
+	}
+}
+
+EXPORT_SYMBOL(imx_gpio_mode);
+
+/*
+ *  get the system pll clock in Hz
+ *
+ *                  mfi + mfn / (mfd +1)
+ *  f = 2 * f_ref * --------------------
+ *                        pd + 1
+ */
+static unsigned int imx_decode_pll(unsigned int pll)
+{
+	u32 mfi = (pll >> 10) & 0xf;
+	u32 mfn = pll & 0x3ff;
+	u32 mfd = (pll >> 16) & 0x3ff;
+	u32 pd =  (pll >> 26) & 0xf;
+	u32 f_ref = (CSCR & CSCR_SYSTEM_SEL) ? 16000000 : (CLK32 * 512);
+
+	mfi = mfi <= 5 ? 5 : mfi;
+
+	return (2 * (f_ref>>10) * ( (mfi<<10) + (mfn<<10) / (mfd+1) )) / (pd+1);
+}
+
+unsigned int imx_get_system_clk(void)
+{
+	return imx_decode_pll(SPCTL0);
+}
+EXPORT_SYMBOL(imx_get_system_clk);
+
+unsigned int imx_get_mcu_clk(void)
+{
+	return imx_decode_pll(MPCTL0);
+}
+EXPORT_SYMBOL(imx_get_mcu_clk);
+
+/*
+ *  get peripheral clock 1 ( UART[12], Timer[12], PWM )
+ */
+unsigned int imx_get_perclk1(void)
+{
+	return imx_get_system_clk() / (((PCDR) & 0xf)+1);
+}
+EXPORT_SYMBOL(imx_get_perclk1);
+
+/*
+ *  get peripheral clock 2 ( LCD, SD, SPI[12] )
+ */
+unsigned int imx_get_perclk2(void)
+{
+	return imx_get_system_clk() / (((PCDR>>4) & 0xf)+1);
+}
+EXPORT_SYMBOL(imx_get_perclk2);
+
+/*
+ *  get peripheral clock 3 ( SSI )
+ */
+unsigned int imx_get_perclk3(void)
+{
+	return imx_get_system_clk() / (((PCDR>>16) & 0x7f)+1);
+}
+EXPORT_SYMBOL(imx_get_perclk3);
+
+/*
+ *  get hclk ( SDRAM, CSI, Memory Stick, I2C, DMA )
+ */
+unsigned int imx_get_hclk(void)
+{
+	return imx_get_system_clk() / (((CSCR>>10) & 0xf)+1);
+}
+EXPORT_SYMBOL(imx_get_hclk);
+
+static struct resource imx_mmc_resources[] = {
+	[0] = {
+		.start	= 0x00214000,
+		.end	= 0x002140FF,
+		.flags	= IORESOURCE_MEM,
+	},
+	[1] = {
+		.start	= (SDHC_INT),
+		.end	= (SDHC_INT),
+		.flags	= IORESOURCE_IRQ,
+	},
+};
+
+static struct platform_device imx_mmc_device = {
+	.name		= "imx-mmc",
+	.id		= 0,
+	.num_resources	= ARRAY_SIZE(imx_mmc_resources),
+	.resource	= imx_mmc_resources,
+};
+
+static struct resource imx_uart1_resources[] = {
+	[0] = {
+		.start	= 0x00206000,
+		.end	= 0x002060FF,
+		.flags	= IORESOURCE_MEM,
+	},
+	[1] = {
+		.start	= (UART1_MINT_RX),
+		.end	= (UART1_MINT_RX),
+		.flags	= IORESOURCE_IRQ,
+	},
+	[2] = {
+		.start	= (UART1_MINT_TX),
+		.end	= (UART1_MINT_TX),
+		.flags	= IORESOURCE_IRQ,
+	},
+};
+
+static struct platform_device imx_uart1_device = {
+	.name		= "imx-uart",
+	.id		= 0,
+	.num_resources	= ARRAY_SIZE(imx_uart1_resources),
+	.resource	= imx_uart1_resources,
+};
+
+static struct resource imx_uart2_resources[] = {
+	[0] = {
+		.start	= 0x00207000,
+		.end	= 0x002070FF,
+		.flags	= IORESOURCE_MEM,
+	},
+	[1] = {
+		.start	= (UART2_MINT_RX),
+		.end	= (UART2_MINT_RX),
+		.flags	= IORESOURCE_IRQ,
+	},
+	[2] = {
+		.start	= (UART2_MINT_TX),
+		.end	= (UART2_MINT_TX),
+		.flags	= IORESOURCE_IRQ,
+	},
+};
+
+static struct platform_device imx_uart2_device = {
+	.name		= "imx-uart",
+	.id		= 1,
+	.num_resources	= ARRAY_SIZE(imx_uart2_resources),
+	.resource	= imx_uart2_resources,
+};
+
+static struct resource imxfb_resources[] = {
+	[0] = {
+		.start	= 0x00205000,
+		.end	= 0x002050FF,
+		.flags	= IORESOURCE_MEM,
+	},
+	[1] = {
+		.start	= LCDC_INT,
+		.end	= LCDC_INT,
+		.flags	= IORESOURCE_IRQ,
+	},
+};
+
+static struct platform_device imxfb_device = {
+	.name		= "imx-fb",
+	.id		= 0,
+	.num_resources	= ARRAY_SIZE(imxfb_resources),
+	.resource	= imxfb_resources,
+};
+
+static struct platform_device *devices[] __initdata = {
+	&imx_mmc_device,
+	&imxfb_device,
+	&imx_uart1_device,
+	&imx_uart2_device,
+};
+
+static struct map_desc imx_io_desc[] __initdata = {
+	/* virtual     physical    length      type */
+	{IMX_IO_BASE, IMX_IO_PHYS, IMX_IO_SIZE, MT_DEVICE},
+};
+
+void __init
+imx_map_io(void)
+{
+	iotable_init(imx_io_desc, ARRAY_SIZE(imx_io_desc));
+}
+
+static int __init imx_init(void)
+{
+	return platform_add_devices(devices, ARRAY_SIZE(devices));
+}
+
+subsys_initcall(imx_init);
diff --git a/arch/arm/mach-imx/generic.h b/arch/arm/mach-imx/generic.h
new file mode 100644
index 0000000..e91003e
--- /dev/null
+++ b/arch/arm/mach-imx/generic.h
@@ -0,0 +1,16 @@
+/*
+ *  linux/arch/arm/mach-imx/generic.h
+ *
+ * Author:	Sascha Hauer <sascha@saschahauer.de>
+ * Copyright:	Synertronixx GmbH
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+extern void __init imx_map_io(void);
+extern void __init imx_init_irq(void);
+
+struct sys_timer;
+extern struct sys_timer imx_timer;
diff --git a/arch/arm/mach-imx/irq.c b/arch/arm/mach-imx/irq.c
new file mode 100644
index 0000000..0c27134
--- /dev/null
+++ b/arch/arm/mach-imx/irq.c
@@ -0,0 +1,252 @@
+/*
+ *  linux/arch/arm/mach-imx/irq.c
+ *
+ *  Copyright (C) 1999 ARM Limited
+ *  Copyright (C) 2002 Shane Nay (shane@minirl.com)
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ *  03/03/2004   Sascha Hauer <sascha@saschahauer.de>
+ *               Copied from the motorola bsp package and added gpio demux
+ *               interrupt handler
+ */
+
+#include <linux/init.h>
+#include <linux/list.h>
+#include <linux/timer.h>
+
+#include <asm/hardware.h>
+#include <asm/irq.h>
+#include <asm/io.h>
+
+#include <asm/mach/irq.h>
+
+/*
+ *
+ * We simply use the ENABLE DISABLE registers inside of the IMX
+ * to turn on/off specific interrupts.  FIXME- We should
+ * also add support for the accelerated interrupt controller
+ * by putting offets to irq jump code in the appropriate
+ * places.
+ *
+ */
+
+#define INTENNUM_OFF              0x8
+#define INTDISNUM_OFF             0xC
+
+#define VA_AITC_BASE              IO_ADDRESS(IMX_AITC_BASE)
+#define IMX_AITC_INTDISNUM       (VA_AITC_BASE + INTDISNUM_OFF)
+#define IMX_AITC_INTENNUM        (VA_AITC_BASE + INTENNUM_OFF)
+
+#if 0
+#define DEBUG_IRQ(fmt...)	printk(fmt)
+#else
+#define DEBUG_IRQ(fmt...)	do { } while (0)
+#endif
+
+static void
+imx_mask_irq(unsigned int irq)
+{
+	__raw_writel(irq, IMX_AITC_INTDISNUM);
+}
+
+static void
+imx_unmask_irq(unsigned int irq)
+{
+	__raw_writel(irq, IMX_AITC_INTENNUM);
+}
+
+static int
+imx_gpio_irq_type(unsigned int _irq, unsigned int type)
+{
+	unsigned int irq_type = 0, irq, reg, bit;
+
+	irq = _irq - IRQ_GPIOA(0);
+	reg = irq >> 5;
+	bit = 1 << (irq % 32);
+
+	if (type == IRQT_PROBE) {
+		/* Don't mess with enabled GPIOs using preconfigured edges or
+		   GPIOs set to alternate function during probe */
+		/* TODO: support probe */
+//              if ((GPIO_IRQ_rising_edge[idx] | GPIO_IRQ_falling_edge[idx]) &
+//                  GPIO_bit(gpio))
+//                      return 0;
+//              if (GAFR(gpio) & (0x3 << (((gpio) & 0xf)*2)))
+//                      return 0;
+//              type = __IRQT_RISEDGE | __IRQT_FALEDGE;
+	}
+
+	GIUS(reg) |= bit;
+	DDIR(reg) &= ~(bit);
+
+	DEBUG_IRQ("setting type of irq %d to ", _irq);
+
+	if (type & __IRQT_RISEDGE) {
+		DEBUG_IRQ("rising edges\n");
+		irq_type = 0x0;
+	}
+	if (type & __IRQT_FALEDGE) {
+		DEBUG_IRQ("falling edges\n");
+		irq_type = 0x1;
+	}
+	if (type & __IRQT_LOWLVL) {
+		DEBUG_IRQ("low level\n");
+		irq_type = 0x3;
+	}
+	if (type & __IRQT_HIGHLVL) {
+		DEBUG_IRQ("high level\n");
+		irq_type = 0x2;
+	}
+
+	if (irq % 32 < 16) {
+		ICR1(reg) = (ICR1(reg) & ~(0x3 << ((irq % 16) * 2))) |
+		    (irq_type << ((irq % 16) * 2));
+	} else {
+		ICR2(reg) = (ICR2(reg) & ~(0x3 << ((irq % 16) * 2))) |
+		    (irq_type << ((irq % 16) * 2));
+	}
+
+	return 0;
+
+}
+
+static void
+imx_gpio_ack_irq(unsigned int irq)
+{
+	DEBUG_IRQ("%s: irq %d\n", __FUNCTION__, irq);
+	ISR(IRQ_TO_REG(irq)) |= 1 << ((irq - IRQ_GPIOA(0)) % 32);
+}
+
+static void
+imx_gpio_mask_irq(unsigned int irq)
+{
+	DEBUG_IRQ("%s: irq %d\n", __FUNCTION__, irq);
+	IMR(IRQ_TO_REG(irq)) &= ~( 1 << ((irq - IRQ_GPIOA(0)) % 32));
+}
+
+static void
+imx_gpio_unmask_irq(unsigned int irq)
+{
+	DEBUG_IRQ("%s: irq %d\n", __FUNCTION__, irq);
+	IMR(IRQ_TO_REG(irq)) |= 1 << ((irq - IRQ_GPIOA(0)) % 32);
+}
+
+static void
+imx_gpio_handler(unsigned int mask, unsigned int irq,
+                 struct irqdesc *desc, struct pt_regs *regs)
+{
+	desc = irq_desc + irq;
+	while (mask) {
+		if (mask & 1) {
+			DEBUG_IRQ("handling irq %d\n", irq);
+			desc->handle(irq, desc, regs);
+		}
+		irq++;
+		desc++;
+		mask >>= 1;
+	}
+}
+
+static void
+imx_gpioa_demux_handler(unsigned int irq_unused, struct irqdesc *desc,
+			struct pt_regs *regs)
+{
+	unsigned int mask, irq;
+
+	mask = ISR(0);
+	irq = IRQ_GPIOA(0);
+	imx_gpio_handler(mask, irq, desc, regs);
+}
+
+static void
+imx_gpiob_demux_handler(unsigned int irq_unused, struct irqdesc *desc,
+			struct pt_regs *regs)
+{
+	unsigned int mask, irq;
+
+	mask = ISR(1);
+	irq = IRQ_GPIOB(0);
+	imx_gpio_handler(mask, irq, desc, regs);
+}
+
+static void
+imx_gpioc_demux_handler(unsigned int irq_unused, struct irqdesc *desc,
+			struct pt_regs *regs)
+{
+	unsigned int mask, irq;
+
+	mask = ISR(2);
+	irq = IRQ_GPIOC(0);
+	imx_gpio_handler(mask, irq, desc, regs);
+}
+
+static void
+imx_gpiod_demux_handler(unsigned int irq_unused, struct irqdesc *desc,
+			struct pt_regs *regs)
+{
+	unsigned int mask, irq;
+
+	mask = ISR(3);
+	irq = IRQ_GPIOD(0);
+	imx_gpio_handler(mask, irq, desc, regs);
+}
+
+static struct irqchip imx_internal_chip = {
+	.ack = imx_mask_irq,
+	.mask = imx_mask_irq,
+	.unmask = imx_unmask_irq,
+};
+
+static struct irqchip imx_gpio_chip = {
+	.ack = imx_gpio_ack_irq,
+	.mask = imx_gpio_mask_irq,
+	.unmask = imx_gpio_unmask_irq,
+	.type = imx_gpio_irq_type,
+};
+
+void __init
+imx_init_irq(void)
+{
+	unsigned int irq;
+
+	DEBUG_IRQ("Initializing imx interrupts\n");
+
+	/* Mask all interrupts initially */
+	IMR(0) = 0;
+	IMR(1) = 0;
+	IMR(2) = 0;
+	IMR(3) = 0;
+
+	for (irq = 0; irq < IMX_IRQS; irq++) {
+		set_irq_chip(irq, &imx_internal_chip);
+		set_irq_handler(irq, do_level_IRQ);
+		set_irq_flags(irq, IRQF_VALID);
+	}
+
+	for (irq = IRQ_GPIOA(0); irq < IRQ_GPIOD(32); irq++) {
+		set_irq_chip(irq, &imx_gpio_chip);
+		set_irq_handler(irq, do_edge_IRQ);
+		set_irq_flags(irq, IRQF_VALID);
+	}
+
+	set_irq_chained_handler(GPIO_INT_PORTA, imx_gpioa_demux_handler);
+	set_irq_chained_handler(GPIO_INT_PORTB, imx_gpiob_demux_handler);
+	set_irq_chained_handler(GPIO_INT_PORTC, imx_gpioc_demux_handler);
+	set_irq_chained_handler(GPIO_INT_PORTD, imx_gpiod_demux_handler);
+
+	/* Disable all interrupts initially. */
+	/* In IMX this is done in the bootloader. */
+}
diff --git a/arch/arm/mach-imx/leds-mx1ads.c b/arch/arm/mach-imx/leds-mx1ads.c
new file mode 100644
index 0000000..e6399b0
--- /dev/null
+++ b/arch/arm/mach-imx/leds-mx1ads.c
@@ -0,0 +1,54 @@
+/*
+ * linux/arch/arm/mach-imx/leds-mx1ads.c
+ *
+ * Copyright (c) 2004 Sascha Hauer <sascha@saschahauer.de>
+ *
+ * Original (leds-footbridge.c) by Russell King
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ */
+
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <asm/hardware.h>
+#include <asm/system.h>
+#include <asm/io.h>
+#include <asm/leds.h>
+#include <asm/mach-types.h>
+#include "leds.h"
+
+/*
+ * The MX1ADS Board has only one usable LED,
+ * so select only the timer led or the
+ * cpu usage led
+ */
+void
+mx1ads_leds_event(led_event_t ledevt)
+{
+	unsigned long flags;
+
+	local_irq_save(flags);
+
+	switch (ledevt) {
+#ifdef CONFIG_LEDS_CPU
+	case led_idle_start:
+		DR(0) &= ~(1<<2);
+		break;
+
+	case led_idle_end:
+		DR(0) |= 1<<2;
+		break;
+#endif
+
+#ifdef CONFIG_LEDS_TIMER
+	case led_timer:
+		DR(0) ^= 1<<2;
+#endif
+	default:
+		break;
+	}
+	local_irq_restore(flags);
+}
diff --git a/arch/arm/mach-imx/leds.c b/arch/arm/mach-imx/leds.c
new file mode 100644
index 0000000..471c1db
--- /dev/null
+++ b/arch/arm/mach-imx/leds.c
@@ -0,0 +1,31 @@
+/*
+ * linux/arch/arm/mach-imx/leds.h
+ *
+ * Copyright (C) 2004 Sascha Hauer <sascha@saschahauer.de>
+ *
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ */
+
+#include <linux/kernel.h>
+#include <linux/init.h>
+
+#include <asm/leds.h>
+#include <asm/mach-types.h>
+
+#include "leds.h"
+
+static int __init
+leds_init(void)
+{
+	if (machine_is_mx1ads()) {
+		leds_event = mx1ads_leds_event;
+	}
+
+	return 0;
+}
+
+__initcall(leds_init);
diff --git a/arch/arm/mach-imx/leds.h b/arch/arm/mach-imx/leds.h
new file mode 100644
index 0000000..83fa21e
--- /dev/null
+++ b/arch/arm/mach-imx/leds.h
@@ -0,0 +1,9 @@
+/*
+ * include/asm-arm/arch-imx/leds.h
+ *
+ * Copyright (c) 2004 Sascha Hauer <sascha@saschahauer.de>
+ *
+ * blinky lights for IMX-based systems
+ *
+ */
+extern void mx1ads_leds_event(led_event_t evt);
diff --git a/arch/arm/mach-imx/mx1ads.c b/arch/arm/mach-imx/mx1ads.c
new file mode 100644
index 0000000..625dd01
--- /dev/null
+++ b/arch/arm/mach-imx/mx1ads.c
@@ -0,0 +1,88 @@
+/*
+ * arch/arm/mach-imx/mx1ads.c
+ *
+ * Initially based on:
+ *	linux-2.6.7-imx/arch/arm/mach-imx/scb9328.c
+ *	Copyright (c) 2004 Sascha Hauer <sascha@saschahauer.de>
+ *
+ * 2004 (c) MontaVista Software, Inc.
+ *
+ * This file is licensed under the terms of the GNU General Public
+ * License version 2. This program is licensed "as is" without any
+ * warranty of any kind, whether express or implied.
+ */
+
+#include <linux/device.h>
+#include <linux/init.h>
+#include <asm/system.h>
+#include <asm/hardware.h>
+#include <asm/irq.h>
+#include <asm/pgtable.h>
+#include <asm/page.h>
+
+#include <asm/mach/map.h>
+#include <asm/mach-types.h>
+
+#include <asm/mach/arch.h>
+#include <linux/interrupt.h>
+#include "generic.h"
+#include <asm/serial.h>
+
+static struct resource mx1ads_resources[] = {
+	[0] = {
+		.start	= IMX_CS4_VIRT,
+		.end	= IMX_CS4_VIRT + 16,
+		.flags	= IORESOURCE_MEM,
+	},
+	[1] = {
+		.start	= 13,
+		.end	= 13,
+		.flags	= IORESOURCE_IRQ,
+	},
+};
+
+static struct platform_device mx1ads_device = {
+	.name		= "mx1ads",
+	.num_resources	= ARRAY_SIZE(mx1ads_resources),
+	.resource	= mx1ads_resources,
+};
+
+static struct platform_device *devices[] __initdata = {
+	&mx1ads_device,
+};
+
+static void __init
+mx1ads_init(void)
+{
+#ifdef CONFIG_LEDS
+	imx_gpio_mode(GPIO_PORTA | GPIO_OUT | GPIO_GPIO | 2);
+#endif
+	platform_add_devices(devices, ARRAY_SIZE(devices));
+}
+
+static struct map_desc mx1ads_io_desc[] __initdata = {
+	/* virtual     physical    length      type */
+	{IMX_CS0_VIRT, IMX_CS0_PHYS, IMX_CS0_SIZE, MT_DEVICE},
+	{IMX_CS1_VIRT, IMX_CS1_PHYS, IMX_CS1_SIZE, MT_DEVICE},
+	{IMX_CS2_VIRT, IMX_CS2_PHYS, IMX_CS2_SIZE, MT_DEVICE},
+	{IMX_CS3_VIRT, IMX_CS3_PHYS, IMX_CS3_SIZE, MT_DEVICE},
+	{IMX_CS4_VIRT, IMX_CS4_PHYS, IMX_CS4_SIZE, MT_DEVICE},
+	{IMX_CS5_VIRT, IMX_CS5_PHYS, IMX_CS5_SIZE, MT_DEVICE},
+};
+
+static void __init
+mx1ads_map_io(void)
+{
+	imx_map_io();
+	iotable_init(mx1ads_io_desc, ARRAY_SIZE(mx1ads_io_desc));
+}
+
+MACHINE_START(MX1ADS, "Motorola MX1ADS")
+	MAINTAINER("Sascha Hauer, Pengutronix")
+	BOOT_MEM(0x08000000, 0x00200000, 0xe0200000)
+	BOOT_PARAMS(0x08000100)
+	MAPIO(mx1ads_map_io)
+	INITIRQ(imx_init_irq)
+	.timer		= &imx_timer,
+	INIT_MACHINE(mx1ads_init)
+MACHINE_END
diff --git a/arch/arm/mach-imx/time.c b/arch/arm/mach-imx/time.c
new file mode 100644
index 0000000..11f1e56
--- /dev/null
+++ b/arch/arm/mach-imx/time.c
@@ -0,0 +1,101 @@
+/*
+ *  linux/arch/arm/mach-imx/time.c
+ *
+ *  Copyright (C) 2000-2001 Deep Blue Solutions
+ *  Copyright (C) 2002 Shane Nay (shane@minirl.com)
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+#include <linux/config.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/time.h>
+
+#include <asm/hardware.h>
+#include <asm/io.h>
+#include <asm/leds.h>
+#include <asm/irq.h>
+#include <asm/mach/time.h>
+
+/* Use timer 1 as system timer */
+#define TIMER_BASE IMX_TIM1_BASE
+
+/*
+ * Returns number of us since last clock interrupt.  Note that interrupts
+ * will have been disabled by do_gettimeoffset()
+ */
+static unsigned long imx_gettimeoffset(void)
+{
+	unsigned long ticks;
+
+	/*
+	 * Get the current number of ticks.  Note that there is a race
+	 * condition between us reading the timer and checking for
+	 * an interrupt.  We get around this by ensuring that the
+	 * counter has not reloaded between our two reads.
+	 */
+	ticks = IMX_TCN(TIMER_BASE);
+
+	/*
+	 * Interrupt pending?  If so, we've reloaded once already.
+	 */
+	if (IMX_TSTAT(TIMER_BASE) & TSTAT_COMP)
+		ticks += LATCH;
+
+	/*
+	 * Convert the ticks to usecs
+	 */
+	return (1000000 / CLK32) * ticks;
+}
+
+/*
+ * IRQ handler for the timer
+ */
+static irqreturn_t
+imx_timer_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+{
+	write_seqlock(&xtime_lock);
+
+	/* clear the interrupt */
+	if (IMX_TSTAT(TIMER_BASE))
+		IMX_TSTAT(TIMER_BASE) = 0;
+
+	timer_tick(regs);
+	write_sequnlock(&xtime_lock);
+
+	return IRQ_HANDLED;
+}
+
+static struct irqaction imx_timer_irq = {
+	.name		= "i.MX Timer Tick",
+	.flags		= SA_INTERRUPT,
+	.handler	= imx_timer_interrupt
+};
+
+/*
+ * Set up timer interrupt, and return the current time in seconds.
+ */
+static void __init imx_timer_init(void)
+{
+	/*
+	 * Initialise to a known state (all timers off, and timing reset)
+	 */
+	IMX_TCTL(TIMER_BASE) = 0;
+	IMX_TPRER(TIMER_BASE) = 0;
+	IMX_TCMP(TIMER_BASE) = LATCH - 1;
+	IMX_TCTL(TIMER_BASE) = TCTL_CLK_32 | TCTL_IRQEN | TCTL_TEN;
+
+	/*
+	 * Make irqs happen for the system timer
+	 */
+	setup_irq(TIM1_INT, &imx_timer_irq);
+}
+
+struct sys_timer imx_timer = {
+	.init		= imx_timer_init,
+	.offset		= imx_gettimeoffset,
+};