aboutsummaryrefslogtreecommitdiff
path: root/arch/arm/mach-pxa
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@ppc970.osdl.org>2005-04-16 15:20:36 -0700
committerLinus Torvalds <torvalds@ppc970.osdl.org>2005-04-16 15:20:36 -0700
commit1da177e4c3f41524e886b7f1b8a0c1fc7321cac2 (patch)
tree0bba044c4ce775e45a88a51686b5d9f90697ea9d /arch/arm/mach-pxa
downloadlinux-stericsson-1da177e4c3f41524e886b7f1b8a0c1fc7321cac2.tar.gz
Linux-2.6.12-rc2v2.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!
Diffstat (limited to 'arch/arm/mach-pxa')
-rw-r--r--arch/arm/mach-pxa/Kconfig77
-rw-r--r--arch/arm/mach-pxa/Makefile26
-rw-r--r--arch/arm/mach-pxa/Makefile.boot2
-rw-r--r--arch/arm/mach-pxa/corgi.c320
-rw-r--r--arch/arm/mach-pxa/corgi_ssp.c248
-rw-r--r--arch/arm/mach-pxa/dma.c133
-rw-r--r--arch/arm/mach-pxa/generic.c237
-rw-r--r--arch/arm/mach-pxa/generic.h24
-rw-r--r--arch/arm/mach-pxa/idp.c190
-rw-r--r--arch/arm/mach-pxa/irq.c313
-rw-r--r--arch/arm/mach-pxa/leds-idp.c117
-rw-r--r--arch/arm/mach-pxa/leds-lubbock.c126
-rw-r--r--arch/arm/mach-pxa/leds-mainstone.c121
-rw-r--r--arch/arm/mach-pxa/leds.c32
-rw-r--r--arch/arm/mach-pxa/leds.h12
-rw-r--r--arch/arm/mach-pxa/lubbock.c247
-rw-r--r--arch/arm/mach-pxa/mainstone.c316
-rw-r--r--arch/arm/mach-pxa/pm.c227
-rw-r--r--arch/arm/mach-pxa/poodle.c189
-rw-r--r--arch/arm/mach-pxa/pxa25x.c104
-rw-r--r--arch/arm/mach-pxa/pxa27x.c163
-rw-r--r--arch/arm/mach-pxa/sleep.S194
-rw-r--r--arch/arm/mach-pxa/ssp.c363
-rw-r--r--arch/arm/mach-pxa/time.c164
24 files changed, 3945 insertions, 0 deletions
diff --git a/arch/arm/mach-pxa/Kconfig b/arch/arm/mach-pxa/Kconfig
new file mode 100644
index 000000000000..405a55f2287c
--- /dev/null
+++ b/arch/arm/mach-pxa/Kconfig
@@ -0,0 +1,77 @@
+if ARCH_PXA
+
+menu "Intel PXA2xx Implementations"
+
+choice
+ prompt "Select target board"
+
+config ARCH_LUBBOCK
+ bool "Intel DBPXA250 Development Platform"
+ select PXA25x
+ select SA1111
+
+config MACH_MAINSTONE
+ bool "Intel HCDDBBVA0 Development Platform"
+ select PXA27x
+ select IWMMXT
+
+config ARCH_PXA_IDP
+ bool "Accelent Xscale IDP"
+ select PXA25x
+
+config PXA_SHARPSL
+ bool "SHARP SL-5600 and SL-C7xx Models"
+ select PXA25x
+ select SHARP_SCOOP
+ select SHARP_PARAM
+ help
+ Say Y here if you intend to run this kernel on a
+ Sharp SL-5600 (Poodle), Sharp SL-C700 (Corgi),
+ SL-C750 (Shepherd) or a Sharp SL-C760 (Husky)
+ handheld computer.
+
+endchoice
+
+endmenu
+
+config MACH_POODLE
+ bool "Enable Sharp SL-5600 (Poodle) Support"
+ depends PXA_SHARPSL
+ select SHARP_LOCOMO
+
+config MACH_CORGI
+ bool "Enable Sharp SL-C700 (Corgi) Support"
+ depends PXA_SHARPSL
+ select PXA_SHARP_C7xx
+
+config MACH_SHEPHERD
+ bool "Enable Sharp SL-C750 (Shepherd) Support"
+ depends PXA_SHARPSL
+ select PXA_SHARP_C7xx
+
+config MACH_HUSKY
+ bool "Enable Sharp SL-C760 (Husky) Support"
+ depends PXA_SHARPSL
+ select PXA_SHARP_C7xx
+
+config PXA25x
+ bool
+ help
+ Select code specific to PXA21x/25x/26x variants
+
+config PXA27x
+ bool
+ help
+ Select code specific to PXA27x variants
+
+config IWMMXT
+ bool
+ help
+ Enable support for iWMMXt
+
+config PXA_SHARP_C7xx
+ bool
+ help
+ Enable support for all Sharp C7xx models
+
+endif
diff --git a/arch/arm/mach-pxa/Makefile b/arch/arm/mach-pxa/Makefile
new file mode 100644
index 000000000000..c4e6d2523585
--- /dev/null
+++ b/arch/arm/mach-pxa/Makefile
@@ -0,0 +1,26 @@
+#
+# Makefile for the linux kernel.
+#
+
+# Common support (must be linked before board specific support)
+obj-y += generic.o irq.o dma.o time.o
+obj-$(CONFIG_PXA25x) += pxa25x.o
+obj-$(CONFIG_PXA27x) += pxa27x.o
+
+# Specific board support
+obj-$(CONFIG_ARCH_LUBBOCK) += lubbock.o
+obj-$(CONFIG_MACH_MAINSTONE) += mainstone.o
+obj-$(CONFIG_ARCH_PXA_IDP) += idp.o
+obj-$(CONFIG_PXA_SHARP_C7xx) += corgi.o corgi_ssp.o ssp.o
+obj-$(CONFIG_MACH_POODLE) += poodle.o
+
+# Support for blinky lights
+led-y := leds.o
+led-$(CONFIG_ARCH_LUBBOCK) += leds-lubbock.o
+led-$(CONFIG_MACH_MAINSTONE) += leds-mainstone.o
+led-$(CONFIG_ARCH_PXA_IDP) += leds-idp.o
+
+obj-$(CONFIG_LEDS) += $(led-y)
+
+# Misc features
+obj-$(CONFIG_PM) += pm.o sleep.o
diff --git a/arch/arm/mach-pxa/Makefile.boot b/arch/arm/mach-pxa/Makefile.boot
new file mode 100644
index 000000000000..1ead67178eca
--- /dev/null
+++ b/arch/arm/mach-pxa/Makefile.boot
@@ -0,0 +1,2 @@
+ zreladdr-y := 0xa0008000
+
diff --git a/arch/arm/mach-pxa/corgi.c b/arch/arm/mach-pxa/corgi.c
new file mode 100644
index 000000000000..f691cf77d390
--- /dev/null
+++ b/arch/arm/mach-pxa/corgi.c
@@ -0,0 +1,320 @@
+/*
+ * Support for Sharp SL-C7xx PDAs
+ * Models: SL-C700 (Corgi), SL-C750 (Shepherd), SL-C760 (Husky)
+ *
+ * Copyright (c) 2004-2005 Richard Purdie
+ *
+ * Based on Sharp's 2.4 kernel patches/lubbock.c
+ *
+ * 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 <linux/device.h>
+#include <linux/major.h>
+#include <linux/fs.h>
+#include <linux/interrupt.h>
+#include <linux/mmc/host.h>
+
+#include <asm/setup.h>
+#include <asm/memory.h>
+#include <asm/mach-types.h>
+#include <asm/hardware.h>
+#include <asm/irq.h>
+#include <asm/io.h>
+
+#include <asm/mach/arch.h>
+#include <asm/mach/map.h>
+#include <asm/mach/irq.h>
+
+#include <asm/arch/pxa-regs.h>
+#include <asm/arch/irq.h>
+#include <asm/arch/mmc.h>
+#include <asm/arch/udc.h>
+#include <asm/arch/corgi.h>
+
+#include <asm/mach/sharpsl_param.h>
+#include <asm/hardware/scoop.h>
+#include <video/w100fb.h>
+
+#include "generic.h"
+
+
+/*
+ * Corgi SCOOP Device
+ */
+static struct resource corgi_scoop_resources[] = {
+ [0] = {
+ .start = 0x10800000,
+ .end = 0x10800fff,
+ .flags = IORESOURCE_MEM,
+ },
+};
+
+static struct scoop_config corgi_scoop_setup = {
+ .io_dir = CORGI_SCOOP_IO_DIR,
+ .io_out = CORGI_SCOOP_IO_OUT,
+};
+
+struct platform_device corgiscoop_device = {
+ .name = "sharp-scoop",
+ .id = -1,
+ .dev = {
+ .platform_data = &corgi_scoop_setup,
+ },
+ .num_resources = ARRAY_SIZE(corgi_scoop_resources),
+ .resource = corgi_scoop_resources,
+};
+
+
+/*
+ * Corgi SSP Device
+ *
+ * Set the parent as the scoop device because a lot of SSP devices
+ * also use scoop functions and this makes the power up/down order
+ * work correctly.
+ */
+static struct platform_device corgissp_device = {
+ .name = "corgi-ssp",
+ .dev = {
+ .parent = &corgiscoop_device.dev,
+ },
+ .id = -1,
+};
+
+
+/*
+ * Corgi w100 Frame Buffer Device
+ */
+static struct w100fb_mach_info corgi_fb_info = {
+ .w100fb_ssp_send = corgi_ssp_lcdtg_send,
+ .comadj = -1,
+ .phadadj = -1,
+};
+
+static struct resource corgi_fb_resources[] = {
+ [0] = {
+ .start = 0x08000000,
+ .end = 0x08ffffff,
+ .flags = IORESOURCE_MEM,
+ },
+};
+
+static struct platform_device corgifb_device = {
+ .name = "w100fb",
+ .id = -1,
+ .dev = {
+ .platform_data = &corgi_fb_info,
+ .parent = &corgissp_device.dev,
+ },
+ .num_resources = ARRAY_SIZE(corgi_fb_resources),
+ .resource = corgi_fb_resources,
+};
+
+
+/*
+ * Corgi Backlight Device
+ */
+static struct platform_device corgibl_device = {
+ .name = "corgi-bl",
+ .dev = {
+ .parent = &corgifb_device.dev,
+ },
+ .id = -1,
+};
+
+
+/*
+ * MMC/SD Device
+ *
+ * The card detect interrupt isn't debounced so we delay it by HZ/4
+ * to give the card a chance to fully insert/eject.
+ */
+static struct mmc_detect {
+ struct timer_list detect_timer;
+ void *devid;
+} mmc_detect;
+
+static void mmc_detect_callback(unsigned long data)
+{
+ mmc_detect_change(mmc_detect.devid);
+}
+
+static irqreturn_t corgi_mmc_detect_int(int irq, void *devid, struct pt_regs *regs)
+{
+ mmc_detect.devid=devid;
+ mod_timer(&mmc_detect.detect_timer, jiffies + HZ/4);
+ return IRQ_HANDLED;
+}
+
+static int corgi_mci_init(struct device *dev, irqreturn_t (*unused_detect_int)(int, void *, struct pt_regs *), void *data)
+{
+ int err;
+
+ /* setup GPIO for PXA25x MMC controller */
+ pxa_gpio_mode(GPIO6_MMCCLK_MD);
+ pxa_gpio_mode(GPIO8_MMCCS0_MD);
+ pxa_gpio_mode(CORGI_GPIO_nSD_DETECT | GPIO_IN);
+ pxa_gpio_mode(CORGI_GPIO_SD_PWR | GPIO_OUT);
+
+ init_timer(&mmc_detect.detect_timer);
+ mmc_detect.detect_timer.function = mmc_detect_callback;
+ mmc_detect.detect_timer.data = (unsigned long) &mmc_detect;
+
+ err = request_irq(CORGI_IRQ_GPIO_nSD_DETECT, corgi_mmc_detect_int, SA_INTERRUPT,
+ "MMC card detect", data);
+ if (err) {
+ printk(KERN_ERR "corgi_mci_init: MMC/SD: can't request MMC card detect IRQ\n");
+ return -1;
+ }
+
+ set_irq_type(CORGI_IRQ_GPIO_nSD_DETECT, IRQT_BOTHEDGE);
+
+ return 0;
+}
+
+static void corgi_mci_setpower(struct device *dev, unsigned int vdd)
+{
+ struct pxamci_platform_data* p_d = dev->platform_data;
+
+ if (( 1 << vdd) & p_d->ocr_mask) {
+ printk(KERN_DEBUG "%s: on\n", __FUNCTION__);
+ GPSR1 = GPIO_bit(CORGI_GPIO_SD_PWR);
+ } else {
+ printk(KERN_DEBUG "%s: off\n", __FUNCTION__);
+ GPCR1 = GPIO_bit(CORGI_GPIO_SD_PWR);
+ }
+}
+
+static void corgi_mci_exit(struct device *dev, void *data)
+{
+ free_irq(CORGI_IRQ_GPIO_nSD_DETECT, data);
+ del_timer(&mmc_detect.detect_timer);
+}
+
+static struct pxamci_platform_data corgi_mci_platform_data = {
+ .ocr_mask = MMC_VDD_32_33|MMC_VDD_33_34,
+ .init = corgi_mci_init,
+ .setpower = corgi_mci_setpower,
+ .exit = corgi_mci_exit,
+};
+
+
+/*
+ * USB Device Controller
+ */
+static void corgi_udc_command(int cmd)
+{
+ switch(cmd) {
+ case PXA2XX_UDC_CMD_CONNECT:
+ GPSR(CORGI_GPIO_USB_PULLUP) = GPIO_bit(CORGI_GPIO_USB_PULLUP);
+ break;
+ case PXA2XX_UDC_CMD_DISCONNECT:
+ GPCR(CORGI_GPIO_USB_PULLUP) = GPIO_bit(CORGI_GPIO_USB_PULLUP);
+ break;
+ }
+}
+
+static struct pxa2xx_udc_mach_info udc_info __initdata = {
+ /* no connect GPIO; corgi can't tell connection status */
+ .udc_command = corgi_udc_command,
+};
+
+
+static struct platform_device *devices[] __initdata = {
+ &corgiscoop_device,
+ &corgissp_device,
+ &corgifb_device,
+ &corgibl_device,
+};
+
+static void __init corgi_init(void)
+{
+ corgi_fb_info.comadj=sharpsl_param.comadj;
+ corgi_fb_info.phadadj=sharpsl_param.phadadj;
+
+ pxa_gpio_mode(CORGI_GPIO_USB_PULLUP | GPIO_OUT);
+ pxa_set_udc_info(&udc_info);
+ pxa_set_mci_info(&corgi_mci_platform_data);
+
+ platform_add_devices(devices, ARRAY_SIZE(devices));
+}
+
+static void __init fixup_corgi(struct machine_desc *desc,
+ struct tag *tags, char **cmdline, struct meminfo *mi)
+{
+ sharpsl_save_param();
+ mi->nr_banks=1;
+ mi->bank[0].start = 0xa0000000;
+ mi->bank[0].node = 0;
+ if (machine_is_corgi())
+ mi->bank[0].size = (32*1024*1024);
+ else
+ mi->bank[0].size = (64*1024*1024);
+}
+
+static void __init corgi_init_irq(void)
+{
+ pxa_init_irq();
+}
+
+static struct map_desc corgi_io_desc[] __initdata = {
+/* virtual physical length */
+/* { 0xf1000000, 0x08000000, 0x01000000, MT_DEVICE },*/ /* LCDC (readable for Qt driver) */
+/* { 0xef700000, 0x10800000, 0x00001000, MT_DEVICE },*/ /* SCOOP */
+ { 0xef800000, 0x00000000, 0x00800000, MT_DEVICE }, /* Boot Flash */
+};
+
+static void __init corgi_map_io(void)
+{
+ pxa_map_io();
+ iotable_init(corgi_io_desc,ARRAY_SIZE(corgi_io_desc));
+
+ /* setup sleep mode values */
+ PWER = 0x00000002;
+ PFER = 0x00000000;
+ PRER = 0x00000002;
+ PGSR0 = 0x0158C000;
+ PGSR1 = 0x00FF0080;
+ PGSR2 = 0x0001C004;
+ /* Stop 3.6MHz and drive HIGH to PCMCIA and CS */
+ PCFR |= PCFR_OPDE;
+}
+
+#ifdef CONFIG_MACH_CORGI
+MACHINE_START(CORGI, "SHARP Corgi")
+ BOOT_MEM(0xa0000000, 0x40000000, io_p2v(0x40000000))
+ FIXUP(fixup_corgi)
+ MAPIO(corgi_map_io)
+ INITIRQ(corgi_init_irq)
+ .init_machine = corgi_init,
+ .timer = &pxa_timer,
+MACHINE_END
+#endif
+
+#ifdef CONFIG_MACH_SHEPHERD
+MACHINE_START(SHEPHERD, "SHARP Shepherd")
+ BOOT_MEM(0xa0000000, 0x40000000, io_p2v(0x40000000))
+ FIXUP(fixup_corgi)
+ MAPIO(corgi_map_io)
+ INITIRQ(corgi_init_irq)
+ .init_machine = corgi_init,
+ .timer = &pxa_timer,
+MACHINE_END
+#endif
+
+#ifdef CONFIG_MACH_HUSKY
+MACHINE_START(HUSKY, "SHARP Husky")
+ BOOT_MEM(0xa0000000, 0x40000000, io_p2v(0x40000000))
+ FIXUP(fixup_corgi)
+ MAPIO(corgi_map_io)
+ INITIRQ(corgi_init_irq)
+ .init_machine = corgi_init,
+ .timer = &pxa_timer,
+MACHINE_END
+#endif
+
diff --git a/arch/arm/mach-pxa/corgi_ssp.c b/arch/arm/mach-pxa/corgi_ssp.c
new file mode 100644
index 000000000000..8ccffba0018f
--- /dev/null
+++ b/arch/arm/mach-pxa/corgi_ssp.c
@@ -0,0 +1,248 @@
+/*
+ * SSP control code for Sharp Corgi devices
+ *
+ * Copyright (c) 2004 Richard Purdie
+ *
+ * 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/module.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/slab.h>
+#include <linux/delay.h>
+#include <linux/device.h>
+#include <asm/hardware.h>
+
+#include <asm/arch/ssp.h>
+#include <asm/arch/corgi.h>
+#include <asm/arch/pxa-regs.h>
+
+static spinlock_t corgi_ssp_lock = SPIN_LOCK_UNLOCKED;
+static struct ssp_dev corgi_ssp_dev;
+static struct ssp_state corgi_ssp_state;
+
+/*
+ * There are three devices connected to the SSP interface:
+ * 1. A touchscreen controller (TI ADS7846 compatible)
+ * 2. An LCD contoller (with some Backlight functionality)
+ * 3. A battery moinitoring IC (Maxim MAX1111)
+ *
+ * Each device uses a different speed/mode of communication.
+ *
+ * The touchscreen is very sensitive and the most frequently used
+ * so the port is left configured for this.
+ *
+ * Devices are selected using Chip Selects on GPIOs.
+ */
+
+/*
+ * ADS7846 Routines
+ */
+unsigned long corgi_ssp_ads7846_putget(ulong data)
+{
+ unsigned long ret,flag;
+
+ spin_lock_irqsave(&corgi_ssp_lock, flag);
+ GPCR0 = GPIO_bit(CORGI_GPIO_ADS7846_CS);
+
+ ssp_write_word(&corgi_ssp_dev,data);
+ ret = ssp_read_word(&corgi_ssp_dev);
+
+ GPSR0 = GPIO_bit(CORGI_GPIO_ADS7846_CS);
+ spin_unlock_irqrestore(&corgi_ssp_lock, flag);
+
+ return ret;
+}
+
+/*
+ * NOTE: These functions should always be called in interrupt context
+ * and use the _lock and _unlock functions. They are very time sensitive.
+ */
+void corgi_ssp_ads7846_lock(void)
+{
+ spin_lock(&corgi_ssp_lock);
+ GPCR0 = GPIO_bit(CORGI_GPIO_ADS7846_CS);
+}
+
+void corgi_ssp_ads7846_unlock(void)
+{
+ GPSR0 = GPIO_bit(CORGI_GPIO_ADS7846_CS);
+ spin_unlock(&corgi_ssp_lock);
+}
+
+void corgi_ssp_ads7846_put(ulong data)
+{
+ ssp_write_word(&corgi_ssp_dev,data);
+}
+
+unsigned long corgi_ssp_ads7846_get(void)
+{
+ return ssp_read_word(&corgi_ssp_dev);
+}
+
+EXPORT_SYMBOL(corgi_ssp_ads7846_putget);
+EXPORT_SYMBOL(corgi_ssp_ads7846_lock);
+EXPORT_SYMBOL(corgi_ssp_ads7846_unlock);
+EXPORT_SYMBOL(corgi_ssp_ads7846_put);
+EXPORT_SYMBOL(corgi_ssp_ads7846_get);
+
+
+/*
+ * LCD/Backlight Routines
+ */
+unsigned long corgi_ssp_dac_put(ulong data)
+{
+ unsigned long flag;
+
+ spin_lock_irqsave(&corgi_ssp_lock, flag);
+ GPCR0 = GPIO_bit(CORGI_GPIO_LCDCON_CS);
+
+ ssp_disable(&corgi_ssp_dev);
+ ssp_config(&corgi_ssp_dev, (SSCR0_Motorola | (SSCR0_DSS & 0x07 )), SSCR1_SPH, 0, SSCR0_SerClkDiv(76));
+ ssp_enable(&corgi_ssp_dev);
+
+ ssp_write_word(&corgi_ssp_dev,data);
+ /* Read null data back from device to prevent SSP overflow */
+ ssp_read_word(&corgi_ssp_dev);
+
+ ssp_disable(&corgi_ssp_dev);
+ ssp_config(&corgi_ssp_dev, (SSCR0_National | (SSCR0_DSS & 0x0b )), 0, 0, SSCR0_SerClkDiv(2));
+ ssp_enable(&corgi_ssp_dev);
+ GPSR0 = GPIO_bit(CORGI_GPIO_LCDCON_CS);
+ spin_unlock_irqrestore(&corgi_ssp_lock, flag);
+
+ return 0;
+}
+
+void corgi_ssp_lcdtg_send(u8 adrs, u8 data)
+{
+ corgi_ssp_dac_put(((adrs & 0x07) << 5) | (data & 0x1f));
+}
+
+void corgi_ssp_blduty_set(int duty)
+{
+ corgi_ssp_lcdtg_send(0x02,duty);
+}
+
+EXPORT_SYMBOL(corgi_ssp_lcdtg_send);
+EXPORT_SYMBOL(corgi_ssp_blduty_set);
+
+/*
+ * Max1111 Routines
+ */
+int corgi_ssp_max1111_get(ulong data)
+{
+ unsigned long flag;
+ int voltage,voltage1,voltage2;
+
+ spin_lock_irqsave(&corgi_ssp_lock, flag);
+ GPCR0 = GPIO_bit(CORGI_GPIO_MAX1111_CS);
+ ssp_disable(&corgi_ssp_dev);
+ ssp_config(&corgi_ssp_dev, (SSCR0_Motorola | (SSCR0_DSS & 0x07 )), 0, 0, SSCR0_SerClkDiv(8));
+ ssp_enable(&corgi_ssp_dev);
+
+ udelay(1);
+
+ /* TB1/RB1 */
+ ssp_write_word(&corgi_ssp_dev,data);
+ ssp_read_word(&corgi_ssp_dev); /* null read */
+
+ /* TB12/RB2 */
+ ssp_write_word(&corgi_ssp_dev,0);
+ voltage1=ssp_read_word(&corgi_ssp_dev);
+
+ /* TB13/RB3*/
+ ssp_write_word(&corgi_ssp_dev,0);
+ voltage2=ssp_read_word(&corgi_ssp_dev);
+
+ ssp_disable(&corgi_ssp_dev);
+ ssp_config(&corgi_ssp_dev, (SSCR0_National | (SSCR0_DSS & 0x0b )), 0, 0, SSCR0_SerClkDiv(2));
+ ssp_enable(&corgi_ssp_dev);
+ GPSR0 = GPIO_bit(CORGI_GPIO_MAX1111_CS);
+ spin_unlock_irqrestore(&corgi_ssp_lock, flag);
+
+ if (voltage1 & 0xc0 || voltage2 & 0x3f)
+ voltage = -1;
+ else
+ voltage = ((voltage1 << 2) & 0xfc) | ((voltage2 >> 6) & 0x03);
+
+ return voltage;
+}
+
+EXPORT_SYMBOL(corgi_ssp_max1111_get);
+
+/*
+ * Support Routines
+ */
+int __init corgi_ssp_probe(struct device *dev)
+{
+ int ret;
+
+ /* Chip Select - Disable All */
+ GPDR0 |= GPIO_bit(CORGI_GPIO_LCDCON_CS); /* output */
+ GPSR0 = GPIO_bit(CORGI_GPIO_LCDCON_CS); /* High - Disable LCD Control/Timing Gen */
+ GPDR0 |= GPIO_bit(CORGI_GPIO_MAX1111_CS); /* output */
+ GPSR0 = GPIO_bit(CORGI_GPIO_MAX1111_CS); /* High - Disable MAX1111*/
+ GPDR0 |= GPIO_bit(CORGI_GPIO_ADS7846_CS); /* output */
+ GPSR0 = GPIO_bit(CORGI_GPIO_ADS7846_CS); /* High - Disable ADS7846*/
+
+ ret=ssp_init(&corgi_ssp_dev,1);
+
+ if (ret)
+ printk(KERN_ERR "Unable to register SSP handler!\n");
+ else {
+ ssp_disable(&corgi_ssp_dev);
+ ssp_config(&corgi_ssp_dev, (SSCR0_National | (SSCR0_DSS & 0x0b )), 0, 0, SSCR0_SerClkDiv(2));
+ ssp_enable(&corgi_ssp_dev);
+ }
+
+ return ret;
+}
+
+static int corgi_ssp_remove(struct device *dev)
+{
+ ssp_exit(&corgi_ssp_dev);
+ return 0;
+}
+
+static int corgi_ssp_suspend(struct device *dev, pm_message_t state, u32 level)
+{
+ if (level == SUSPEND_POWER_DOWN) {
+ ssp_flush(&corgi_ssp_dev);
+ ssp_save_state(&corgi_ssp_dev,&corgi_ssp_state);
+ }
+ return 0;
+}
+
+static int corgi_ssp_resume(struct device *dev, u32 level)
+{
+ if (level == RESUME_POWER_ON) {
+ GPSR0 = GPIO_bit(CORGI_GPIO_LCDCON_CS); /* High - Disable LCD Control/Timing Gen */
+ GPSR0 = GPIO_bit(CORGI_GPIO_MAX1111_CS); /* High - Disable MAX1111*/
+ GPSR0 = GPIO_bit(CORGI_GPIO_ADS7846_CS); /* High - Disable ADS7846*/
+ ssp_restore_state(&corgi_ssp_dev,&corgi_ssp_state);
+ ssp_enable(&corgi_ssp_dev);
+ }
+ return 0;
+}
+
+static struct device_driver corgissp_driver = {
+ .name = "corgi-ssp",
+ .bus = &platform_bus_type,
+ .probe = corgi_ssp_probe,
+ .remove = corgi_ssp_remove,
+ .suspend = corgi_ssp_suspend,
+ .resume = corgi_ssp_resume,
+};
+
+int __init corgi_ssp_init(void)
+{
+ return driver_register(&corgissp_driver);
+}
+
+arch_initcall(corgi_ssp_init);
diff --git a/arch/arm/mach-pxa/dma.c b/arch/arm/mach-pxa/dma.c
new file mode 100644
index 000000000000..458112b21e25
--- /dev/null
+++ b/arch/arm/mach-pxa/dma.c
@@ -0,0 +1,133 @@
+/*
+ * linux/arch/arm/mach-pxa/dma.c
+ *
+ * PXA DMA registration and IRQ dispatching
+ *
+ * Author: Nicolas Pitre
+ * Created: Nov 15, 2001
+ * Copyright: MontaVista Software Inc.
+ *
+ * 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/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>
+
+#include <asm/arch/pxa-regs.h>
+
+static struct dma_channel {
+ char *name;
+ void (*irq_handler)(int, void *, struct pt_regs *);
+ void *data;
+} dma_channels[PXA_DMA_CHANNELS];
+
+
+int pxa_request_dma (char *name, pxa_dma_prio prio,
+ void (*irq_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 + PXA_DMA_NBCH(prio); 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) {
+ DCSR(i) = DCSR_STARTINTR|DCSR_ENDINTR|DCSR_BUSERR;
+ dma_channels[i].name = name;
+ dma_channels[i].irq_handler = irq_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 pxa_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);
+ DCSR(dma_ch) = DCSR_STARTINTR|DCSR_ENDINTR|DCSR_BUSERR;
+ dma_channels[dma_ch].name = NULL;
+ local_irq_restore(flags);
+}
+
+static irqreturn_t dma_irq_handler(int irq, void *dev_id, struct pt_regs *regs)
+{
+ int i, dint = DINT;
+
+ for (i = 0; i < PXA_DMA_CHANNELS; i++) {
+ if (dint & (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);
+ DCSR(i) = DCSR_STARTINTR|DCSR_ENDINTR|DCSR_BUSERR;
+ }
+ }
+ }
+ return IRQ_HANDLED;
+}
+
+static int __init pxa_dma_init (void)
+{
+ int ret;
+
+ ret = request_irq (IRQ_DMA, dma_irq_handler, 0, "DMA", NULL);
+ if (ret)
+ printk (KERN_CRIT "Wow! Can't register IRQ for DMA\n");
+ return ret;
+}
+
+arch_initcall(pxa_dma_init);
+
+EXPORT_SYMBOL(pxa_request_dma);
+EXPORT_SYMBOL(pxa_free_dma);
+
diff --git a/arch/arm/mach-pxa/generic.c b/arch/arm/mach-pxa/generic.c
new file mode 100644
index 000000000000..b1575b8dc1cd
--- /dev/null
+++ b/arch/arm/mach-pxa/generic.c
@@ -0,0 +1,237 @@
+/*
+ * linux/arch/arm/mach-pxa/generic.c
+ *
+ * Author: Nicolas Pitre
+ * Created: Jun 15, 2001
+ * Copyright: MontaVista Software Inc.
+ *
+ * Code common to all PXA machines.
+ *
+ * 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.
+ *
+ * Since this file should be linked before any other machine specific file,
+ * the __initcall() here will be executed first. This serves as default
+ * initialization stuff for PXA machines which can be overridden later if
+ * need be.
+ */
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/device.h>
+#include <linux/ioport.h>
+#include <linux/pm.h>
+
+#include <asm/hardware.h>
+#include <asm/irq.h>
+#include <asm/system.h>
+#include <asm/pgtable.h>
+#include <asm/mach/map.h>
+
+#include <asm/arch/pxa-regs.h>
+#include <asm/arch/udc.h>
+#include <asm/arch/pxafb.h>
+#include <asm/arch/mmc.h>
+
+#include "generic.h"
+
+/*
+ * Handy function to set GPIO alternate functions
+ */
+
+void pxa_gpio_mode(int gpio_mode)
+{
+ unsigned long flags;
+ int gpio = gpio_mode & GPIO_MD_MASK_NR;
+ int fn = (gpio_mode & GPIO_MD_MASK_FN) >> 8;
+ int gafr;
+
+ local_irq_save(flags);
+ if (gpio_mode & GPIO_DFLT_LOW)
+ GPCR(gpio) = GPIO_bit(gpio);
+ else if (gpio_mode & GPIO_DFLT_HIGH)
+ GPSR(gpio) = GPIO_bit(gpio);
+ if (gpio_mode & GPIO_MD_MASK_DIR)
+ GPDR(gpio) |= GPIO_bit(gpio);
+ else
+ GPDR(gpio) &= ~GPIO_bit(gpio);
+ gafr = GAFR(gpio) & ~(0x3 << (((gpio) & 0xf)*2));
+ GAFR(gpio) = gafr | (fn << (((gpio) & 0xf)*2));
+ local_irq_restore(flags);
+}
+
+EXPORT_SYMBOL(pxa_gpio_mode);
+
+/*
+ * Routine to safely enable or disable a clock in the CKEN
+ */
+void pxa_set_cken(int clock, int enable)
+{
+ unsigned long flags;
+ local_irq_save(flags);
+
+ if (enable)
+ CKEN |= clock;
+ else
+ CKEN &= ~clock;
+
+ local_irq_restore(flags);
+}
+
+EXPORT_SYMBOL(pxa_set_cken);
+
+/*
+ * Intel PXA2xx internal register mapping.
+ *
+ * Note 1: not all PXA2xx variants implement all those addresses.
+ *
+ * Note 2: virtual 0xfffe0000-0xffffffff is reserved for the vector table
+ * and cache flush area.
+ */
+static struct map_desc standard_io_desc[] __initdata = {
+ /* virtual physical length type */
+ { 0xf2000000, 0x40000000, 0x02000000, MT_DEVICE }, /* Devs */
+ { 0xf4000000, 0x44000000, 0x00100000, MT_DEVICE }, /* LCD */
+ { 0xf6000000, 0x48000000, 0x00100000, MT_DEVICE }, /* Mem Ctl */
+ { 0xf8000000, 0x4c000000, 0x00100000, MT_DEVICE }, /* USB host */
+ { 0xfa000000, 0x50000000, 0x00100000, MT_DEVICE }, /* Camera */
+ { 0xfe000000, 0x58000000, 0x00100000, MT_DEVICE }, /* IMem ctl */
+ { 0xff000000, 0x00000000, 0x00100000, MT_DEVICE } /* UNCACHED_PHYS_0 */
+};
+
+void __init pxa_map_io(void)
+{
+ iotable_init(standard_io_desc, ARRAY_SIZE(standard_io_desc));
+ get_clk_frequency_khz(1);
+}
+
+
+static struct resource pxamci_resources[] = {
+ [0] = {
+ .start = 0x41100000,
+ .end = 0x41100fff,
+ .flags = IORESOURCE_MEM,
+ },
+ [1] = {
+ .start = IRQ_MMC,
+ .end = IRQ_MMC,
+ .flags = IORESOURCE_IRQ,
+ },
+};
+
+static u64 pxamci_dmamask = 0xffffffffUL;
+
+static struct platform_device pxamci_device = {
+ .name = "pxa2xx-mci",
+ .id = -1,
+ .dev = {
+ .dma_mask = &pxamci_dmamask,
+ .coherent_dma_mask = 0xffffffff,
+ },
+ .num_resources = ARRAY_SIZE(pxamci_resources),
+ .resource = pxamci_resources,
+};
+
+void __init pxa_set_mci_info(struct pxamci_platform_data *info)
+{
+ pxamci_device.dev.platform_data = info;
+}
+
+
+static struct pxa2xx_udc_mach_info pxa_udc_info;
+
+void __init pxa_set_udc_info(struct pxa2xx_udc_mach_info *info)
+{
+ memcpy(&pxa_udc_info, info, sizeof *info);
+}
+
+static struct resource pxa2xx_udc_resources[] = {
+ [0] = {
+ .start = 0x40600000,
+ .end = 0x4060ffff,
+ .flags = IORESOURCE_MEM,
+ },
+ [1] = {
+ .start = IRQ_USB,
+ .end = IRQ_USB,
+ .flags = IORESOURCE_IRQ,
+ },
+};
+
+static u64 udc_dma_mask = ~(u32)0;
+
+static struct platform_device udc_device = {
+ .name = "pxa2xx-udc",
+ .id = -1,
+ .resource = pxa2xx_udc_resources,
+ .num_resources = ARRAY_SIZE(pxa2xx_udc_resources),
+ .dev = {
+ .platform_data = &pxa_udc_info,
+ .dma_mask = &udc_dma_mask,
+ }
+};
+
+static struct pxafb_mach_info pxa_fb_info;
+
+void __init set_pxa_fb_info(struct pxafb_mach_info *hard_pxa_fb_info)
+{
+ memcpy(&pxa_fb_info,hard_pxa_fb_info,sizeof(struct pxafb_mach_info));
+}
+
+static struct resource pxafb_resources[] = {
+ [0] = {
+ .start = 0x44000000,
+ .end = 0x4400ffff,
+ .flags = IORESOURCE_MEM,
+ },
+ [1] = {
+ .start = IRQ_LCD,
+ .end = IRQ_LCD,
+ .flags = IORESOURCE_IRQ,
+ },
+};
+
+static u64 fb_dma_mask = ~(u64)0;
+
+static struct platform_device pxafb_device = {
+ .name = "pxa2xx-fb",
+ .id = -1,
+ .dev = {
+ .platform_data = &pxa_fb_info,
+ .dma_mask = &fb_dma_mask,
+ .coherent_dma_mask = 0xffffffff,
+ },
+ .num_resources = ARRAY_SIZE(pxafb_resources),
+ .resource = pxafb_resources,
+};
+
+static struct platform_device ffuart_device = {
+ .name = "pxa2xx-uart",
+ .id = 0,
+};
+static struct platform_device btuart_device = {
+ .name = "pxa2xx-uart",
+ .id = 1,
+};
+static struct platform_device stuart_device = {
+ .name = "pxa2xx-uart",
+ .id = 2,
+};
+
+static struct platform_device *devices[] __initdata = {
+ &pxamci_device,
+ &udc_device,
+ &pxafb_device,
+ &ffuart_device,
+ &btuart_device,
+ &stuart_device,
+};
+
+static int __init pxa_init(void)
+{
+ return platform_add_devices(devices, ARRAY_SIZE(devices));
+}
+
+subsys_initcall(pxa_init);
diff --git a/arch/arm/mach-pxa/generic.h b/arch/arm/mach-pxa/generic.h
new file mode 100644
index 000000000000..e54a8dd63c17
--- /dev/null
+++ b/arch/arm/mach-pxa/generic.h
@@ -0,0 +1,24 @@
+/*
+ * linux/arch/arm/mach-pxa/generic.h
+ *
+ * Author: Nicolas Pitre
+ * Copyright: MontaVista Software Inc.
+ *
+ * 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.
+ */
+
+struct sys_timer;
+
+extern struct sys_timer pxa_timer;
+extern void __init pxa_map_io(void);
+extern void __init pxa_init_irq(void);
+
+extern unsigned int get_clk_frequency_khz(int info);
+
+#define SET_BANK(__nr,__start,__size) \
+ mi->bank[__nr].start = (__start), \
+ mi->bank[__nr].size = (__size), \
+ mi->bank[__nr].node = (((unsigned)(__start) - PHYS_OFFSET) >> 27)
+
diff --git a/arch/arm/mach-pxa/idp.c b/arch/arm/mach-pxa/idp.c
new file mode 100644
index 000000000000..c5a66bf4d3d5
--- /dev/null
+++ b/arch/arm/mach-pxa/idp.c
@@ -0,0 +1,190 @@
+/*
+ * linux/arch/arm/mach-pxa/idp.c
+ *
+ * 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.
+ *
+ * Copyright (c) 2001 Cliff Brake, Accelent Systems Inc.
+ *
+ * 2001-09-13: Cliff Brake <cbrake@accelent.com>
+ * Initial code
+ *
+ * 2005-02-15: Cliff Brake <cliff.brake@gmail.com>
+ * <http://www.vibren.com> <http://bec-systems.com>
+ * Updated for 2.6 kernel
+ *
+ */
+
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/device.h>
+#include <linux/fb.h>
+
+#include <asm/setup.h>
+#include <asm/memory.h>
+#include <asm/mach-types.h>
+#include <asm/hardware.h>
+#include <asm/irq.h>
+
+#include <asm/mach/arch.h>
+#include <asm/mach/map.h>
+
+#include <asm/arch/pxa-regs.h>
+#include <asm/arch/idp.h>
+#include <asm/arch/pxafb.h>
+#include <asm/arch/bitfield.h>
+#include <asm/arch/mmc.h>
+
+#include "generic.h"
+
+/* TODO:
+ * - add pxa2xx_audio_ops_t device structure
+ * - Ethernet interrupt
+ */
+
+static struct resource smc91x_resources[] = {
+ [0] = {
+ .start = (IDP_ETH_PHYS + 0x300),
+ .end = (IDP_ETH_PHYS + 0xfffff),
+ .flags = IORESOURCE_MEM,
+ },
+ [1] = {
+ .start = IRQ_GPIO(4),
+ .end = IRQ_GPIO(4),
+ .flags = IORESOURCE_IRQ,
+ }
+};
+
+static struct platform_device smc91x_device = {
+ .name = "smc91x",
+ .id = 0,
+ .num_resources = ARRAY_SIZE(smc91x_resources),
+ .resource = smc91x_resources,
+};
+
+static void idp_backlight_power(int on)
+{
+ if (on) {
+ IDP_CPLD_LCD |= (1<<1);
+ } else {
+ IDP_CPLD_LCD &= ~(1<<1);
+ }
+}
+
+static void idp_vlcd(int on)
+{
+ if (on) {
+ IDP_CPLD_LCD |= (1<<2);
+ } else {
+ IDP_CPLD_LCD &= ~(1<<2);
+ }
+}
+
+static void idp_lcd_power(int on)
+{
+ if (on) {
+ IDP_CPLD_LCD |= (1<<0);
+ } else {
+ IDP_CPLD_LCD &= ~(1<<0);
+ }
+
+ /* call idp_vlcd for now as core driver does not support
+ * both power and vlcd hooks. Note, this is not technically
+ * the correct sequence, but seems to work. Disclaimer:
+ * this may eventually damage the display.
+ */
+
+ idp_vlcd(on);
+}
+
+static struct pxafb_mach_info sharp_lm8v31 __initdata = {
+ .pixclock = 270000,
+ .xres = 640,
+ .yres = 480,
+ .bpp = 16,
+ .hsync_len = 1,
+ .left_margin = 3,
+ .right_margin = 3,
+ .vsync_len = 1,
+ .upper_margin = 0,
+ .lower_margin = 0,
+ .sync = FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
+ .cmap_greyscale = 0,
+ .cmap_inverse = 0,
+ .cmap_static = 0,
+ .lccr0 = LCCR0_SDS,
+ .lccr3 = LCCR3_PCP | LCCR3_Acb(255),
+ .pxafb_backlight_power = &idp_backlight_power,
+ .pxafb_lcd_power = &idp_lcd_power
+};
+
+static int idp_mci_init(struct device *dev, irqreturn_t (*idp_detect_int)(int, void *, struct pt_regs *), void *data)
+{
+ /* setup GPIO for PXA25x MMC controller */
+ pxa_gpio_mode(GPIO6_MMCCLK_MD);
+ pxa_gpio_mode(GPIO8_MMCCS0_MD);
+
+ return 0;
+}
+
+static struct pxamci_platform_data idp_mci_platform_data = {
+ .ocr_mask = MMC_VDD_32_33|MMC_VDD_33_34,
+ .init = idp_mci_init,
+};
+
+static void __init idp_init(void)
+{
+ printk("idp_init()\n");
+
+ platform_device_register(&smc91x_device);
+ //platform_device_register(&mst_audio_device);
+ set_pxa_fb_info(&sharp_lm8v31);
+ pxa_set_mci_info(&idp_mci_platform_data);
+}
+
+static void __init idp_init_irq(void)
+{
+
+ pxa_init_irq();
+
+ set_irq_type(TOUCH_PANEL_IRQ, TOUCH_PANEL_IRQ_EDGE);
+}
+
+static struct map_desc idp_io_desc[] __initdata = {
+ /* virtual physical length type */
+
+ { IDP_COREVOLT_VIRT,
+ IDP_COREVOLT_PHYS,
+ IDP_COREVOLT_SIZE,
+ MT_DEVICE },
+ { IDP_CPLD_VIRT,
+ IDP_CPLD_PHYS,
+ IDP_CPLD_SIZE,
+ MT_DEVICE }
+};
+
+static void __init idp_map_io(void)
+{
+ pxa_map_io();
+ iotable_init(idp_io_desc, ARRAY_SIZE(idp_io_desc));
+
+ // serial ports 2 & 3
+ pxa_gpio_mode(GPIO42_BTRXD_MD);
+ pxa_gpio_mode(GPIO43_BTTXD_MD);
+ pxa_gpio_mode(GPIO44_BTCTS_MD);
+ pxa_gpio_mode(GPIO45_BTRTS_MD);
+ pxa_gpio_mode(GPIO46_STRXD_MD);
+ pxa_gpio_mode(GPIO47_STTXD_MD);
+
+}
+
+
+MACHINE_START(PXA_IDP, "Vibren PXA255 IDP")
+ MAINTAINER("Vibren Technologies")
+ BOOT_MEM(0xa0000000, 0x40000000, io_p2v(0x40000000))
+ MAPIO(idp_map_io)
+ INITIRQ(idp_init_irq)
+ .timer = &pxa_timer,
+ INIT_MACHINE(idp_init)
+MACHINE_END
diff --git a/arch/arm/mach-pxa/irq.c b/arch/arm/mach-pxa/irq.c
new file mode 100644
index 000000000000..f3cac43124a5
--- /dev/null
+++ b/arch/arm/mach-pxa/irq.c
@@ -0,0 +1,313 @@
+/*
+ * linux/arch/arm/mach-pxa/irq.c
+ *
+ * Generic PXA IRQ handling, GPIO IRQ demultiplexing, etc.
+ *
+ * Author: Nicolas Pitre
+ * Created: Jun 15, 2001
+ * Copyright: MontaVista Software Inc.
+ *
+ * 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/init.h>
+#include <linux/module.h>
+#include <linux/interrupt.h>
+#include <linux/ptrace.h>
+
+#include <asm/hardware.h>
+#include <asm/irq.h>
+#include <asm/mach/irq.h>
+#include <asm/arch/pxa-regs.h>
+
+#include "generic.h"
+
+
+/*
+ * This is for peripheral IRQs internal to the PXA chip.
+ */
+
+static void pxa_mask_low_irq(unsigned int irq)
+{
+ ICMR &= ~(1 << (irq + PXA_IRQ_SKIP));
+}
+
+static void pxa_unmask_low_irq(unsigned int irq)
+{
+ ICMR |= (1 << (irq + PXA_IRQ_SKIP));
+}
+
+static struct irqchip pxa_internal_chip_low = {
+ .ack = pxa_mask_low_irq,
+ .mask = pxa_mask_low_irq,
+ .unmask = pxa_unmask_low_irq,
+};
+
+#if PXA_INTERNAL_IRQS > 32
+
+/*
+ * This is for the second set of internal IRQs as found on the PXA27x.
+ */
+
+static void pxa_mask_high_irq(unsigned int irq)
+{
+ ICMR2 &= ~(1 << (irq - 32 + PXA_IRQ_SKIP));
+}
+
+static void pxa_unmask_high_irq(unsigned int irq)
+{
+ ICMR2 |= (1 << (irq - 32 + PXA_IRQ_SKIP));
+}
+
+static struct irqchip pxa_internal_chip_high = {
+ .ack = pxa_mask_high_irq,
+ .mask = pxa_mask_high_irq,
+ .unmask = pxa_unmask_high_irq,
+};
+
+#endif
+
+/*
+ * PXA GPIO edge detection for IRQs:
+ * IRQs are generated on Falling-Edge, Rising-Edge, or both.
+ * Use this instead of directly setting GRER/GFER.
+ */
+
+static long GPIO_IRQ_rising_edge[4];
+static long GPIO_IRQ_falling_edge[4];
+static long GPIO_IRQ_mask[4];
+
+static int pxa_gpio_irq_type(unsigned int irq, unsigned int type)
+{
+ int gpio, idx;
+
+ gpio = IRQ_TO_GPIO(irq);
+ idx = gpio >> 5;
+
+ if (type == IRQT_PROBE) {
+ /* Don't mess with enabled GPIOs using preconfigured edges or
+ GPIOs set to alternate function during 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;
+ }
+
+ /* printk(KERN_DEBUG "IRQ%d (GPIO%d): ", irq, gpio); */
+
+ pxa_gpio_mode(gpio | GPIO_IN);
+
+ if (type & __IRQT_RISEDGE) {
+ /* printk("rising "); */
+ __set_bit (gpio, GPIO_IRQ_rising_edge);
+ } else
+ __clear_bit (gpio, GPIO_IRQ_rising_edge);
+
+ if (type & __IRQT_FALEDGE) {
+ /* printk("falling "); */
+ __set_bit (gpio, GPIO_IRQ_falling_edge);
+ } else
+ __clear_bit (gpio, GPIO_IRQ_falling_edge);
+
+ /* printk("edges\n"); */
+
+ GRER(gpio) = GPIO_IRQ_rising_edge[idx] & GPIO_IRQ_mask[idx];
+ GFER(gpio) = GPIO_IRQ_falling_edge[idx] & GPIO_IRQ_mask[idx];
+ return 0;
+}
+
+/*
+ * GPIO IRQs must be acknowledged. This is for GPIO 0 and 1.
+ */
+
+static void pxa_ack_low_gpio(unsigned int irq)
+{
+ GEDR0 = (1 << (irq - IRQ_GPIO0));
+}
+
+static struct irqchip pxa_low_gpio_chip = {
+ .ack = pxa_ack_low_gpio,
+ .mask = pxa_mask_low_irq,
+ .unmask = pxa_unmask_low_irq,
+ .type = pxa_gpio_irq_type,
+};
+
+/*
+ * Demux handler for GPIO>=2 edge detect interrupts
+ */
+
+static void pxa_gpio_demux_handler(unsigned int irq, struct irqdesc *desc,
+ struct pt_regs *regs)
+{
+ unsigned int mask;
+ int loop;
+
+ do {
+ loop = 0;
+
+ mask = GEDR0 & ~3;
+ if (mask) {
+ GEDR0 = mask;
+ irq = IRQ_GPIO(2);
+ desc = irq_desc + irq;
+ mask >>= 2;
+ do {
+ if (mask & 1)
+ desc->handle(irq, desc, regs);
+ irq++;
+ desc++;
+ mask >>= 1;
+ } while (mask);
+ loop = 1;
+ }
+
+ mask = GEDR1;
+ if (mask) {
+ GEDR1 = mask;
+ irq = IRQ_GPIO(32);
+ desc = irq_desc + irq;
+ do {
+ if (mask & 1)
+ desc->handle(irq, desc, regs);
+ irq++;
+ desc++;
+ mask >>= 1;
+ } while (mask);
+ loop = 1;
+ }
+
+ mask = GEDR2;
+ if (mask) {
+ GEDR2 = mask;
+ irq = IRQ_GPIO(64);
+ desc = irq_desc + irq;
+ do {
+ if (mask & 1)
+ desc->handle(irq, desc, regs);
+ irq++;
+ desc++;
+ mask >>= 1;
+ } while (mask);
+ loop = 1;
+ }
+
+#if PXA_LAST_GPIO >= 96
+ mask = GEDR3;
+ if (mask) {
+ GEDR3 = mask;
+ irq = IRQ_GPIO(96);
+ desc = irq_desc + irq;
+ do {
+ if (mask & 1)
+ desc->handle(irq, desc, regs);
+ irq++;
+ desc++;
+ mask >>= 1;
+ } while (mask);
+ loop = 1;
+ }
+#endif
+ } while (loop);
+}
+
+static void pxa_ack_muxed_gpio(unsigned int irq)
+{
+ int gpio = irq - IRQ_GPIO(2) + 2;
+ GEDR(gpio) = GPIO_bit(gpio);
+}
+
+static void pxa_mask_muxed_gpio(unsigned int irq)
+{
+ int gpio = irq - IRQ_GPIO(2) + 2;
+ __clear_bit(gpio, GPIO_IRQ_mask);
+ GRER(gpio) &= ~GPIO_bit(gpio);
+ GFER(gpio) &= ~GPIO_bit(gpio);
+}
+
+static void pxa_unmask_muxed_gpio(unsigned int irq)
+{
+ int gpio = irq - IRQ_GPIO(2) + 2;
+ int idx = gpio >> 5;
+ __set_bit(gpio, GPIO_IRQ_mask);
+ GRER(gpio) = GPIO_IRQ_rising_edge[idx] & GPIO_IRQ_mask[idx];
+ GFER(gpio) = GPIO_IRQ_falling_edge[idx] & GPIO_IRQ_mask[idx];
+}
+
+static struct irqchip pxa_muxed_gpio_chip = {
+ .ack = pxa_ack_muxed_gpio,
+ .mask = pxa_mask_muxed_gpio,
+ .unmask = pxa_unmask_muxed_gpio,
+ .type = pxa_gpio_irq_type,
+};
+
+
+void __init pxa_init_irq(void)
+{
+ int irq;
+
+ /* disable all IRQs */
+ ICMR = 0;
+
+ /* all IRQs are IRQ, not FIQ */
+ ICLR = 0;
+
+ /* clear all GPIO edge detects */
+ GFER0 = 0;
+ GFER1 = 0;
+ GFER2 = 0;
+ GRER0 = 0;
+ GRER1 = 0;
+ GRER2 = 0;
+ GEDR0 = GEDR0;
+ GEDR1 = GEDR1;
+ GEDR2 = GEDR2;
+
+#ifdef CONFIG_PXA27x
+ /* And similarly for the extra regs on the PXA27x */
+ ICMR2 = 0;
+ ICLR2 = 0;
+ GFER3 = 0;
+ GRER3 = 0;
+ GEDR3 = GEDR3;
+#endif
+
+ /* only unmasked interrupts kick us out of idle */
+ ICCR = 1;
+
+ /* GPIO 0 and 1 must have their mask bit always set */
+ GPIO_IRQ_mask[0] = 3;
+
+ for (irq = PXA_IRQ(PXA_IRQ_SKIP); irq <= PXA_IRQ(31); irq++) {
+ set_irq_chip(irq, &pxa_internal_chip_low);
+ set_irq_handler(irq, do_level_IRQ);
+ set_irq_flags(irq, IRQF_VALID);
+ }
+
+#if PXA_INTERNAL_IRQS > 32
+ for (irq = PXA_IRQ(32); irq < PXA_IRQ(PXA_INTERNAL_IRQS); irq++) {
+ set_irq_chip(irq, &pxa_internal_chip_high);
+ set_irq_handler(irq, do_level_IRQ);
+ set_irq_flags(irq, IRQF_VALID);
+ }
+#endif
+
+ for (irq = IRQ_GPIO0; irq <= IRQ_GPIO1; irq++) {
+ set_irq_chip(irq, &pxa_low_gpio_chip);
+ set_irq_handler(irq, do_edge_IRQ);
+ set_irq_flags(irq, IRQF_VALID | IRQF_PROBE);
+ }
+
+ for (irq = IRQ_GPIO(2); irq <= IRQ_GPIO(PXA_LAST_GPIO); irq++) {
+ set_irq_chip(irq, &pxa_muxed_gpio_chip);
+ set_irq_handler(irq, do_edge_IRQ);
+ set_irq_flags(irq, IRQF_VALID | IRQF_PROBE);
+ }
+
+ /* Install handler for GPIO>=2 edge detect interrupts */
+ set_irq_chip(IRQ_GPIO_2_x, &pxa_internal_chip_low);
+ set_irq_chained_handler(IRQ_GPIO_2_x, pxa_gpio_demux_handler);
+}
diff --git a/arch/arm/mach-pxa/leds-idp.c b/arch/arm/mach-pxa/leds-idp.c
new file mode 100644
index 000000000000..5eba6ea0b0f7
--- /dev/null
+++ b/arch/arm/mach-pxa/leds-idp.c
@@ -0,0 +1,117 @@
+/*
+ * linux/arch/arm/mach-pxa/leds-idp.c
+ *
+ * Copyright (C) 2000 John Dorsey <john+@cs.cmu.edu>
+ *
+ * Copyright (c) 2001 Jeff Sutherland <jeffs@accelent.com>
+ *
+ * Original (leds-footbridge.c) by Russell King
+ *
+ * Macros for actual LED manipulation should be in machine specific
+ * files in this 'mach' directory.
+ */
+
+
+#include <linux/config.h>
+#include <linux/init.h>
+
+#include <asm/hardware.h>
+#include <asm/leds.h>
+#include <asm/system.h>
+
+#include <asm/arch/pxa-regs.h>
+#include <asm/arch/idp.h>
+
+#include "leds.h"
+
+#define LED_STATE_ENABLED 1
+#define LED_STATE_CLAIMED 2
+
+static unsigned int led_state;
+static unsigned int hw_led_state;
+
+void idp_leds_event(led_event_t evt)
+{
+ unsigned long flags;
+
+ local_irq_save(flags);
+
+ switch (evt) {
+ case led_start:
+ hw_led_state = IDP_HB_LED | IDP_BUSY_LED;
+ led_state = LED_STATE_ENABLED;
+ break;
+
+ case led_stop:
+ led_state &= ~LED_STATE_ENABLED;
+ break;
+
+ case led_claim:
+ led_state |= LED_STATE_CLAIMED;
+ hw_led_state = IDP_HB_LED | IDP_BUSY_LED;
+ break;
+
+ case led_release:
+ led_state &= ~LED_STATE_CLAIMED;
+ hw_led_state = IDP_HB_LED | IDP_BUSY_LED;
+ break;
+
+#ifdef CONFIG_LEDS_TIMER
+ case led_timer:
+ if (!(led_state & LED_STATE_CLAIMED))
+ hw_led_state ^= IDP_HB_LED;
+ break;
+#endif
+
+#ifdef CONFIG_LEDS_CPU
+ case led_idle_start:
+ if (!(led_state & LED_STATE_CLAIMED))
+ hw_led_state &= ~IDP_BUSY_LED;
+ break;
+
+ case led_idle_end:
+ if (!(led_state & LED_STATE_CLAIMED))
+ hw_led_state |= IDP_BUSY_LED;
+ break;
+#endif
+
+ case led_halted:
+ break;
+
+ case led_green_on:
+ if (led_state & LED_STATE_CLAIMED)
+ hw_led_state |= IDP_HB_LED;
+ break;
+
+ case led_green_off:
+ if (led_state & LED_STATE_CLAIMED)
+ hw_led_state &= ~IDP_HB_LED;
+ break;
+
+ case led_amber_on:
+ break;
+
+ case led_amber_off:
+ break;
+
+ case led_red_on:
+ if (led_state & LED_STATE_CLAIMED)
+ hw_led_state |= IDP_BUSY_LED;
+ break;
+
+ case led_red_off:
+ if (led_state & LED_STATE_CLAIMED)
+ hw_led_state &= ~IDP_BUSY_LED;
+ break;
+
+ default:
+ break;
+ }
+
+ if (led_state & LED_STATE_ENABLED)
+ IDP_CPLD_LED_CONTROL = ( (IDP_CPLD_LED_CONTROL | IDP_LEDS_MASK) & ~hw_led_state);
+ else
+ IDP_CPLD_LED_CONTROL |= IDP_LEDS_MASK;
+
+ local_irq_restore(flags);
+}
diff --git a/arch/arm/mach-pxa/leds-lubbock.c b/arch/arm/mach-pxa/leds-lubbock.c
new file mode 100644
index 000000000000..05cf56059a0f
--- /dev/null
+++ b/arch/arm/mach-pxa/leds-lubbock.c
@@ -0,0 +1,126 @@
+/*
+ * linux/arch/arm/mach-pxa/leds-lubbock.c
+ *
+ * Copyright (C) 2000 John Dorsey <john+@cs.cmu.edu>
+ *
+ * Copyright (c) 2001 Jeff Sutherland <jeffs@accelent.com>
+ *
+ * Original (leds-footbridge.c) by Russell King
+ *
+ * Major surgery on April 2004 by Nicolas Pitre for less global
+ * namespace collision. Mostly adapted the Mainstone version.
+ */
+
+#include <linux/config.h>
+#include <linux/init.h>
+
+#include <asm/hardware.h>
+#include <asm/leds.h>
+#include <asm/system.h>
+#include <asm/arch/pxa-regs.h>
+#include <asm/arch/lubbock.h>
+
+#include "leds.h"
+
+/*
+ * 8 discrete leds available for general use:
+ *
+ * Note: bits [15-8] are used to enable/blank the 8 7 segment hex displays
+ * so be sure to not monkey with them here.
+ */
+
+#define D28 (1 << 0)
+#define D27 (1 << 1)
+#define D26 (1 << 2)
+#define D25 (1 << 3)
+#define D24 (1 << 4)
+#define D23 (1 << 5)
+#define D22 (1 << 6)
+#define D21 (1 << 7)
+
+#define LED_STATE_ENABLED 1
+#define LED_STATE_CLAIMED 2
+
+static unsigned int led_state;
+static unsigned int hw_led_state;
+
+void lubbock_leds_event(led_event_t evt)
+{
+ unsigned long flags;
+
+ local_irq_save(flags);
+
+ switch (evt) {
+ case led_start:
+ hw_led_state = 0;
+ led_state = LED_STATE_ENABLED;
+ break;
+
+ case led_stop:
+ led_state &= ~LED_STATE_ENABLED;
+ break;
+
+ case led_claim:
+ led_state |= LED_STATE_CLAIMED;
+ hw_led_state = 0;
+ break;
+
+ case led_release:
+ led_state &= ~LED_STATE_CLAIMED;
+ hw_led_state = 0;
+ break;
+
+#ifdef CONFIG_LEDS_TIMER
+ case led_timer:
+ hw_led_state ^= D26;
+ break;
+#endif
+
+#ifdef CONFIG_LEDS_CPU
+ case led_idle_start:
+ hw_led_state &= ~D27;
+ break;
+
+ case led_idle_end:
+ hw_led_state |= D27;
+ break;
+#endif
+
+ case led_halted:
+ break;
+
+ case led_green_on:
+ hw_led_state |= D21;
+ break;
+
+ case led_green_off:
+ hw_led_state &= ~D21;
+ break;
+
+ case led_amber_on:
+ hw_led_state |= D22;
+ break;
+
+ case led_amber_off:
+ hw_led_state &= ~D22;
+ break;
+
+ case led_red_on:
+ hw_led_state |= D23;
+ break;
+
+ case led_red_off:
+ hw_led_state &= ~D23;
+ break;
+
+ default:
+ break;
+ }
+
+ if (led_state & LED_STATE_ENABLED)
+ LUB_DISC_BLNK_LED = (LUB_DISC_BLNK_LED | 0xff) & ~hw_led_state;
+ else
+ LUB_DISC_BLNK_LED |= 0xff;
+
+ local_irq_restore(flags);
+}
diff --git a/arch/arm/mach-pxa/leds-mainstone.c b/arch/arm/mach-pxa/leds-mainstone.c
new file mode 100644
index 000000000000..bbd3f87a9fc2
--- /dev/null
+++ b/arch/arm/mach-pxa/leds-mainstone.c
@@ -0,0 +1,121 @@
+/*
+ * linux/arch/arm/mach-pxa/leds-mainstone.c
+ *
+ * Author: Nicolas Pitre
+ * Created: Nov 05, 2002
+ * Copyright: MontaVista Software Inc.
+ *
+ * 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/init.h>
+
+#include <asm/hardware.h>
+#include <asm/leds.h>
+#include <asm/system.h>
+
+#include <asm/arch/pxa-regs.h>
+#include <asm/arch/mainstone.h>
+
+#include "leds.h"
+
+
+/* 8 discrete leds available for general use: */
+#define D28 (1 << 0)
+#define D27 (1 << 1)
+#define D26 (1 << 2)
+#define D25 (1 << 3)
+#define D24 (1 << 4)
+#define D23 (1 << 5)
+#define D22 (1 << 6)
+#define D21 (1 << 7)
+
+#define LED_STATE_ENABLED 1
+#define LED_STATE_CLAIMED 2
+
+static unsigned int led_state;
+static unsigned int hw_led_state;
+
+void mainstone_leds_event(led_event_t evt)
+{
+ unsigned long flags;
+
+ local_irq_save(flags);
+
+ switch (evt) {
+ case led_start:
+ hw_led_state = 0;
+ led_state = LED_STATE_ENABLED;
+ break;
+
+ case led_stop:
+ led_state &= ~LED_STATE_ENABLED;
+ break;
+
+ case led_claim:
+ led_state |= LED_STATE_CLAIMED;
+ hw_led_state = 0;
+ break;
+
+ case led_release:
+ led_state &= ~LED_STATE_CLAIMED;
+ hw_led_state = 0;
+ break;
+
+#ifdef CONFIG_LEDS_TIMER
+ case led_timer:
+ hw_led_state ^= D26;
+ break;
+#endif
+
+#ifdef CONFIG_LEDS_CPU
+ case led_idle_start:
+ hw_led_state &= ~D27;
+ break;
+
+ case led_idle_end:
+ hw_led_state |= D27;
+ break;
+#endif
+
+ case led_halted:
+ break;
+
+ case led_green_on:
+ hw_led_state |= D21;;
+ break;
+
+ case led_green_off:
+ hw_led_state &= ~D21;
+ break;
+
+ case led_amber_on:
+ hw_led_state |= D22;;
+ break;
+
+ case led_amber_off:
+ hw_led_state &= ~D22;
+ break;
+
+ case led_red_on:
+ hw_led_state |= D23;;
+ break;
+
+ case led_red_off:
+ hw_led_state &= ~D23;
+ break;
+
+ default:
+ break;
+ }
+
+ if (led_state & LED_STATE_ENABLED)
+ MST_LEDCTRL = (MST_LEDCTRL | 0xff) & ~hw_led_state;
+ else
+ MST_LEDCTRL |= 0xff;
+
+ local_irq_restore(flags);
+}
diff --git a/arch/arm/mach-pxa/leds.c b/arch/arm/mach-pxa/leds.c
new file mode 100644
index 000000000000..bbe4d5f6afaa
--- /dev/null
+++ b/arch/arm/mach-pxa/leds.c
@@ -0,0 +1,32 @@
+/*
+ * linux/arch/arm/mach-pxa/leds.c
+ *
+ * xscale LEDs dispatcher
+ *
+ * Copyright (C) 2001 Nicolas Pitre
+ *
+ * Copyright (c) 2001 Jeff Sutherland, Accelent Systems Inc.
+ */
+#include <linux/compiler.h>
+#include <linux/init.h>
+
+#include <asm/leds.h>
+#include <asm/mach-types.h>
+
+#include "leds.h"
+
+static int __init
+pxa_leds_init(void)
+{
+ if (machine_is_lubbock())
+ leds_event = lubbock_leds_event;
+ if (machine_is_mainstone())
+ leds_event = mainstone_leds_event;
+ if (machine_is_pxa_idp())
+ leds_event = idp_leds_event;
+
+ leds_event(led_start);
+ return 0;
+}
+
+core_initcall(pxa_leds_init);
diff --git a/arch/arm/mach-pxa/leds.h b/arch/arm/mach-pxa/leds.h
new file mode 100644
index 000000000000..d98f6e93c12b
--- /dev/null
+++ b/arch/arm/mach-pxa/leds.h
@@ -0,0 +1,12 @@
+/*
+ * include/asm-arm/arch-pxa/leds.h
+ *
+ * Copyright (c) 2001 Jeff Sutherland, Accelent Systems Inc.
+ *
+ * blinky lights for various PXA-based systems:
+ *
+ */
+
+extern void idp_leds_event(led_event_t evt);
+extern void lubbock_leds_event(led_event_t evt);
+extern void mainstone_leds_event(led_event_t evt);
diff --git a/arch/arm/mach-pxa/lubbock.c b/arch/arm/mach-pxa/lubbock.c
new file mode 100644
index 000000000000..dd012d6e2f5c
--- /dev/null
+++ b/arch/arm/mach-pxa/lubbock.c
@@ -0,0 +1,247 @@
+/*
+ * linux/arch/arm/mach-pxa/lubbock.c
+ *
+ * Support for the Intel DBPXA250 Development Platform.
+ *
+ * Author: Nicolas Pitre
+ * Created: Jun 15, 2001
+ * Copyright: MontaVista Software Inc.
+ *
+ * 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/module.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/device.h>
+#include <linux/major.h>
+#include <linux/fb.h>
+#include <linux/interrupt.h>
+
+#include <asm/setup.h>
+#include <asm/memory.h>
+#include <asm/mach-types.h>
+#include <asm/hardware.h>
+#include <asm/irq.h>
+
+#include <asm/mach/arch.h>
+#include <asm/mach/map.h>
+#include <asm/mach/irq.h>
+
+#include <asm/hardware/sa1111.h>
+
+#include <asm/arch/pxa-regs.h>
+#include <asm/arch/lubbock.h>
+#include <asm/arch/udc.h>
+#include <asm/arch/pxafb.h>
+#include <asm/arch/mmc.h>
+
+#include "generic.h"
+
+
+#define LUB_MISC_WR __LUB_REG(LUBBOCK_FPGA_PHYS + 0x080)
+
+void lubbock_set_misc_wr(unsigned int mask, unsigned int set)
+{
+ unsigned long flags;
+
+ local_irq_save(flags);
+ LUB_MISC_WR = (LUB_MISC_WR & ~mask) | (set & mask);
+ local_irq_restore(flags);
+}
+EXPORT_SYMBOL(lubbock_set_misc_wr);
+
+static unsigned long lubbock_irq_enabled;
+
+static void lubbock_mask_irq(unsigned int irq)
+{
+ int lubbock_irq = (irq - LUBBOCK_IRQ(0));
+ LUB_IRQ_MASK_EN = (lubbock_irq_enabled &= ~(1 << lubbock_irq));
+}
+
+static void lubbock_unmask_irq(unsigned int irq)
+{
+ int lubbock_irq = (irq - LUBBOCK_IRQ(0));
+ /* the irq can be acknowledged only if deasserted, so it's done here */
+ LUB_IRQ_SET_CLR &= ~(1 << lubbock_irq);
+ LUB_IRQ_MASK_EN = (lubbock_irq_enabled |= (1 << lubbock_irq));
+}
+
+static struct irqchip lubbock_irq_chip = {
+ .ack = lubbock_mask_irq,
+ .mask = lubbock_mask_irq,
+ .unmask = lubbock_unmask_irq,
+};
+
+static void lubbock_irq_handler(unsigned int irq, struct irqdesc *desc,
+ struct pt_regs *regs)
+{
+ unsigned long pending = LUB_IRQ_SET_CLR & lubbock_irq_enabled;
+ do {
+ GEDR(0) = GPIO_bit(0); /* clear our parent irq */
+ if (likely(pending)) {
+ irq = LUBBOCK_IRQ(0) + __ffs(pending);
+ desc = irq_desc + irq;
+ desc->handle(irq, desc, regs);
+ }
+ pending = LUB_IRQ_SET_CLR & lubbock_irq_enabled;
+ } while (pending);
+}
+
+static void __init lubbock_init_irq(void)
+{
+ int irq;
+
+ pxa_init_irq();
+
+ /* setup extra lubbock irqs */
+ for (irq = LUBBOCK_IRQ(0); irq <= LUBBOCK_LAST_IRQ; irq++) {
+ set_irq_chip(irq, &lubbock_irq_chip);
+ set_irq_handler(irq, do_level_IRQ);
+ set_irq_flags(irq, IRQF_VALID | IRQF_PROBE);
+ }
+
+ set_irq_chained_handler(IRQ_GPIO(0), lubbock_irq_handler);
+ set_irq_type(IRQ_GPIO(0), IRQT_FALLING);
+}
+
+static int lubbock_udc_is_connected(void)
+{
+ return (LUB_MISC_RD & (1 << 9)) == 0;
+}
+
+static struct pxa2xx_udc_mach_info udc_info __initdata = {
+ .udc_is_connected = lubbock_udc_is_connected,
+ // no D+ pullup; lubbock can't connect/disconnect in software
+};
+
+static struct resource sa1111_resources[] = {
+ [0] = {
+ .start = 0x10000000,
+ .end = 0x10001fff,
+ .flags = IORESOURCE_MEM,
+ },
+ [1] = {
+ .start = LUBBOCK_SA1111_IRQ,
+ .end = LUBBOCK_SA1111_IRQ,
+ .flags = IORESOURCE_IRQ,
+ },
+};
+
+static struct platform_device sa1111_device = {
+ .name = "sa1111",
+ .id = -1,
+ .num_resources = ARRAY_SIZE(sa1111_resources),
+ .resource = sa1111_resources,
+};
+
+static struct resource smc91x_resources[] = {
+ [0] = {
+ .name = "smc91x-regs",
+ .start = 0x0c000000,
+ .end = 0x0c0fffff,
+ .flags = IORESOURCE_MEM,
+ },
+ [1] = {
+ .start = LUBBOCK_ETH_IRQ,
+ .end = LUBBOCK_ETH_IRQ,
+ .flags = IORESOURCE_IRQ,
+ },
+ [2] = {
+ .name = "smc91x-attrib",
+ .start = 0x0e000000,
+ .end = 0x0e0fffff,
+ .flags = IORESOURCE_MEM,
+ },
+};
+
+static struct platform_device smc91x_device = {
+ .name = "smc91x",
+ .id = -1,
+ .num_resources = ARRAY_SIZE(smc91x_resources),
+ .resource = smc91x_resources,
+};
+
+static struct platform_device *devices[] __initdata = {
+ &sa1111_device,
+ &smc91x_device,
+};
+
+static struct pxafb_mach_info sharp_lm8v31 __initdata = {
+ .pixclock = 270000,
+ .xres = 640,
+ .yres = 480,
+ .bpp = 16,
+ .hsync_len = 1,
+ .left_margin = 3,
+ .right_margin = 3,
+ .vsync_len = 1,
+ .upper_margin = 0,
+ .lower_margin = 0,
+ .sync = FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
+ .cmap_greyscale = 0,
+ .cmap_inverse = 0,
+ .cmap_static = 0,
+ .lccr0 = LCCR0_SDS,
+ .lccr3 = LCCR3_PCP | LCCR3_Acb(255),
+};
+
+static int lubbock_mci_init(struct device *dev, irqreturn_t (*lubbock_detect_int)(int, void *, struct pt_regs *), void *data)
+{
+ /* setup GPIO for PXA25x MMC controller */
+ pxa_gpio_mode(GPIO6_MMCCLK_MD);
+ pxa_gpio_mode(GPIO8_MMCCS0_MD);
+
+ return 0;
+}
+
+static struct pxamci_platform_data lubbock_mci_platform_data = {
+ .ocr_mask = MMC_VDD_32_33|MMC_VDD_33_34,
+ .init = lubbock_mci_init,
+};
+
+static void __init lubbock_init(void)
+{
+ pxa_set_udc_info(&udc_info);
+ set_pxa_fb_info(&sharp_lm8v31);
+ pxa_set_mci_info(&lubbock_mci_platform_data);
+ (void) platform_add_devices(devices, ARRAY_SIZE(devices));
+}
+
+static struct map_desc lubbock_io_desc[] __initdata = {
+ { LUBBOCK_FPGA_VIRT, LUBBOCK_FPGA_PHYS, 0x00100000, MT_DEVICE }, /* CPLD */
+};
+
+static void __init lubbock_map_io(void)
+{
+ pxa_map_io();
+ iotable_init(lubbock_io_desc, ARRAY_SIZE(lubbock_io_desc));
+
+ /* This enables the BTUART */
+ pxa_gpio_mode(GPIO42_BTRXD_MD);
+ pxa_gpio_mode(GPIO43_BTTXD_MD);
+ pxa_gpio_mode(GPIO44_BTCTS_MD);
+ pxa_gpio_mode(GPIO45_BTRTS_MD);
+
+ /* This is for the SMC chip select */
+ pxa_gpio_mode(GPIO79_nCS_3_MD);
+
+ /* setup sleep mode values */
+ PWER = 0x00000002;
+ PFER = 0x00000000;
+ PRER = 0x00000002;
+ PGSR0 = 0x00008000;
+ PGSR1 = 0x003F0202;
+ PGSR2 = 0x0001C000;
+ PCFR |= PCFR_OPDE;
+}
+
+MACHINE_START(LUBBOCK, "Intel DBPXA250 Development Platform (aka Lubbock)")
+ MAINTAINER("MontaVista Software Inc.")
+ BOOT_MEM(0xa0000000, 0x40000000, io_p2v(0x40000000))
+ MAPIO(lubbock_map_io)
+ INITIRQ(lubbock_init_irq)
+ .timer = &pxa_timer,
+ INIT_MACHINE(lubbock_init)
+MACHINE_END
diff --git a/arch/arm/mach-pxa/mainstone.c b/arch/arm/mach-pxa/mainstone.c
new file mode 100644
index 000000000000..3f952237ae3d
--- /dev/null
+++ b/arch/arm/mach-pxa/mainstone.c
@@ -0,0 +1,316 @@
+/*
+ * linux/arch/arm/mach-pxa/mainstone.c
+ *
+ * Support for the Intel HCDDBBVA0 Development Platform.
+ * (go figure how they came up with such name...)
+ *
+ * Author: Nicolas Pitre
+ * Created: Nov 05, 2002
+ * Copyright: MontaVista Software Inc.
+ *
+ * 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/init.h>
+#include <linux/device.h>
+#include <linux/interrupt.h>
+#include <linux/sched.h>
+#include <linux/bitops.h>
+#include <linux/fb.h>
+
+#include <asm/types.h>
+#include <asm/setup.h>
+#include <asm/memory.h>
+#include <asm/mach-types.h>
+#include <asm/hardware.h>
+#include <asm/irq.h>
+
+#include <asm/mach/arch.h>
+#include <asm/mach/map.h>
+#include <asm/mach/irq.h>
+
+#include <asm/arch/pxa-regs.h>
+#include <asm/arch/mainstone.h>
+#include <asm/arch/audio.h>
+#include <asm/arch/pxafb.h>
+#include <asm/arch/mmc.h>
+
+#include "generic.h"
+
+
+static unsigned long mainstone_irq_enabled;
+
+static void mainstone_mask_irq(unsigned int irq)
+{
+ int mainstone_irq = (irq - MAINSTONE_IRQ(0));
+ MST_INTMSKENA = (mainstone_irq_enabled &= ~(1 << mainstone_irq));
+}
+
+static void mainstone_unmask_irq(unsigned int irq)
+{
+ int mainstone_irq = (irq - MAINSTONE_IRQ(0));
+ /* the irq can be acknowledged only if deasserted, so it's done here */
+ MST_INTSETCLR &= ~(1 << mainstone_irq);
+ MST_INTMSKENA = (mainstone_irq_enabled |= (1 << mainstone_irq));
+}
+
+static struct irqchip mainstone_irq_chip = {
+ .ack = mainstone_mask_irq,
+ .mask = mainstone_mask_irq,
+ .unmask = mainstone_unmask_irq,
+};
+
+
+static void mainstone_irq_handler(unsigned int irq, struct irqdesc *desc,
+ struct pt_regs *regs)
+{
+ unsigned long pending = MST_INTSETCLR & mainstone_irq_enabled;
+ do {
+ GEDR(0) = GPIO_bit(0); /* clear useless edge notification */
+ if (likely(pending)) {
+ irq = MAINSTONE_IRQ(0) + __ffs(pending);
+ desc = irq_desc + irq;
+ desc->handle(irq, desc, regs);
+ }
+ pending = MST_INTSETCLR & mainstone_irq_enabled;
+ } while (pending);
+}
+
+static void __init mainstone_init_irq(void)
+{
+ int irq;
+
+ pxa_init_irq();
+
+ /* setup extra Mainstone irqs */
+ for(irq = MAINSTONE_IRQ(0); irq <= MAINSTONE_IRQ(15); irq++) {
+ set_irq_chip(irq, &mainstone_irq_chip);
+ set_irq_handler(irq, do_level_IRQ);
+ set_irq_flags(irq, IRQF_VALID | IRQF_PROBE);
+ }
+ set_irq_flags(MAINSTONE_IRQ(8), 0);
+ set_irq_flags(MAINSTONE_IRQ(12), 0);
+
+ MST_INTMSKENA = 0;
+ MST_INTSETCLR = 0;
+
+ set_irq_chained_handler(IRQ_GPIO(0), mainstone_irq_handler);
+ set_irq_type(IRQ_GPIO(0), IRQT_FALLING);
+}
+
+
+static struct resource smc91x_resources[] = {
+ [0] = {
+ .start = (MST_ETH_PHYS + 0x300),
+ .end = (MST_ETH_PHYS + 0xfffff),
+ .flags = IORESOURCE_MEM,
+ },
+ [1] = {
+ .start = MAINSTONE_IRQ(3),
+ .end = MAINSTONE_IRQ(3),
+ .flags = IORESOURCE_IRQ,
+ }
+};
+
+static struct platform_device smc91x_device = {
+ .name = "smc91x",
+ .id = 0,
+ .num_resources = ARRAY_SIZE(smc91x_resources),
+ .resource = smc91x_resources,
+};
+
+static int mst_audio_startup(snd_pcm_substream_t *substream, void *priv)
+{
+ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+ MST_MSCWR2 &= ~MST_MSCWR2_AC97_SPKROFF;
+ return 0;
+}
+
+static void mst_audio_shutdown(snd_pcm_substream_t *substream, void *priv)
+{
+ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+ MST_MSCWR2 |= MST_MSCWR2_AC97_SPKROFF;
+}
+
+static long mst_audio_suspend_mask;
+
+static void mst_audio_suspend(void *priv)
+{
+ mst_audio_suspend_mask = MST_MSCWR2;
+ MST_MSCWR2 |= MST_MSCWR2_AC97_SPKROFF;
+}
+
+static void mst_audio_resume(void *priv)
+{
+ MST_MSCWR2 &= mst_audio_suspend_mask | ~MST_MSCWR2_AC97_SPKROFF;
+}
+
+static pxa2xx_audio_ops_t mst_audio_ops = {
+ .startup = mst_audio_startup,
+ .shutdown = mst_audio_shutdown,
+ .suspend = mst_audio_suspend,
+ .resume = mst_audio_resume,
+};
+
+static struct platform_device mst_audio_device = {
+ .name = "pxa2xx-ac97",
+ .id = -1,
+ .dev = { .platform_data = &mst_audio_ops },
+};
+
+static void mainstone_backlight_power(int on)
+{
+ if (on) {
+ pxa_gpio_mode(GPIO16_PWM0_MD);
+ pxa_set_cken(CKEN0_PWM0, 1);
+ PWM_CTRL0 = 0;
+ PWM_PWDUTY0 = 0x3ff;
+ PWM_PERVAL0 = 0x3ff;
+ } else {
+ PWM_CTRL0 = 0;
+ PWM_PWDUTY0 = 0x0;
+ PWM_PERVAL0 = 0x3FF;
+ pxa_set_cken(CKEN0_PWM0, 0);
+ }
+}
+
+static struct pxafb_mach_info toshiba_ltm04c380k __initdata = {
+ .pixclock = 50000,
+ .xres = 640,
+ .yres = 480,
+ .bpp = 16,
+ .hsync_len = 1,
+ .left_margin = 0x9f,
+ .right_margin = 1,
+ .vsync_len = 44,
+ .upper_margin = 0,
+ .lower_margin = 0,
+ .sync = FB_SYNC_HOR_HIGH_ACT|FB_SYNC_VERT_HIGH_ACT,
+ .lccr0 = LCCR0_Act,
+ .lccr3 = LCCR3_PCP,
+ .pxafb_backlight_power = mainstone_backlight_power,
+};
+
+static struct pxafb_mach_info toshiba_ltm035a776c __initdata = {
+ .pixclock = 110000,
+ .xres = 240,
+ .yres = 320,
+ .bpp = 16,
+ .hsync_len = 4,
+ .left_margin = 8,
+ .right_margin = 20,
+ .vsync_len = 3,
+ .upper_margin = 1,
+ .lower_margin = 10,
+ .sync = FB_SYNC_HOR_HIGH_ACT|FB_SYNC_VERT_HIGH_ACT,
+ .lccr0 = LCCR0_Act,
+ .lccr3 = LCCR3_PCP,
+ .pxafb_backlight_power = mainstone_backlight_power,
+};
+
+static int mainstone_mci_init(struct device *dev, irqreturn_t (*mstone_detect_int)(int, void *, struct pt_regs *), void *data)
+{
+ int err;
+
+ /*
+ * setup GPIO for PXA27x MMC controller
+ */
+ pxa_gpio_mode(GPIO32_MMCCLK_MD);
+ pxa_gpio_mode(GPIO112_MMCCMD_MD);
+ pxa_gpio_mode(GPIO92_MMCDAT0_MD);
+ pxa_gpio_mode(GPIO109_MMCDAT1_MD);
+ pxa_gpio_mode(GPIO110_MMCDAT2_MD);
+ pxa_gpio_mode(GPIO111_MMCDAT3_MD);
+
+ /* make sure SD/Memory Stick multiplexer's signals
+ * are routed to MMC controller
+ */
+ MST_MSCWR1 &= ~MST_MSCWR1_MS_SEL;
+
+ err = request_irq(MAINSTONE_MMC_IRQ, mstone_detect_int, SA_INTERRUPT,
+ "MMC card detect", data);
+ if (err) {
+ printk(KERN_ERR "mainstone_mci_init: MMC/SD: can't request MMC card detect IRQ\n");
+ return -1;
+ }
+
+ return 0;
+}
+
+static void mainstone_mci_setpower(struct device *dev, unsigned int vdd)
+{
+ struct pxamci_platform_data* p_d = dev->platform_data;
+
+ if (( 1 << vdd) & p_d->ocr_mask) {
+ printk(KERN_DEBUG "%s: on\n", __FUNCTION__);
+ MST_MSCWR1 |= MST_MSCWR1_MMC_ON;
+ MST_MSCWR1 &= ~MST_MSCWR1_MS_SEL;
+ } else {
+ printk(KERN_DEBUG "%s: off\n", __FUNCTION__);
+ MST_MSCWR1 &= ~MST_MSCWR1_MMC_ON;
+ }
+}
+
+static void mainstone_mci_exit(struct device *dev, void *data)
+{
+ free_irq(MAINSTONE_MMC_IRQ, data);
+}
+
+static struct pxamci_platform_data mainstone_mci_platform_data = {
+ .ocr_mask = MMC_VDD_32_33|MMC_VDD_33_34,
+ .init = mainstone_mci_init,
+ .setpower = mainstone_mci_setpower,
+ .exit = mainstone_mci_exit,
+};
+
+static void __init mainstone_init(void)
+{
+ /*
+ * On Mainstone, we route AC97_SYSCLK via GPIO45 to
+ * the audio daughter card
+ */
+ pxa_gpio_mode(GPIO45_SYSCLK_AC97_MD);
+
+ platform_device_register(&smc91x_device);
+ platform_device_register(&mst_audio_device);
+
+ /* reading Mainstone's "Virtual Configuration Register"
+ might be handy to select LCD type here */
+ if (0)
+ set_pxa_fb_info(&toshiba_ltm04c380k);
+ else
+ set_pxa_fb_info(&toshiba_ltm035a776c);
+
+ pxa_set_mci_info(&mainstone_mci_platform_data);
+}
+
+
+static struct map_desc mainstone_io_desc[] __initdata = {
+ { MST_FPGA_VIRT, MST_FPGA_PHYS, 0x00100000, MT_DEVICE }, /* CPLD */
+};
+
+static void __init mainstone_map_io(void)
+{
+ pxa_map_io();
+ iotable_init(mainstone_io_desc, ARRAY_SIZE(mainstone_io_desc));
+
+ /* initialize sleep mode regs (wake-up sources, etc) */
+ PGSR0 = 0x00008800;
+ PGSR1 = 0x00000002;
+ PGSR2 = 0x0001FC00;
+ PGSR3 = 0x00001F81;
+ PWER = 0xC0000002;
+ PRER = 0x00000002;
+ PFER = 0x00000002;
+}
+
+MACHINE_START(MAINSTONE, "Intel HCDDBBVA0 Development Platform (aka Mainstone)")
+ MAINTAINER("MontaVista Software Inc.")
+ BOOT_MEM(0xa0000000, 0x40000000, io_p2v(0x40000000))
+ MAPIO(mainstone_map_io)
+ INITIRQ(mainstone_init_irq)
+ .timer = &pxa_timer,
+ INIT_MACHINE(mainstone_init)
+MACHINE_END
diff --git a/arch/arm/mach-pxa/pm.c b/arch/arm/mach-pxa/pm.c
new file mode 100644
index 000000000000..82a4bf34c251
--- /dev/null
+++ b/arch/arm/mach-pxa/pm.c
@@ -0,0 +1,227 @@
+/*
+ * PXA250/210 Power Management Routines
+ *
+ * Original code for the SA11x0:
+ * Copyright (c) 2001 Cliff Brake <cbrake@accelent.com>
+ *
+ * Modified for the PXA250 by Nicolas Pitre:
+ * Copyright (c) 2002 Monta Vista Software, Inc.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License.
+ */
+#include <linux/config.h>
+#include <linux/init.h>
+#include <linux/suspend.h>
+#include <linux/errno.h>
+#include <linux/time.h>
+
+#include <asm/hardware.h>
+#include <asm/memory.h>
+#include <asm/system.h>
+#include <asm/arch/pxa-regs.h>
+#include <asm/arch/lubbock.h>
+#include <asm/mach/time.h>
+
+
+/*
+ * Debug macros
+ */
+#undef DEBUG
+
+extern void pxa_cpu_suspend(void);
+extern void pxa_cpu_resume(void);
+
+#define SAVE(x) sleep_save[SLEEP_SAVE_##x] = x
+#define RESTORE(x) x = sleep_save[SLEEP_SAVE_##x]
+
+#define RESTORE_GPLEVEL(n) do { \
+ GPSR##n = sleep_save[SLEEP_SAVE_GPLR##n]; \
+ GPCR##n = ~sleep_save[SLEEP_SAVE_GPLR##n]; \
+} while (0)
+
+/*
+ * List of global PXA peripheral registers to preserve.
+ * More ones like CP and general purpose register values are preserved
+ * with the stack pointer in sleep.S.
+ */
+enum { SLEEP_SAVE_START = 0,
+
+ SLEEP_SAVE_GPLR0, SLEEP_SAVE_GPLR1, SLEEP_SAVE_GPLR2, SLEEP_SAVE_GPLR3,
+ SLEEP_SAVE_GPDR0, SLEEP_SAVE_GPDR1, SLEEP_SAVE_GPDR2, SLEEP_SAVE_GPDR3,
+ SLEEP_SAVE_GRER0, SLEEP_SAVE_GRER1, SLEEP_SAVE_GRER2, SLEEP_SAVE_GRER3,
+ SLEEP_SAVE_GFER0, SLEEP_SAVE_GFER1, SLEEP_SAVE_GFER2, SLEEP_SAVE_GFER3,
+ SLEEP_SAVE_PGSR0, SLEEP_SAVE_PGSR1, SLEEP_SAVE_PGSR2, SLEEP_SAVE_PGSR3,
+
+ SLEEP_SAVE_GAFR0_L, SLEEP_SAVE_GAFR0_U,
+ SLEEP_SAVE_GAFR1_L, SLEEP_SAVE_GAFR1_U,
+ SLEEP_SAVE_GAFR2_L, SLEEP_SAVE_GAFR2_U,
+ SLEEP_SAVE_GAFR3_L, SLEEP_SAVE_GAFR3_U,
+
+ SLEEP_SAVE_PSTR,
+
+ SLEEP_SAVE_ICMR,
+ SLEEP_SAVE_CKEN,
+
+ SLEEP_SAVE_CKSUM,
+
+ SLEEP_SAVE_SIZE
+};
+
+
+static int pxa_pm_enter(suspend_state_t state)
+{
+ unsigned long sleep_save[SLEEP_SAVE_SIZE];
+ unsigned long checksum = 0;
+ struct timespec delta, rtc;
+ int i;
+
+ if (state != PM_SUSPEND_MEM)
+ return -EINVAL;
+
+#ifdef CONFIG_IWMMXT
+ /* force any iWMMXt context to ram **/
+ iwmmxt_task_disable(NULL);
+#endif
+
+ /* preserve current time */
+ rtc.tv_sec = RCNR;
+ rtc.tv_nsec = 0;
+ save_time_delta(&delta, &rtc);
+
+ SAVE(GPLR0); SAVE(GPLR1); SAVE(GPLR2);
+ SAVE(GPDR0); SAVE(GPDR1); SAVE(GPDR2);
+ SAVE(GRER0); SAVE(GRER1); SAVE(GRER2);
+ SAVE(GFER0); SAVE(GFER1); SAVE(GFER2);
+ SAVE(PGSR0); SAVE(PGSR1); SAVE(PGSR2);
+
+ SAVE(GAFR0_L); SAVE(GAFR0_U);
+ SAVE(GAFR1_L); SAVE(GAFR1_U);
+ SAVE(GAFR2_L); SAVE(GAFR2_U);
+
+#ifdef CONFIG_PXA27x
+ SAVE(GPLR3); SAVE(GPDR3); SAVE(GRER3); SAVE(GFER3); SAVE(PGSR3);
+ SAVE(GAFR3_L); SAVE(GAFR3_U);
+#endif
+
+ SAVE(ICMR);
+ ICMR = 0;
+
+ SAVE(CKEN);
+ CKEN = 0;
+
+ SAVE(PSTR);
+
+ /* Note: wake up source are set up in each machine specific files */
+
+ /* clear GPIO transition detect bits */
+ GEDR0 = GEDR0; GEDR1 = GEDR1; GEDR2 = GEDR2;
+#ifdef CONFIG_PXA27x
+ GEDR3 = GEDR3;
+#endif
+
+ /* Clear sleep reset status */
+ RCSR = RCSR_SMR;
+
+ /* set resume return address */
+ PSPR = virt_to_phys(pxa_cpu_resume);
+
+ /* before sleeping, calculate and save a checksum */
+ for (i = 0; i < SLEEP_SAVE_SIZE - 1; i++)
+ checksum += sleep_save[i];
+ sleep_save[SLEEP_SAVE_CKSUM] = checksum;
+
+ /* *** go zzz *** */
+ pxa_cpu_suspend();
+
+ /* after sleeping, validate the checksum */
+ checksum = 0;
+ for (i = 0; i < SLEEP_SAVE_SIZE - 1; i++)
+ checksum += sleep_save[i];
+
+ /* if invalid, display message and wait for a hardware reset */
+ if (checksum != sleep_save[SLEEP_SAVE_CKSUM]) {
+#ifdef CONFIG_ARCH_LUBBOCK
+ LUB_HEXLED = 0xbadbadc5;
+#endif
+ while (1)
+ pxa_cpu_suspend();
+ }
+
+ /* ensure not to come back here if it wasn't intended */
+ PSPR = 0;
+
+ /* restore registers */
+ RESTORE(GAFR0_L); RESTORE(GAFR0_U);
+ RESTORE(GAFR1_L); RESTORE(GAFR1_U);
+ RESTORE(GAFR2_L); RESTORE(GAFR2_U);
+ RESTORE_GPLEVEL(0); RESTORE_GPLEVEL(1); RESTORE_GPLEVEL(2);
+ RESTORE(GPDR0); RESTORE(GPDR1); RESTORE(GPDR2);
+ RESTORE(GRER0); RESTORE(GRER1); RESTORE(GRER2);
+ RESTORE(GFER0); RESTORE(GFER1); RESTORE(GFER2);
+ RESTORE(PGSR0); RESTORE(PGSR1); RESTORE(PGSR2);
+
+#ifdef CONFIG_PXA27x
+ RESTORE(GAFR3_L); RESTORE(GAFR3_U); RESTORE_GPLEVEL(3);
+ RESTORE(GPDR3); RESTORE(GRER3); RESTORE(GFER3); RESTORE(PGSR3);
+#endif
+
+ PSSR = PSSR_RDH | PSSR_PH;
+
+ RESTORE(CKEN);
+
+ ICLR = 0;
+ ICCR = 1;
+ RESTORE(ICMR);
+
+ RESTORE(PSTR);
+
+ /* restore current time */
+ rtc.tv_sec = RCNR;
+ restore_time_delta(&delta, &rtc);
+
+#ifdef DEBUG
+ printk(KERN_DEBUG "*** made it back from resume\n");
+#endif
+
+ return 0;
+}
+
+unsigned long sleep_phys_sp(void *sp)
+{
+ return virt_to_phys(sp);
+}
+
+/*
+ * Called after processes are frozen, but before we shut down devices.
+ */
+static int pxa_pm_prepare(suspend_state_t state)
+{
+ return 0;
+}
+
+/*
+ * Called after devices are re-setup, but before processes are thawed.
+ */
+static int pxa_pm_finish(suspend_state_t state)
+{
+ return 0;
+}
+
+/*
+ * Set to PM_DISK_FIRMWARE so we can quickly veto suspend-to-disk.
+ */
+static struct pm_ops pxa_pm_ops = {
+ .pm_disk_mode = PM_DISK_FIRMWARE,
+ .prepare = pxa_pm_prepare,
+ .enter = pxa_pm_enter,
+ .finish = pxa_pm_finish,
+};
+
+static int __init pxa_pm_init(void)
+{
+ pm_set_ops(&pxa_pm_ops);
+ return 0;
+}
+
+late_initcall(pxa_pm_init);
diff --git a/arch/arm/mach-pxa/poodle.c b/arch/arm/mach-pxa/poodle.c
new file mode 100644
index 000000000000..b6c746ea3830
--- /dev/null
+++ b/arch/arm/mach-pxa/poodle.c
@@ -0,0 +1,189 @@
+/*
+ * linux/arch/arm/mach-pxa/poodle.c
+ *
+ * Support for the SHARP Poodle Board.
+ *
+ * Based on:
+ * linux/arch/arm/mach-pxa/lubbock.c Author: Nicolas Pitre
+ *
+ * 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.
+ *
+ * Change Log
+ * 12-Dec-2002 Sharp Corporation for Poodle
+ * John Lenz <lenz@cs.wisc.edu> updates to 2.6
+ */
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/device.h>
+#include <linux/fb.h>
+
+#include <asm/hardware.h>
+#include <asm/mach-types.h>
+#include <asm/irq.h>
+#include <asm/setup.h>
+
+#include <asm/mach/arch.h>
+#include <asm/mach/map.h>
+#include <asm/mach/irq.h>
+
+#include <asm/arch/pxa-regs.h>
+#include <asm/arch/irq.h>
+#include <asm/arch/poodle.h>
+#include <asm/arch/pxafb.h>
+
+#include <asm/hardware/scoop.h>
+#include <asm/hardware/locomo.h>
+#include <asm/mach/sharpsl_param.h>
+
+#include "generic.h"
+
+static struct resource poodle_scoop_resources[] = {
+ [0] = {
+ .start = 0x10800000,
+ .end = 0x10800fff,
+ .flags = IORESOURCE_MEM,
+ },
+};
+
+static struct scoop_config poodle_scoop_setup = {
+ .io_dir = POODLE_SCOOP_IO_DIR,
+ .io_out = POODLE_SCOOP_IO_OUT,
+};
+
+struct platform_device poodle_scoop_device = {
+ .name = "sharp-scoop",
+ .id = -1,
+ .dev = {
+ .platform_data = &poodle_scoop_setup,
+ },
+ .num_resources = ARRAY_SIZE(poodle_scoop_resources),
+ .resource = poodle_scoop_resources,
+};
+
+
+/* LoCoMo device */
+static struct resource locomo_resources[] = {
+ [0] = {
+ .start = 0x10000000,
+ .end = 0x10001fff,
+ .flags = IORESOURCE_MEM,
+ },
+ [1] = {
+ .start = IRQ_GPIO(10),
+ .end = IRQ_GPIO(10),
+ .flags = IORESOURCE_IRQ,
+ },
+};
+
+static struct platform_device locomo_device = {
+ .name = "locomo",
+ .id = 0,
+ .num_resources = ARRAY_SIZE(locomo_resources),
+ .resource = locomo_resources,
+};
+
+/* PXAFB device */
+static struct pxafb_mach_info poodle_fb_info __initdata = {
+ .pixclock = 144700,
+
+ .xres = 320,
+ .yres = 240,
+ .bpp = 16,
+
+ .hsync_len = 7,
+ .left_margin = 11,
+ .right_margin = 30,
+
+ .vsync_len = 2,
+ .upper_margin = 2,
+ .lower_margin = 0,
+ .sync = FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
+
+ .lccr0 = LCCR0_Act | LCCR0_Sngl | LCCR0_Color,
+ .lccr3 = 0,
+
+ .pxafb_backlight_power = NULL,
+ .pxafb_lcd_power = NULL,
+};
+
+static struct platform_device *devices[] __initdata = {
+ &locomo_device,
+ &poodle_scoop_device,
+};
+
+static void __init poodle_init(void)
+{
+ int ret = 0;
+
+ /* cpu initialize */
+ /* Pgsr Register */
+ PGSR0 = 0x0146dd80;
+ PGSR1 = 0x03bf0890;
+ PGSR2 = 0x0001c000;
+
+ /* Alternate Register */
+ GAFR0_L = 0x01001000;
+ GAFR0_U = 0x591a8010;
+ GAFR1_L = 0x900a8451;
+ GAFR1_U = 0xaaa5aaaa;
+ GAFR2_L = 0x8aaaaaaa;
+ GAFR2_U = 0x00000002;
+
+ /* Direction Register */
+ GPDR0 = 0xd3f0904c;
+ GPDR1 = 0xfcffb7d3;
+ GPDR2 = 0x0001ffff;
+
+ /* Output Register */
+ GPCR0 = 0x00000000;
+ GPCR1 = 0x00000000;
+ GPCR2 = 0x00000000;
+
+ GPSR0 = 0x00400000;
+ GPSR1 = 0x00000000;
+ GPSR2 = 0x00000000;
+
+ set_pxa_fb_info(&poodle_fb_info);
+
+ ret = platform_add_devices(devices, ARRAY_SIZE(devices));
+ if (ret) {
+ printk(KERN_WARNING "poodle: Unable to register LoCoMo device\n");
+ }
+}
+
+static void __init fixup_poodle(struct machine_desc *desc,
+ struct tag *tags, char **cmdline, struct meminfo *mi)
+{
+ sharpsl_save_param();
+}
+
+static struct map_desc poodle_io_desc[] __initdata = {
+ /* virtual physical length */
+ { 0xef800000, 0x00000000, 0x00800000, MT_DEVICE }, /* Boot Flash */
+};
+
+static void __init poodle_map_io(void)
+{
+ pxa_map_io();
+ iotable_init(poodle_io_desc, ARRAY_SIZE(poodle_io_desc));
+
+ /* setup sleep mode values */
+ PWER = 0x00000002;
+ PFER = 0x00000000;
+ PRER = 0x00000002;
+ PGSR0 = 0x00008000;
+ PGSR1 = 0x003F0202;
+ PGSR2 = 0x0001C000;
+ PCFR |= PCFR_OPDE;
+}
+
+MACHINE_START(POODLE, "SHARP Poodle")
+ BOOT_MEM(0xa0000000, 0x40000000, io_p2v(0x40000000))
+ FIXUP(fixup_poodle)
+ MAPIO(poodle_map_io)
+ INITIRQ(pxa_init_irq)
+ .timer = &pxa_timer,
+ .init_machine = poodle_init,
+MACHINE_END
diff --git a/arch/arm/mach-pxa/pxa25x.c b/arch/arm/mach-pxa/pxa25x.c
new file mode 100644
index 000000000000..e887b7175ef3
--- /dev/null
+++ b/arch/arm/mach-pxa/pxa25x.c
@@ -0,0 +1,104 @@
+/*
+ * linux/arch/arm/mach-pxa/pxa25x.c
+ *
+ * Author: Nicolas Pitre
+ * Created: Jun 15, 2001
+ * Copyright: MontaVista Software Inc.
+ *
+ * Code specific to PXA21x/25x/26x variants.
+ *
+ * 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.
+ *
+ * Since this file should be linked before any other machine specific file,
+ * the __initcall() here will be executed first. This serves as default
+ * initialization stuff for PXA machines which can be overridden later if
+ * need be.
+ */
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/pm.h>
+
+#include <asm/hardware.h>
+#include <asm/arch/pxa-regs.h>
+
+#include "generic.h"
+
+/*
+ * Various clock factors driven by the CCCR register.
+ */
+
+/* Crystal Frequency to Memory Frequency Multiplier (L) */
+static unsigned char L_clk_mult[32] = { 0, 27, 32, 36, 40, 45, 0, };
+
+/* Memory Frequency to Run Mode Frequency Multiplier (M) */
+static unsigned char M_clk_mult[4] = { 0, 1, 2, 4 };
+
+/* Run Mode Frequency to Turbo Mode Frequency Multiplier (N) */
+/* Note: we store the value N * 2 here. */
+static unsigned char N2_clk_mult[8] = { 0, 0, 2, 3, 4, 0, 6, 0 };
+
+/* Crystal clock */
+#define BASE_CLK 3686400
+
+/*
+ * Get the clock frequency as reflected by CCCR and the turbo flag.
+ * We assume these values have been applied via a fcs.
+ * If info is not 0 we also display the current settings.
+ */
+unsigned int get_clk_frequency_khz(int info)
+{
+ unsigned long cccr, turbo;
+ unsigned int l, L, m, M, n2, N;
+
+ cccr = CCCR;
+ asm( "mrc\tp14, 0, %0, c6, c0, 0" : "=r" (turbo) );
+
+ l = L_clk_mult[(cccr >> 0) & 0x1f];
+ m = M_clk_mult[(cccr >> 5) & 0x03];
+ n2 = N2_clk_mult[(cccr >> 7) & 0x07];
+
+ L = l * BASE_CLK;
+ M = m * L;
+ N = n2 * M / 2;
+
+ if(info)
+ {
+ L += 5000;
+ printk( KERN_INFO "Memory clock: %d.%02dMHz (*%d)\n",
+ L / 1000000, (L % 1000000) / 10000, l );
+ M += 5000;
+ printk( KERN_INFO "Run Mode clock: %d.%02dMHz (*%d)\n",
+ M / 1000000, (M % 1000000) / 10000, m );
+ N += 5000;
+ printk( KERN_INFO "Turbo Mode clock: %d.%02dMHz (*%d.%d, %sactive)\n",
+ N / 1000000, (N % 1000000) / 10000, n2 / 2, (n2 % 2) * 5,
+ (turbo & 1) ? "" : "in" );
+ }
+
+ return (turbo & 1) ? (N/1000) : (M/1000);
+}
+
+EXPORT_SYMBOL(get_clk_frequency_khz);
+
+/*
+ * Return the current memory clock frequency in units of 10kHz
+ */
+unsigned int get_memclk_frequency_10khz(void)
+{
+ return L_clk_mult[(CCCR >> 0) & 0x1f] * BASE_CLK / 10000;
+}
+
+EXPORT_SYMBOL(get_memclk_frequency_10khz);
+
+/*
+ * Return the current LCD clock frequency in units of 10kHz
+ */
+unsigned int get_lcdclk_frequency_10khz(void)
+{
+ return get_memclk_frequency_10khz();
+}
+
+EXPORT_SYMBOL(get_lcdclk_frequency_10khz);
diff --git a/arch/arm/mach-pxa/pxa27x.c b/arch/arm/mach-pxa/pxa27x.c
new file mode 100644
index 000000000000..7e863afefb53
--- /dev/null
+++ b/arch/arm/mach-pxa/pxa27x.c
@@ -0,0 +1,163 @@
+/*
+ * linux/arch/arm/mach-pxa/pxa27x.c
+ *
+ * Author: Nicolas Pitre
+ * Created: Nov 05, 2002
+ * Copyright: MontaVista Software Inc.
+ *
+ * Code specific to PXA27x aka Bulverde.
+ *
+ * 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/module.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/pm.h>
+#include <linux/device.h>
+
+#include <asm/hardware.h>
+#include <asm/irq.h>
+#include <asm/arch/pxa-regs.h>
+
+#include "generic.h"
+
+/* Crystal clock: 13MHz */
+#define BASE_CLK 13000000
+
+/*
+ * Get the clock frequency as reflected by CCSR and the turbo flag.
+ * We assume these values have been applied via a fcs.
+ * If info is not 0 we also display the current settings.
+ */
+unsigned int get_clk_frequency_khz( int info)
+{
+ unsigned long ccsr, clkcfg;
+ unsigned int l, L, m, M, n2, N, S;
+ int cccr_a, t, ht, b;
+
+ ccsr = CCSR;
+ cccr_a = CCCR & (1 << 25);
+
+ /* Read clkcfg register: it has turbo, b, half-turbo (and f) */
+ asm( "mrc\tp14, 0, %0, c6, c0, 0" : "=r" (clkcfg) );
+ t = clkcfg & (1 << 1);
+ ht = clkcfg & (1 << 2);
+ b = clkcfg & (1 << 3);
+
+ l = ccsr & 0x1f;
+ n2 = (ccsr>>7) & 0xf;
+ m = (l <= 10) ? 1 : (l <= 20) ? 2 : 4;
+
+ L = l * BASE_CLK;
+ N = (L * n2) / 2;
+ M = (!cccr_a) ? (L/m) : ((b) ? L : (L/2));
+ S = (b) ? L : (L/2);
+
+ if (info) {
+ printk( KERN_INFO "Run Mode clock: %d.%02dMHz (*%d)\n",
+ L / 1000000, (L % 1000000) / 10000, l );
+ printk( KERN_INFO "Turbo Mode clock: %d.%02dMHz (*%d.%d, %sactive)\n",
+ N / 1000000, (N % 1000000)/10000, n2 / 2, (n2 % 2)*5,
+ (t) ? "" : "in" );
+ printk( KERN_INFO "Memory clock: %d.%02dMHz (/%d)\n",
+ M / 1000000, (M % 1000000) / 10000, m );
+ printk( KERN_INFO "System bus clock: %d.%02dMHz \n",
+ S / 1000000, (S % 1000000) / 10000 );
+ }
+
+ return (t) ? (N/1000) : (L/1000);
+}
+
+/*
+ * Return the current mem clock frequency in units of 10kHz as
+ * reflected by CCCR[A], B, and L
+ */
+unsigned int get_memclk_frequency_10khz(void)
+{
+ unsigned long ccsr, clkcfg;
+ unsigned int l, L, m, M;
+ int cccr_a, b;
+
+ ccsr = CCSR;
+ cccr_a = CCCR & (1 << 25);
+
+ /* Read clkcfg register: it has turbo, b, half-turbo (and f) */
+ asm( "mrc\tp14, 0, %0, c6, c0, 0" : "=r" (clkcfg) );
+ b = clkcfg & (1 << 3);
+
+ l = ccsr & 0x1f;
+ m = (l <= 10) ? 1 : (l <= 20) ? 2 : 4;
+
+ L = l * BASE_CLK;
+ M = (!cccr_a) ? (L/m) : ((b) ? L : (L/2));
+
+ return (M / 10000);
+}
+
+/*
+ * Return the current LCD clock frequency in units of 10kHz as
+ */
+unsigned int get_lcdclk_frequency_10khz(void)
+{
+ unsigned long ccsr;
+ unsigned int l, L, k, K;
+
+ ccsr = CCSR;
+
+ l = ccsr & 0x1f;
+ k = (l <= 7) ? 1 : (l <= 16) ? 2 : 4;
+
+ L = l * BASE_CLK;
+ K = L / k;
+
+ return (K / 10000);
+}
+
+EXPORT_SYMBOL(get_clk_frequency_khz);
+EXPORT_SYMBOL(get_memclk_frequency_10khz);
+EXPORT_SYMBOL(get_lcdclk_frequency_10khz);
+
+
+/*
+ * device registration specific to PXA27x.
+ */
+
+static u64 pxa27x_dmamask = 0xffffffffUL;
+
+static struct resource pxa27x_ohci_resources[] = {
+ [0] = {
+ .start = 0x4C000000,
+ .end = 0x4C00ff6f,
+ .flags = IORESOURCE_MEM,
+ },
+ [1] = {
+ .start = IRQ_USBH1,
+ .end = IRQ_USBH1,
+ .flags = IORESOURCE_IRQ,
+ },
+};
+
+static struct platform_device ohci_device = {
+ .name = "pxa27x-ohci",
+ .id = -1,
+ .dev = {
+ .dma_mask = &pxa27x_dmamask,
+ .coherent_dma_mask = 0xffffffff,
+ },
+ .num_resources = ARRAY_SIZE(pxa27x_ohci_resources),
+ .resource = pxa27x_ohci_resources,
+};
+
+static struct platform_device *devices[] __initdata = {
+ &ohci_device,
+};
+
+static int __init pxa27x_init(void)
+{
+ return platform_add_devices(devices, ARRAY_SIZE(devices));
+}
+
+subsys_initcall(pxa27x_init);
diff --git a/arch/arm/mach-pxa/sleep.S b/arch/arm/mach-pxa/sleep.S
new file mode 100644
index 000000000000..16cad2c2497c
--- /dev/null
+++ b/arch/arm/mach-pxa/sleep.S
@@ -0,0 +1,194 @@
+/*
+ * Low-level PXA250/210 sleep/wakeUp support
+ *
+ * Initial SA1110 code:
+ * Copyright (c) 2001 Cliff Brake <cbrake@accelent.com>
+ *
+ * Adapted for PXA by Nicolas Pitre:
+ * Copyright (c) 2002 Monta Vista Software, Inc.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License.
+ */
+
+#include <linux/config.h>
+#include <linux/linkage.h>
+#include <asm/assembler.h>
+#include <asm/hardware.h>
+
+#include <asm/arch/pxa-regs.h>
+
+ .text
+
+/*
+ * pxa_cpu_suspend()
+ *
+ * Forces CPU into sleep state
+ */
+
+ENTRY(pxa_cpu_suspend)
+
+ mra r2, r3, acc0
+ stmfd sp!, {r2 - r12, lr} @ save registers on stack
+
+ @ get coprocessor registers
+ mrc p14, 0, r3, c6, c0, 0 @ clock configuration, for turbo mode
+ mrc p15, 0, r4, c15, c1, 0 @ CP access reg
+ mrc p15, 0, r5, c13, c0, 0 @ PID
+ mrc p15, 0, r6, c3, c0, 0 @ domain ID
+ mrc p15, 0, r7, c2, c0, 0 @ translation table base addr
+ mrc p15, 0, r8, c1, c1, 0 @ auxiliary control reg
+ mrc p15, 0, r9, c1, c0, 0 @ control reg
+
+ bic r3, r3, #2 @ clear frequency change bit
+
+ @ store them plus current virtual stack ptr on stack
+ mov r10, sp
+ stmfd sp!, {r3 - r10}
+
+ @ preserve phys address of stack
+ mov r0, sp
+ bl sleep_phys_sp
+ ldr r1, =sleep_save_sp
+ str r0, [r1]
+
+ @ clean data cache
+ bl xscale_flush_kern_cache_all
+
+ @ Put the processor to sleep
+ @ (also workaround for sighting 28071)
+
+ @ prepare value for sleep mode
+ mov r1, #3 @ sleep mode
+
+ @ prepare to put SDRAM into self-refresh manually
+ ldr r4, =MDREFR
+ ldr r5, [r4]
+ orr r5, r5, #MDREFR_SLFRSH
+
+ @ prepare pointer to physical address 0 (virtual mapping in generic.c)
+ mov r2, #UNCACHED_PHYS_0
+
+ @ Intel PXA255 Specification Update notes problems
+ @ about suspending with PXBus operating above 133MHz
+ @ (see Errata 31, GPIO output signals, ... unpredictable in sleep
+ @
+ @ We keep the change-down close to the actual suspend on SDRAM
+ @ as possible to eliminate messing about with the refresh clock
+ @ as the system will restore with the original speed settings
+ @
+ @ Ben Dooks, 13-Sep-2004
+
+ ldr r6, =CCCR
+ ldr r8, [r6] @ keep original value for resume
+
+ @ ensure x1 for run and turbo mode with memory clock
+ bic r7, r8, #CCCR_M_MASK | CCCR_N_MASK
+ orr r7, r7, #(1<<5) | (2<<7)
+
+ @ check that the memory frequency is within limits
+ and r14, r7, #CCCR_L_MASK
+ teq r14, #1
+ bicne r7, r7, #CCCR_L_MASK
+ orrne r7, r7, #1 @@ 99.53MHz
+
+ @ get ready for the change
+
+ @ note, turbo is not preserved over sleep so there is no
+ @ point in preserving it here. we save it on the stack with the
+ @ other CP registers instead.
+ mov r0, #0
+ mcr p14, 0, r0, c6, c0, 0
+ orr r0, r0, #2 @ initiate change bit
+
+ @ align execution to a cache line
+ b 1f
+
+ .ltorg
+ .align 5
+1:
+
+ @ All needed values are now in registers.
+ @ These last instructions should be in cache
+
+ @ initiate the frequency change...
+ str r7, [r6]
+ mcr p14, 0, r0, c6, c0, 0
+
+ @ restore the original cpu speed value for resume
+ str r8, [r6]
+
+ @ put SDRAM into self-refresh
+ str r5, [r4]
+
+ @ force address lines low by reading at physical address 0
+ ldr r3, [r2]
+
+ @ enter sleep mode
+ mcr p14, 0, r1, c7, c0, 0
+
+20: b 20b @ loop waiting for sleep
+
+/*
+ * cpu_pxa_resume()
+ *
+ * entry point from bootloader into kernel during resume
+ *
+ * Note: Yes, part of the following code is located into the .data section.
+ * This is to allow sleep_save_sp to be accessed with a relative load
+ * while we can't rely on any MMU translation. We could have put
+ * sleep_save_sp in the .text section as well, but some setups might
+ * insist on it to be truly read-only.
+ */
+
+ .data
+ .align 5
+ENTRY(pxa_cpu_resume)
+ mov r0, #PSR_I_BIT | PSR_F_BIT | MODE_SVC @ set SVC, irqs off
+ msr cpsr_c, r0
+
+ ldr r0, sleep_save_sp @ stack phys addr
+ ldr r2, =resume_after_mmu @ its absolute virtual address
+ ldmfd r0, {r3 - r9, sp} @ CP regs + virt stack ptr
+
+ mov r1, #0
+ mcr p15, 0, r1, c8, c7, 0 @ invalidate I & D TLBs
+ mcr p15, 0, r1, c7, c7, 0 @ invalidate I & D caches, BTB
+
+#ifdef CONFIG_XSCALE_CACHE_ERRATA
+ bic r9, r9, #0x0004 @ see cpu_xscale_proc_init
+#endif
+
+ mcr p14, 0, r3, c6, c0, 0 @ clock configuration, turbo mode.
+ mcr p15, 0, r4, c15, c1, 0 @ CP access reg
+ mcr p15, 0, r5, c13, c0, 0 @ PID
+ mcr p15, 0, r6, c3, c0, 0 @ domain ID
+ mcr p15, 0, r7, c2, c0, 0 @ translation table base addr
+ mcr p15, 0, r8, c1, c1, 0 @ auxiliary control reg
+ b resume_turn_on_mmu @ cache align execution
+
+ .align 5
+resume_turn_on_mmu:
+ mcr p15, 0, r9, c1, c0, 0 @ turn on MMU, caches, etc.
+
+ @ Let us ensure we jump to resume_after_mmu only when the mcr above
+ @ actually took effect. They call it the "cpwait" operation.
+ mrc p15, 0, r1, c2, c0, 0 @ queue a dependency on CP15
+ sub pc, r2, r1, lsr #32 @ jump to virtual addr
+ nop
+ nop
+ nop
+
+sleep_save_sp:
+ .word 0 @ preserve stack phys ptr here
+
+ .text
+resume_after_mmu:
+#ifdef CONFIG_XSCALE_CACHE_ERRATA
+ bl cpu_xscale_proc_init
+#endif
+ ldmfd sp!, {r2, r3}
+ mar acc0, r2, r3
+ ldmfd sp!, {r4 - r12, pc} @ return to caller
+
+
diff --git a/arch/arm/mach-pxa/ssp.c b/arch/arm/mach-pxa/ssp.c
new file mode 100644
index 000000000000..4d826c021315
--- /dev/null
+++ b/arch/arm/mach-pxa/ssp.c
@@ -0,0 +1,363 @@
+/*
+ * linux/arch/arm/mach-pxa/ssp.c
+ *
+ * based on linux/arch/arm/mach-sa1100/ssp.c by Russell King
+ *
+ * Copyright (C) 2003 Russell King.
+ * Copyright (C) 2003 Wolfson Microelectronics PLC
+ *
+ * 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.
+ *
+ * PXA2xx SSP driver. This provides the generic core for simple
+ * IO-based SSP applications and allows easy port setup for DMA access.
+ *
+ * Author: Liam Girdwood <liam.girdwood@wolfsonmicro.com>
+ *
+ * Revision history:
+ * 22nd Aug 2003 Initial version.
+ * 20th Dec 2004 Added ssp_config for changing port config without
+ * closing the port.
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/slab.h>
+#include <linux/errno.h>
+#include <linux/interrupt.h>
+#include <linux/ioport.h>
+#include <linux/init.h>
+#include <asm/io.h>
+#include <asm/irq.h>
+#include <asm/hardware.h>
+#include <asm/arch/ssp.h>
+#include <asm/arch/pxa-regs.h>
+
+#define PXA_SSP_PORTS 3
+
+static DECLARE_MUTEX(sem);
+static int use_count[PXA_SSP_PORTS] = {0, 0, 0};
+
+static irqreturn_t ssp_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+{
+ struct ssp_dev *dev = (struct ssp_dev*) dev_id;
+ unsigned int status = SSSR_P(dev->port);
+
+ SSSR_P(dev->port) = status; /* clear status bits */
+
+ if (status & SSSR_ROR)
+ printk(KERN_WARNING "SSP(%d): receiver overrun\n", dev->port);
+
+ if (status & SSSR_TUR)
+ printk(KERN_WARNING "SSP(%d): transmitter underrun\n", dev->port);
+
+ if (status & SSSR_BCE)
+ printk(KERN_WARNING "SSP(%d): bit count error\n", dev->port);
+
+ return IRQ_HANDLED;
+}
+
+/**
+ * ssp_write_word - write a word to the SSP port
+ * @data: 32-bit, MSB justified data to write.
+ *
+ * Wait for a free entry in the SSP transmit FIFO, and write a data
+ * word to the SSP port.
+ *
+ * The caller is expected to perform the necessary locking.
+ *
+ * Returns:
+ * %-ETIMEDOUT timeout occurred (for future)
+ * 0 success
+ */
+int ssp_write_word(struct ssp_dev *dev, u32 data)
+{
+ while (!(SSSR_P(dev->port) & SSSR_TNF))
+ cpu_relax();
+
+ SSDR_P(dev->port) = data;
+
+ return 0;
+}
+
+/**
+ * ssp_read_word - read a word from the SSP port
+ *
+ * Wait for a data word in the SSP receive FIFO, and return the
+ * received data. Data is LSB justified.
+ *
+ * Note: Currently, if data is not expected to be received, this
+ * function will wait for ever.
+ *
+ * The caller is expected to perform the necessary locking.
+ *
+ * Returns:
+ * %-ETIMEDOUT timeout occurred (for future)
+ * 32-bit data success
+ */
+int ssp_read_word(struct ssp_dev *dev)
+{
+ while (!(SSSR_P(dev->port) & SSSR_RNE))
+ cpu_relax();
+
+ return SSDR_P(dev->port);
+}
+
+/**
+ * ssp_flush - flush the transmit and receive FIFOs
+ *
+ * Wait for the SSP to idle, and ensure that the receive FIFO
+ * is empty.
+ *
+ * The caller is expected to perform the necessary locking.
+ */
+void ssp_flush(struct ssp_dev *dev)
+{
+ do {
+ while (SSSR_P(dev->port) & SSSR_RNE) {
+ (void) SSDR_P(dev->port);
+ }
+ } while (SSSR_P(dev->port) & SSSR_BSY);
+}
+
+/**
+ * ssp_enable - enable the SSP port
+ *
+ * Turn on the SSP port.
+ */
+void ssp_enable(struct ssp_dev *dev)
+{
+ SSCR0_P(dev->port) |= SSCR0_SSE;
+}
+
+/**
+ * ssp_disable - shut down the SSP port
+ *
+ * Turn off the SSP port, optionally powering it down.
+ */
+void ssp_disable(struct ssp_dev *dev)
+{
+ SSCR0_P(dev->port) &= ~SSCR0_SSE;
+}
+
+/**
+ * ssp_save_state - save the SSP configuration
+ * @ssp: pointer to structure to save SSP configuration
+ *
+ * Save the configured SSP state for suspend.
+ */
+void ssp_save_state(struct ssp_dev *dev, struct ssp_state *ssp)
+{
+ ssp->cr0 = SSCR0_P(dev->port);
+ ssp->cr1 = SSCR1_P(dev->port);
+ ssp->to = SSTO_P(dev->port);
+ ssp->psp = SSPSP_P(dev->port);
+
+ SSCR0_P(dev->port) &= ~SSCR0_SSE;
+}
+
+/**
+ * ssp_restore_state - restore a previously saved SSP configuration
+ * @ssp: pointer to configuration saved by ssp_save_state
+ *
+ * Restore the SSP configuration saved previously by ssp_save_state.
+ */
+void ssp_restore_state(struct ssp_dev *dev, struct ssp_state *ssp)
+{
+ SSSR_P(dev->port) = SSSR_ROR | SSSR_TUR | SSSR_BCE;
+
+ SSCR0_P(dev->port) = ssp->cr0 & ~SSCR0_SSE;
+ SSCR1_P(dev->port) = ssp->cr1;
+ SSTO_P(dev->port) = ssp->to;
+ SSPSP_P(dev->port) = ssp->psp;
+
+ SSCR0_P(dev->port) = ssp->cr0;
+}
+
+/**
+ * ssp_config - configure SSP port settings
+ * @mode: port operating mode
+ * @flags: port config flags
+ * @psp_flags: port PSP config flags
+ * @speed: port speed
+ *
+ * Port MUST be disabled by ssp_disable before making any config changes.
+ */
+int ssp_config(struct ssp_dev *dev, u32 mode, u32 flags, u32 psp_flags, u32 speed)
+{
+ dev->mode = mode;
+ dev->flags = flags;
+ dev->psp_flags = psp_flags;
+ dev->speed = speed;
+
+ /* set up port type, speed, port settings */
+ SSCR0_P(dev->port) = (dev->speed | dev->mode);
+ SSCR1_P(dev->port) = dev->flags;
+ SSPSP_P(dev->port) = dev->psp_flags;
+
+ return 0;
+}
+
+/**
+ * ssp_init - setup the SSP port
+ *
+ * initialise and claim resources for the SSP port.
+ *
+ * Returns:
+ * %-ENODEV if the SSP port is unavailable
+ * %-EBUSY if the resources are already in use
+ * %0 on success
+ */
+int ssp_init(struct ssp_dev *dev, u32 port)
+{
+ int ret, irq;
+
+ if (port > PXA_SSP_PORTS || port == 0)
+ return -ENODEV;
+
+ down(&sem);
+ if (use_count[port - 1]) {
+ up(&sem);
+ return -EBUSY;
+ }
+ use_count[port - 1]++;
+
+ if (!request_mem_region(__PREG(SSCR0_P(port)), 0x2c, "SSP")) {
+ use_count[port - 1]--;
+ up(&sem);
+ return -EBUSY;
+ }
+
+ switch (port) {
+ case 1:
+ irq = IRQ_SSP;
+ break;
+#if defined (CONFIG_PXA27x)
+ case 2:
+ irq = IRQ_SSP2;
+ break;
+ case 3:
+ irq = IRQ_SSP3;
+ break;
+#else
+ case 2:
+ irq = IRQ_NSSP;
+ break;
+ case 3:
+ irq = IRQ_ASSP;
+ break;
+#endif
+ default:
+ return -ENODEV;
+ }
+
+ dev->port = port;
+
+ ret = request_irq(irq, ssp_interrupt, 0, "SSP", dev);
+ if (ret)
+ goto out_region;
+
+ /* turn on SSP port clock */
+ switch (dev->port) {
+#if defined (CONFIG_PXA27x)
+ case 1:
+ pxa_set_cken(CKEN23_SSP1, 1);
+ break;
+ case 2:
+ pxa_set_cken(CKEN3_SSP2, 1);
+ break;
+ case 3:
+ pxa_set_cken(CKEN4_SSP3, 1);
+ break;
+#else
+ case 1:
+ pxa_set_cken(CKEN3_SSP, 1);
+ break;
+ case 2:
+ pxa_set_cken(CKEN9_NSSP, 1);
+ break;
+ case 3:
+ pxa_set_cken(CKEN10_ASSP, 1);
+ break;
+#endif
+ }
+
+ up(&sem);
+ return 0;
+
+out_region:
+ release_mem_region(__PREG(SSCR0_P(port)), 0x2c);
+ use_count[port - 1]--;
+ up(&sem);
+ return ret;
+}
+
+/**
+ * ssp_exit - undo the effects of ssp_init
+ *
+ * release and free resources for the SSP port.
+ */
+void ssp_exit(struct ssp_dev *dev)
+{
+ int irq;
+
+ down(&sem);
+ SSCR0_P(dev->port) &= ~SSCR0_SSE;
+
+ /* find irq, save power and turn off SSP port clock */
+ switch (dev->port) {
+#if defined (CONFIG_PXA27x)
+ case 1:
+ irq = IRQ_SSP;
+ pxa_set_cken(CKEN23_SSP1, 0);
+ break;
+ case 2:
+ irq = IRQ_SSP2;
+ pxa_set_cken(CKEN3_SSP2, 0);
+ break;
+ case 3:
+ irq = IRQ_SSP3;
+ pxa_set_cken(CKEN4_SSP3, 0);
+ break;
+#else
+ case 1:
+ irq = IRQ_SSP;
+ pxa_set_cken(CKEN3_SSP, 0);
+ break;
+ case 2:
+ irq = IRQ_NSSP;
+ pxa_set_cken(CKEN9_NSSP, 0);
+ break;
+ case 3:
+ irq = IRQ_ASSP;
+ pxa_set_cken(CKEN10_ASSP, 0);
+ break;
+#endif
+ default:
+ printk(KERN_WARNING "SSP: tried to close invalid port\n");
+ return;
+ }
+
+ free_irq(irq, dev);
+ release_mem_region(__PREG(SSCR0_P(dev->port)), 0x2c);
+ use_count[dev->port - 1]--;
+ up(&sem);
+}
+
+EXPORT_SYMBOL(ssp_write_word);
+EXPORT_SYMBOL(ssp_read_word);
+EXPORT_SYMBOL(ssp_flush);
+EXPORT_SYMBOL(ssp_enable);
+EXPORT_SYMBOL(ssp_disable);
+EXPORT_SYMBOL(ssp_save_state);
+EXPORT_SYMBOL(ssp_restore_state);
+EXPORT_SYMBOL(ssp_init);
+EXPORT_SYMBOL(ssp_exit);
+EXPORT_SYMBOL(ssp_config);
+
+MODULE_DESCRIPTION("PXA SSP driver");
+MODULE_AUTHOR("Liam Girdwood");
+MODULE_LICENSE("GPL");
+
diff --git a/arch/arm/mach-pxa/time.c b/arch/arm/mach-pxa/time.c
new file mode 100644
index 000000000000..473fb6173f72
--- /dev/null
+++ b/arch/arm/mach-pxa/time.c
@@ -0,0 +1,164 @@
+/*
+ * arch/arm/mach-pxa/time.c
+ *
+ * Author: Nicolas Pitre
+ * Created: Jun 15, 2001
+ * Copyright: MontaVista Software Inc.
+ *
+ * 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/init.h>
+#include <linux/delay.h>
+#include <linux/interrupt.h>
+#include <linux/time.h>
+#include <linux/signal.h>
+#include <linux/errno.h>
+#include <linux/sched.h>
+
+#include <asm/system.h>
+#include <asm/hardware.h>
+#include <asm/io.h>
+#include <asm/leds.h>
+#include <asm/irq.h>
+#include <asm/mach/irq.h>
+#include <asm/mach/time.h>
+#include <asm/arch/pxa-regs.h>
+
+
+static inline unsigned long pxa_get_rtc_time(void)
+{
+ return RCNR;
+}
+
+static int pxa_set_rtc(void)
+{
+ unsigned long current_time = xtime.tv_sec;
+
+ if (RTSR & RTSR_ALE) {
+ /* make sure not to forward the clock over an alarm */
+ unsigned long alarm = RTAR;
+ if (current_time >= alarm && alarm >= RCNR)
+ return -ERESTARTSYS;
+ }
+ RCNR = current_time;
+ return 0;
+}
+
+/* IRQs are disabled before entering here from do_gettimeofday() */
+static unsigned long pxa_gettimeoffset (void)
+{
+ long ticks_to_match, elapsed, usec;
+
+ /* Get ticks before next timer match */
+ ticks_to_match = OSMR0 - OSCR;
+
+ /* We need elapsed ticks since last match */
+ elapsed = LATCH - ticks_to_match;
+
+ /* don't get fooled by the workaround in pxa_timer_interrupt() */
+ if (elapsed <= 0)
+ return 0;
+
+ /* Now convert them to usec */
+ usec = (unsigned long)(elapsed * (tick_nsec / 1000))/LATCH;
+
+ return usec;
+}
+
+static irqreturn_t
+pxa_timer_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+{
+ int next_match;
+
+ write_seqlock(&xtime_lock);
+
+ /* Loop until we get ahead of the free running timer.
+ * This ensures an exact clock tick count and time accuracy.
+ * IRQs are disabled inside the loop to ensure coherence between
+ * lost_ticks (updated in do_timer()) and the match reg value, so we
+ * can use do_gettimeofday() from interrupt handlers.
+ *
+ * HACK ALERT: it seems that the PXA timer regs aren't updated right
+ * away in all cases when a write occurs. We therefore compare with
+ * 8 instead of 0 in the while() condition below to avoid missing a
+ * match if OSCR has already reached the next OSMR value.
+ * Experience has shown that up to 6 ticks are needed to work around
+ * this problem, but let's use 8 to be conservative. Note that this
+ * affect things only when the timer IRQ has been delayed by nearly
+ * exactly one tick period which should be a pretty rare event.
+ */
+ do {
+ timer_tick(regs);
+ OSSR = OSSR_M0; /* Clear match on timer 0 */
+ next_match = (OSMR0 += LATCH);
+ } while( (signed long)(next_match - OSCR) <= 8 );
+
+ write_sequnlock(&xtime_lock);
+
+ return IRQ_HANDLED;
+}
+
+static struct irqaction pxa_timer_irq = {
+ .name = "PXA Timer Tick",
+ .flags = SA_INTERRUPT,
+ .handler = pxa_timer_interrupt
+};
+
+static void __init pxa_timer_init(void)
+{
+ struct timespec tv;
+
+ set_rtc = pxa_set_rtc;
+
+ tv.tv_nsec = 0;
+ tv.tv_sec = pxa_get_rtc_time();
+ do_settimeofday(&tv);
+
+ OSMR0 = 0; /* set initial match at 0 */
+ OSSR = 0xf; /* clear status on all timers */
+ setup_irq(IRQ_OST0, &pxa_timer_irq);
+ OIER |= OIER_E0; /* enable match on timer 0 to cause interrupts */
+ OSCR = 0; /* initialize free-running timer, force first match */
+}
+
+#ifdef CONFIG_PM
+static unsigned long osmr[4], oier;
+
+static void pxa_timer_suspend(void)
+{
+ osmr[0] = OSMR0;
+ osmr[1] = OSMR1;
+ osmr[2] = OSMR2;
+ osmr[3] = OSMR3;
+ oier = OIER;
+}
+
+static void pxa_timer_resume(void)
+{
+ OSMR0 = osmr[0];
+ OSMR1 = osmr[1];
+ OSMR2 = osmr[2];
+ OSMR3 = osmr[3];
+ OIER = oier;
+
+ /*
+ * OSMR0 is the system timer: make sure OSCR is sufficiently behind
+ */
+ OSCR = OSMR0 - LATCH;
+}
+#else
+#define pxa_timer_suspend NULL
+#define pxa_timer_resume NULL
+#endif
+
+struct sys_timer pxa_timer = {
+ .init = pxa_timer_init,
+ .suspend = pxa_timer_suspend,
+ .resume = pxa_timer_resume,
+ .offset = pxa_gettimeoffset,
+};