diff options
Diffstat (limited to 'arch/arm/mach-pxa')
-rw-r--r-- | arch/arm/mach-pxa/Kconfig | 77 | ||||
-rw-r--r-- | arch/arm/mach-pxa/Makefile | 26 | ||||
-rw-r--r-- | arch/arm/mach-pxa/Makefile.boot | 2 | ||||
-rw-r--r-- | arch/arm/mach-pxa/corgi.c | 320 | ||||
-rw-r--r-- | arch/arm/mach-pxa/corgi_ssp.c | 248 | ||||
-rw-r--r-- | arch/arm/mach-pxa/dma.c | 133 | ||||
-rw-r--r-- | arch/arm/mach-pxa/generic.c | 237 | ||||
-rw-r--r-- | arch/arm/mach-pxa/generic.h | 24 | ||||
-rw-r--r-- | arch/arm/mach-pxa/idp.c | 190 | ||||
-rw-r--r-- | arch/arm/mach-pxa/irq.c | 313 | ||||
-rw-r--r-- | arch/arm/mach-pxa/leds-idp.c | 117 | ||||
-rw-r--r-- | arch/arm/mach-pxa/leds-lubbock.c | 126 | ||||
-rw-r--r-- | arch/arm/mach-pxa/leds-mainstone.c | 121 | ||||
-rw-r--r-- | arch/arm/mach-pxa/leds.c | 32 | ||||
-rw-r--r-- | arch/arm/mach-pxa/leds.h | 12 | ||||
-rw-r--r-- | arch/arm/mach-pxa/lubbock.c | 247 | ||||
-rw-r--r-- | arch/arm/mach-pxa/mainstone.c | 316 | ||||
-rw-r--r-- | arch/arm/mach-pxa/pm.c | 227 | ||||
-rw-r--r-- | arch/arm/mach-pxa/poodle.c | 189 | ||||
-rw-r--r-- | arch/arm/mach-pxa/pxa25x.c | 104 | ||||
-rw-r--r-- | arch/arm/mach-pxa/pxa27x.c | 163 | ||||
-rw-r--r-- | arch/arm/mach-pxa/sleep.S | 194 | ||||
-rw-r--r-- | arch/arm/mach-pxa/ssp.c | 363 | ||||
-rw-r--r-- | arch/arm/mach-pxa/time.c | 164 |
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 00000000000..405a55f2287 --- /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 00000000000..c4e6d252358 --- /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 00000000000..1ead67178ec --- /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 00000000000..f691cf77d39 --- /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 00000000000..8ccffba0018 --- /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 00000000000..458112b21e2 --- /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 00000000000..b1575b8dc1c --- /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, +}; |