diff options
Diffstat (limited to 'arch/arm/mach-pxa')
37 files changed, 3753 insertions, 1023 deletions
diff --git a/arch/arm/mach-pxa/Kconfig b/arch/arm/mach-pxa/Kconfig index 656d49661a2..0908bea0f60 100644 --- a/arch/arm/mach-pxa/Kconfig +++ b/arch/arm/mach-pxa/Kconfig @@ -51,6 +51,50 @@ config PXA_SHARPSL SL-C3000 (Spitz), SL-C3100 (Borzoi) or SL-C6000x (Tosa) handheld computer. +config ARCH_PXA_ESERIES + bool "PXA based Toshiba e-series PDAs" + select PXA25x + +config MACH_E330 + bool "Toshiba e330" + default y + depends on ARCH_PXA_ESERIES + help + Say Y here if you intend to run this kernel on a Toshiba + e330 family PDA. + +config MACH_E740 + bool "Toshiba e740" + default y + depends on ARCH_PXA_ESERIES + help + Say Y here if you intend to run this kernel on a Toshiba + e740 family PDA. + +config MACH_E750 + bool "Toshiba e750" + default y + depends on ARCH_PXA_ESERIES + help + Say Y here if you intend to run this kernel on a Toshiba + e750 family PDA. + +config MACH_E400 + bool "Toshiba e400" + default y + depends on ARCH_PXA_ESERIES + help + Say Y here if you intend to run this kernel on a Toshiba + e400 family PDA. + +config MACH_E800 + bool "Toshiba e800" + default y + depends on ARCH_PXA_ESERIES + help + Say Y here if you intend to run this kernel on a Toshiba + e800 family PDA. + config MACH_TRIZEPS4 bool "Keith und Koep Trizeps4 DIMM-Module" select PXA27x @@ -59,15 +103,44 @@ config MACH_EM_X270 bool "CompuLab EM-x270 platform" select PXA27x +config MACH_COLIBRI + bool "Toradex Colibri PX27x" + select PXA27x + config MACH_ZYLONITE bool "PXA3xx Development Platform" select PXA3xx +config MACH_LITTLETON + bool "PXA3xx Form Factor Platform (aka Littleton)" + select PXA3xx + select PXA_SSP + config MACH_ARMCORE bool "CompuLab CM-X270 modules" select PXA27x select IWMMXT +config MACH_MAGICIAN + bool "Enable HTC Magician Support" + depends on ARCH_PXA + select PXA27x + select IWMMXT + +config MACH_PCM027 + bool "Phytec phyCORE-PXA270 CPU module (PCM-027)" + select PXA27x + select IWMMXT + +endchoice + +choice + prompt "Used baseboard" + depends on MACH_PCM027 + +config MACH_PCM990_BASEBOARD + bool "PHYTEC PCM-990 development board" + endchoice if PXA_SHARPSL diff --git a/arch/arm/mach-pxa/Makefile b/arch/arm/mach-pxa/Makefile index 4263527e512..b5c916c0747 100644 --- a/arch/arm/mach-pxa/Makefile +++ b/arch/arm/mach-pxa/Makefile @@ -3,7 +3,7 @@ # # Common support (must be linked before board specific support) -obj-y += clock.o generic.o irq.o dma.o time.o +obj-y += clock.o devices.o generic.o irq.o dma.o time.o obj-$(CONFIG_PXA25x) += pxa25x.o obj-$(CONFIG_PXA27x) += pxa27x.o obj-$(CONFIG_PXA3xx) += pxa3xx.o mfp.o @@ -16,18 +16,24 @@ obj-$(CONFIG_MACH_LOGICPD_PXA270) += lpd270.o obj-$(CONFIG_MACH_MAINSTONE) += mainstone.o obj-$(CONFIG_ARCH_PXA_IDP) += idp.o obj-$(CONFIG_MACH_TRIZEPS4) += trizeps4.o +obj-$(CONFIG_MACH_COLIBRI) += colibri.o obj-$(CONFIG_PXA_SHARP_C7xx) += corgi.o corgi_ssp.o corgi_lcd.o sharpsl_pm.o corgi_pm.o obj-$(CONFIG_PXA_SHARP_Cxx00) += spitz.o corgi_ssp.o corgi_lcd.o sharpsl_pm.o spitz_pm.o obj-$(CONFIG_MACH_AKITA) += akita-ioexp.o obj-$(CONFIG_MACH_POODLE) += poodle.o corgi_ssp.o +obj-$(CONFIG_MACH_PCM027) += pcm027.o +obj-$(CONFIG_MACH_PCM990_BASEBOARD) += pcm990-baseboard.o obj-$(CONFIG_MACH_TOSA) += tosa.o obj-$(CONFIG_MACH_EM_X270) += em-x270.o +obj-$(CONFIG_MACH_MAGICIAN) += magician.o +obj-$(CONFIG_ARCH_PXA_ESERIES) += eseries.o ifeq ($(CONFIG_MACH_ZYLONITE),y) obj-y += zylonite.o obj-$(CONFIG_CPU_PXA300) += zylonite_pxa300.o obj-$(CONFIG_CPU_PXA320) += zylonite_pxa320.o endif +obj-$(CONFIG_MACH_LITTLETON) += littleton.o obj-$(CONFIG_MACH_ARMCORE) += cm-x270.o @@ -41,13 +47,10 @@ led-$(CONFIG_MACH_TRIZEPS4) += leds-trizeps4.o obj-$(CONFIG_LEDS) += $(led-y) # Misc features -obj-$(CONFIG_PM) += pm.o sleep.o +obj-$(CONFIG_PM) += pm.o sleep.o standby.o +obj-$(CONFIG_CPU_FREQ) += cpu-pxa.o obj-$(CONFIG_PXA_SSP) += ssp.o -ifeq ($(CONFIG_PXA27x),y) -obj-$(CONFIG_PM) += standby.o -endif - ifeq ($(CONFIG_PCI),y) obj-$(CONFIG_MACH_ARMCORE) += cm-x270-pci.o endif diff --git a/arch/arm/mach-pxa/cm-x270.c b/arch/arm/mach-pxa/cm-x270.c index a16349272f5..28cfd71c032 100644 --- a/arch/arm/mach-pxa/cm-x270.c +++ b/arch/arm/mach-pxa/cm-x270.c @@ -487,18 +487,15 @@ static int cmx270_mci_init(struct device *dev, /* card detect IRQ on GPIO 83 */ pxa_gpio_mode(IRQ_TO_GPIO(CMX270_MMC_IRQ)); - set_irq_type(CMX270_MMC_IRQ, IRQT_FALLING); err = request_irq(CMX270_MMC_IRQ, cmx270_detect_int, IRQF_DISABLED | IRQF_TRIGGER_FALLING, "MMC card detect", data); - if (err) { + if (err) printk(KERN_ERR "cmx270_mci_init: MMC/SD: can't" " request MMC card detect IRQ\n"); - return -1; - } - return 0; + return err; } static void cmx270_mci_setpower(struct device *dev, unsigned int vdd) diff --git a/arch/arm/mach-pxa/colibri.c b/arch/arm/mach-pxa/colibri.c new file mode 100644 index 00000000000..6db54e31c39 --- /dev/null +++ b/arch/arm/mach-pxa/colibri.c @@ -0,0 +1,134 @@ +/* + * linux/arch/arm/mach-pxa/colibri.c + * + * Support for Toradex PXA27x based Colibri module + * Daniel Mack <daniel@caiaq.de> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#include <linux/init.h> +#include <linux/kernel.h> +#include <linux/platform_device.h> +#include <linux/sysdev.h> +#include <linux/interrupt.h> +#include <linux/bitops.h> +#include <linux/ioport.h> +#include <linux/delay.h> +#include <linux/mtd/mtd.h> +#include <linux/mtd/partitions.h> +#include <linux/mtd/physmap.h> +#include <asm/mach-types.h> +#include <asm/hardware.h> +#include <asm/irq.h> +#include <asm/sizes.h> +#include <asm/mach/arch.h> +#include <asm/mach/map.h> +#include <asm/mach/irq.h> +#include <asm/mach/flash.h> +#include <asm/arch/pxa-regs.h> +#include <asm/arch/colibri.h> + +#include "generic.h" +#include "devices.h" + +/* + * Flash + */ +static struct mtd_partition colibri_partitions[] = { + { + .name = "Bootloader", + .offset = 0x00000000, + .size = 0x00040000, + .mask_flags = MTD_WRITEABLE /* force read-only */ + }, { + .name = "Kernel", + .offset = 0x00040000, + .size = 0x00400000, + .mask_flags = 0 + }, { + .name = "Rootfs", + .offset = 0x00440000, + .size = MTDPART_SIZ_FULL, + .mask_flags = 0 + } +}; + +static struct physmap_flash_data colibri_flash_data[] = { + { + .width = 4, /* bankwidth in bytes */ + .parts = colibri_partitions, + .nr_parts = ARRAY_SIZE(colibri_partitions) + } +}; + +static struct resource flash_resource = { + .start = PXA_CS0_PHYS, + .end = PXA_CS0_PHYS + SZ_32M - 1, + .flags = IORESOURCE_MEM, +}; + +static struct platform_device flash_device = { + .name = "physmap-flash", + .id = 0, + .dev = { + .platform_data = colibri_flash_data, + }, + .resource = &flash_resource, + .num_resources = 1, +}; + +/* + * DM9000 Ethernet + */ +static struct resource dm9000_resources[] = { + [0] = { + .start = COLIBRI_ETH_PHYS, + .end = COLIBRI_ETH_PHYS + 3, + .flags = IORESOURCE_MEM, + }, + [1] = { + .start = COLIBRI_ETH_PHYS + 4, + .end = COLIBRI_ETH_PHYS + 4 + 500, + .flags = IORESOURCE_MEM, + }, + [2] = { + .start = COLIBRI_ETH_IRQ, + .end = COLIBRI_ETH_IRQ, + .flags = IORESOURCE_IRQ, + }, +}; + +static struct platform_device dm9000_device = { + .name = "dm9000", + .id = -1, + .num_resources = ARRAY_SIZE(dm9000_resources), + .resource = dm9000_resources, +}; + +static struct platform_device *colibri_devices[] __initdata = { + &flash_device, + &dm9000_device, +}; + +static void __init colibri_init(void) +{ + /* DM9000 LAN */ + pxa_gpio_mode(GPIO78_nCS_2_MD); + pxa_gpio_mode(GPIO_DM9000 | GPIO_IN); + set_irq_type(COLIBRI_ETH_IRQ, IRQT_FALLING); + + platform_add_devices(colibri_devices, ARRAY_SIZE(colibri_devices)); +} + +MACHINE_START(COLIBRI, "Toradex Colibri PXA27x") + .phys_io = 0x40000000, + .io_pg_offst = (io_p2v(0x40000000) >> 18) & 0xfffc, + .boot_params = COLIBRI_SDRAM_BASE + 0x100, + .init_machine = colibri_init, + .map_io = pxa_map_io, + .init_irq = pxa27x_init_irq, + .timer = &pxa_timer, +MACHINE_END diff --git a/arch/arm/mach-pxa/corgi.c b/arch/arm/mach-pxa/corgi.c index 2363cc64fe0..9292576b83b 100644 --- a/arch/arm/mach-pxa/corgi.c +++ b/arch/arm/mach-pxa/corgi.c @@ -21,6 +21,7 @@ #include <linux/mmc/host.h> #include <linux/pm.h> #include <linux/backlight.h> +#include <video/w100fb.h> #include <asm/setup.h> #include <asm/memory.h> @@ -141,6 +142,136 @@ struct corgissp_machinfo corgi_ssp_machinfo = { /* + * LCD/Framebuffer + */ +static void w100_lcdtg_suspend(struct w100fb_par *par) +{ + corgi_lcdtg_suspend(); +} + +static void w100_lcdtg_init(struct w100fb_par *par) +{ + corgi_lcdtg_hw_init(par->xres); +} + + +static struct w100_tg_info corgi_lcdtg_info = { + .change = w100_lcdtg_init, + .suspend = w100_lcdtg_suspend, + .resume = w100_lcdtg_init, +}; + +static struct w100_mem_info corgi_fb_mem = { + .ext_cntl = 0x00040003, + .sdram_mode_reg = 0x00650021, + .ext_timing_cntl = 0x10002a4a, + .io_cntl = 0x7ff87012, + .size = 0x1fffff, +}; + +static struct w100_gen_regs corgi_fb_regs = { + .lcd_format = 0x00000003, + .lcdd_cntl1 = 0x01CC0000, + .lcdd_cntl2 = 0x0003FFFF, + .genlcd_cntl1 = 0x00FFFF0D, + .genlcd_cntl2 = 0x003F3003, + .genlcd_cntl3 = 0x000102aa, +}; + +static struct w100_gpio_regs corgi_fb_gpio = { + .init_data1 = 0x000000bf, + .init_data2 = 0x00000000, + .gpio_dir1 = 0x00000000, + .gpio_oe1 = 0x03c0feff, + .gpio_dir2 = 0x00000000, + .gpio_oe2 = 0x00000000, +}; + +static struct w100_mode corgi_fb_modes[] = { +{ + .xres = 480, + .yres = 640, + .left_margin = 0x56, + .right_margin = 0x55, + .upper_margin = 0x03, + .lower_margin = 0x00, + .crtc_ss = 0x82360056, + .crtc_ls = 0xA0280000, + .crtc_gs = 0x80280028, + .crtc_vpos_gs = 0x02830002, + .crtc_rev = 0x00400008, + .crtc_dclk = 0xA0000000, + .crtc_gclk = 0x8015010F, + .crtc_goe = 0x80100110, + .crtc_ps1_active = 0x41060010, + .pll_freq = 75, + .fast_pll_freq = 100, + .sysclk_src = CLK_SRC_PLL, + .sysclk_divider = 0, + .pixclk_src = CLK_SRC_PLL, + .pixclk_divider = 2, + .pixclk_divider_rotated = 6, +},{ + .xres = 240, + .yres = 320, + .left_margin = 0x27, + .right_margin = 0x2e, + .upper_margin = 0x01, + .lower_margin = 0x00, + .crtc_ss = 0x81170027, + .crtc_ls = 0xA0140000, + .crtc_gs = 0xC0140014, + .crtc_vpos_gs = 0x00010141, + .crtc_rev = 0x00400008, + .crtc_dclk = 0xA0000000, + .crtc_gclk = 0x8015010F, + .crtc_goe = 0x80100110, + .crtc_ps1_active = 0x41060010, + .pll_freq = 0, + .fast_pll_freq = 0, + .sysclk_src = CLK_SRC_XTAL, + .sysclk_divider = 0, + .pixclk_src = CLK_SRC_XTAL, + .pixclk_divider = 1, + .pixclk_divider_rotated = 1, +}, + +}; + +static struct w100fb_mach_info corgi_fb_info = { + .tg = &corgi_lcdtg_info, + .init_mode = INIT_MODE_ROTATED, + .mem = &corgi_fb_mem, + .regs = &corgi_fb_regs, + .modelist = &corgi_fb_modes[0], + .num_modes = 2, + .gpio = &corgi_fb_gpio, + .xtal_freq = 12500000, + .xtal_dbl = 0, +}; + +static struct resource corgi_fb_resources[] = { + [0] = { + .start = 0x08000000, + .end = 0x08ffffff, + .flags = IORESOURCE_MEM, + }, +}; + +static struct platform_device corgifb_device = { + .name = "w100fb", + .id = -1, + .num_resources = ARRAY_SIZE(corgi_fb_resources), + .resource = corgi_fb_resources, + .dev = { + .platform_data = &corgi_fb_info, + .parent = &corgissp_device.dev, + }, + +}; + + +/* * Corgi Backlight Device */ static void corgi_bl_kick_battery(void) @@ -154,6 +285,21 @@ static void corgi_bl_kick_battery(void) } } +static void corgi_bl_set_intensity(int intensity) +{ + if (intensity > 0x10) + intensity += 0x10; + + /* Bits 0-4 are accessed via the SSP interface */ + corgi_ssp_blduty_set(intensity & 0x1f); + + /* Bit 5 is via SCOOP */ + if (intensity & 0x0020) + set_scoop_gpio(&corgiscoop_device.dev, CORGI_SCP_BACKLIGHT_CONT); + else + reset_scoop_gpio(&corgiscoop_device.dev, CORGI_SCP_BACKLIGHT_CONT); +} + static struct generic_bl_info corgi_bl_machinfo = { .name = "corgi-bl", .max_intensity = 0x2f, @@ -190,9 +336,40 @@ static struct platform_device corgiled_device = { .id = -1, }; + /* * Corgi Touch Screen Device */ +static unsigned long (*get_hsync_invperiod)(struct device *dev); + +static void inline sharpsl_wait_sync(int gpio) +{ + while((GPLR(gpio) & GPIO_bit(gpio)) == 0); + while((GPLR(gpio) & GPIO_bit(gpio)) != 0); +} + +static unsigned long corgi_get_hsync_invperiod(void) +{ + if (!get_hsync_invperiod) + get_hsync_invperiod = symbol_get(w100fb_get_hsynclen); + if (!get_hsync_invperiod) + return 0; + + return get_hsync_invperiod(&corgifb_device.dev); +} + +static void corgi_put_hsync(void) +{ + if (get_hsync_invperiod) + symbol_put(w100fb_get_hsynclen); + get_hsync_invperiod = NULL; +} + +static void corgi_wait_hsync(void) +{ + sharpsl_wait_sync(CORGI_GPIO_HSYNC); +} + static struct resource corgits_resources[] = { [0] = { .start = CORGI_IRQ_GPIO_TP_INT, @@ -202,9 +379,9 @@ static struct resource corgits_resources[] = { }; static struct corgits_machinfo corgi_ts_machinfo = { - .get_hsync_len = corgi_get_hsync_len, - .put_hsync = corgi_put_hsync, - .wait_hsync = corgi_wait_hsync, + .get_hsync_invperiod = corgi_get_hsync_invperiod, + .put_hsync = corgi_put_hsync, + .wait_hsync = corgi_wait_hsync, }; static struct platform_device corgits_device = { @@ -242,12 +419,10 @@ static int corgi_mci_init(struct device *dev, irq_handler_t corgi_detect_int, vo err = request_irq(CORGI_IRQ_GPIO_nSD_DETECT, corgi_detect_int, IRQF_DISABLED | IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING, "MMC card detect", data); - if (err) { + if (err) printk(KERN_ERR "corgi_mci_init: MMC/SD: can't request MMC card detect IRQ\n"); - return -1; - } - return 0; + return err; } static void corgi_mci_setpower(struct device *dev, unsigned int vdd) diff --git a/arch/arm/mach-pxa/corgi_lcd.c b/arch/arm/mach-pxa/corgi_lcd.c index 365b9435f74..9328df37afd 100644 --- a/arch/arm/mach-pxa/corgi_lcd.c +++ b/arch/arm/mach-pxa/corgi_lcd.c @@ -173,7 +173,7 @@ static void lcdtg_set_phadadj(int mode) static int lcd_inited; -static void lcdtg_hw_init(int mode) +void corgi_lcdtg_hw_init(int mode) { if (!lcd_inited) { int comadj; @@ -254,7 +254,7 @@ static void lcdtg_hw_init(int mode) } } -static void lcdtg_suspend(void) +void corgi_lcdtg_suspend(void) { /* 60Hz x 2 frame = 16.7msec x 2 = 33.4 msec */ mdelay(34); @@ -288,298 +288,3 @@ static void lcdtg_suspend(void) lcd_inited = 0; } - -/* - * Corgi w100 Frame Buffer Device - */ -#ifdef CONFIG_PXA_SHARP_C7xx - -#include <video/w100fb.h> - -static void w100_lcdtg_suspend(struct w100fb_par *par) -{ - lcdtg_suspend(); -} - -static void w100_lcdtg_init(struct w100fb_par *par) -{ - lcdtg_hw_init(par->xres); -} - - -static struct w100_tg_info corgi_lcdtg_info = { - .change = w100_lcdtg_init, - .suspend = w100_lcdtg_suspend, - .resume = w100_lcdtg_init, -}; - -static struct w100_mem_info corgi_fb_mem = { - .ext_cntl = 0x00040003, - .sdram_mode_reg = 0x00650021, - .ext_timing_cntl = 0x10002a4a, - .io_cntl = 0x7ff87012, - .size = 0x1fffff, -}; - -static struct w100_gen_regs corgi_fb_regs = { - .lcd_format = 0x00000003, - .lcdd_cntl1 = 0x01CC0000, - .lcdd_cntl2 = 0x0003FFFF, - .genlcd_cntl1 = 0x00FFFF0D, - .genlcd_cntl2 = 0x003F3003, - .genlcd_cntl3 = 0x000102aa, -}; - -static struct w100_gpio_regs corgi_fb_gpio = { - .init_data1 = 0x000000bf, - .init_data2 = 0x00000000, - .gpio_dir1 = 0x00000000, - .gpio_oe1 = 0x03c0feff, - .gpio_dir2 = 0x00000000, - .gpio_oe2 = 0x00000000, -}; - -static struct w100_mode corgi_fb_modes[] = { -{ - .xres = 480, - .yres = 640, - .left_margin = 0x56, - .right_margin = 0x55, - .upper_margin = 0x03, - .lower_margin = 0x00, - .crtc_ss = 0x82360056, - .crtc_ls = 0xA0280000, - .crtc_gs = 0x80280028, - .crtc_vpos_gs = 0x02830002, - .crtc_rev = 0x00400008, - .crtc_dclk = 0xA0000000, - .crtc_gclk = 0x8015010F, - .crtc_goe = 0x80100110, - .crtc_ps1_active = 0x41060010, - .pll_freq = 75, - .fast_pll_freq = 100, - .sysclk_src = CLK_SRC_PLL, - .sysclk_divider = 0, - .pixclk_src = CLK_SRC_PLL, - .pixclk_divider = 2, - .pixclk_divider_rotated = 6, -},{ - .xres = 240, - .yres = 320, - .left_margin = 0x27, - .right_margin = 0x2e, - .upper_margin = 0x01, - .lower_margin = 0x00, - .crtc_ss = 0x81170027, - .crtc_ls = 0xA0140000, - .crtc_gs = 0xC0140014, - .crtc_vpos_gs = 0x00010141, - .crtc_rev = 0x00400008, - .crtc_dclk = 0xA0000000, - .crtc_gclk = 0x8015010F, - .crtc_goe = 0x80100110, - .crtc_ps1_active = 0x41060010, - .pll_freq = 0, - .fast_pll_freq = 0, - .sysclk_src = CLK_SRC_XTAL, - .sysclk_divider = 0, - .pixclk_src = CLK_SRC_XTAL, - .pixclk_divider = 1, - .pixclk_divider_rotated = 1, -}, - -}; - -static struct w100fb_mach_info corgi_fb_info = { - .tg = &corgi_lcdtg_info, - .init_mode = INIT_MODE_ROTATED, - .mem = &corgi_fb_mem, - .regs = &corgi_fb_regs, - .modelist = &corgi_fb_modes[0], - .num_modes = 2, - .gpio = &corgi_fb_gpio, - .xtal_freq = 12500000, - .xtal_dbl = 0, -}; - -static struct resource corgi_fb_resources[] = { - [0] = { - .start = 0x08000000, - .end = 0x08ffffff, - .flags = IORESOURCE_MEM, - }, -}; - -struct platform_device corgifb_device = { - .name = "w100fb", - .id = -1, - .num_resources = ARRAY_SIZE(corgi_fb_resources), - .resource = corgi_fb_resources, - .dev = { - .platform_data = &corgi_fb_info, - .parent = &corgissp_device.dev, - }, - -}; -#endif - - -/* - * Spitz PXA Frame Buffer Device - */ -#ifdef CONFIG_PXA_SHARP_Cxx00 - -#include <asm/arch/pxafb.h> - -void spitz_lcd_power(int on, struct fb_var_screeninfo *var) -{ - if (on) - lcdtg_hw_init(var->xres); - else - lcdtg_suspend(); -} - -#endif - - -/* - * Corgi/Spitz Touchscreen to LCD interface - */ -static unsigned long (*get_hsync_time)(struct device *dev); - -static void inline sharpsl_wait_sync(int gpio) -{ - while((GPLR(gpio) & GPIO_bit(gpio)) == 0); - while((GPLR(gpio) & GPIO_bit(gpio)) != 0); -} - -#ifdef CONFIG_PXA_SHARP_C7xx -unsigned long corgi_get_hsync_len(void) -{ - if (!get_hsync_time) - get_hsync_time = symbol_get(w100fb_get_hsynclen); - if (!get_hsync_time) - return 0; - - return get_hsync_time(&corgifb_device.dev); -} - -void corgi_put_hsync(void) -{ - if (get_hsync_time) - symbol_put(w100fb_get_hsynclen); - get_hsync_time = NULL; -} - -void corgi_wait_hsync(void) -{ - sharpsl_wait_sync(CORGI_GPIO_HSYNC); -} -#endif - -#ifdef CONFIG_PXA_SHARP_Cxx00 -static struct device *spitz_pxafb_dev; - -static int is_pxafb_device(struct device * dev, void * data) -{ - struct platform_device *pdev = container_of(dev, struct platform_device, dev); - - return (strncmp(pdev->name, "pxa2xx-fb", 9) == 0); -} - -unsigned long spitz_get_hsync_len(void) -{ -#ifdef CONFIG_FB_PXA - if (!spitz_pxafb_dev) { - spitz_pxafb_dev = bus_find_device(&platform_bus_type, NULL, NULL, is_pxafb_device); - if (!spitz_pxafb_dev) - return 0; - } - if (!get_hsync_time) - get_hsync_time = symbol_get(pxafb_get_hsync_time); - if (!get_hsync_time) -#endif - return 0; - - return pxafb_get_hsync_time(spitz_pxafb_dev); -} - -void spitz_put_hsync(void) -{ - put_device(spitz_pxafb_dev); - if (get_hsync_time) - symbol_put(pxafb_get_hsync_time); - spitz_pxafb_dev = NULL; - get_hsync_time = NULL; -} - -void spitz_wait_hsync(void) -{ - sharpsl_wait_sync(SPITZ_GPIO_HSYNC); -} -#endif - -/* - * Corgi/Spitz Backlight Power - */ -#ifdef CONFIG_PXA_SHARP_C7xx -void corgi_bl_set_intensity(int intensity) -{ - if (intensity > 0x10) - intensity += 0x10; - - /* Bits 0-4 are accessed via the SSP interface */ - corgi_ssp_blduty_set(intensity & 0x1f); - - /* Bit 5 is via SCOOP */ - if (intensity & 0x0020) - set_scoop_gpio(&corgiscoop_device.dev, CORGI_SCP_BACKLIGHT_CONT); - else - reset_scoop_gpio(&corgiscoop_device.dev, CORGI_SCP_BACKLIGHT_CONT); -} -#endif - - -#if defined(CONFIG_MACH_SPITZ) || defined(CONFIG_MACH_BORZOI) -void spitz_bl_set_intensity(int intensity) -{ - if (intensity > 0x10) - intensity += 0x10; - - /* Bits 0-4 are accessed via the SSP interface */ - corgi_ssp_blduty_set(intensity & 0x1f); - - /* Bit 5 is via SCOOP */ - if (intensity & 0x0020) - reset_scoop_gpio(&spitzscoop2_device.dev, SPITZ_SCP2_BACKLIGHT_CONT); - else - set_scoop_gpio(&spitzscoop2_device.dev, SPITZ_SCP2_BACKLIGHT_CONT); - - if (intensity) - set_scoop_gpio(&spitzscoop2_device.dev, SPITZ_SCP2_BACKLIGHT_ON); - else - reset_scoop_gpio(&spitzscoop2_device.dev, SPITZ_SCP2_BACKLIGHT_ON); -} -#endif - -#ifdef CONFIG_MACH_AKITA -void akita_bl_set_intensity(int intensity) -{ - if (intensity > 0x10) - intensity += 0x10; - - /* Bits 0-4 are accessed via the SSP interface */ - corgi_ssp_blduty_set(intensity & 0x1f); - - /* Bit 5 is via IO-Expander */ - if (intensity & 0x0020) - akita_reset_ioexp(&akitaioexp_device.dev, AKITA_IOEXP_BACKLIGHT_CONT); - else - akita_set_ioexp(&akitaioexp_device.dev, AKITA_IOEXP_BACKLIGHT_CONT); - - if (intensity) - akita_set_ioexp(&akitaioexp_device.dev, AKITA_IOEXP_BACKLIGHT_ON); - else - akita_reset_ioexp(&akitaioexp_device.dev, AKITA_IOEXP_BACKLIGHT_ON); -} -#endif diff --git a/arch/arm/mach-pxa/corgi_ssp.c b/arch/arm/mach-pxa/corgi_ssp.c index 40dea3d5142..efba65edcd5 100644 --- a/arch/arm/mach-pxa/corgi_ssp.c +++ b/arch/arm/mach-pxa/corgi_ssp.c @@ -21,6 +21,7 @@ #include <asm/arch/ssp.h> #include <asm/arch/pxa-regs.h> +#include <asm/arch/regs-ssp.h> #include "sharpsl.h" static DEFINE_SPINLOCK(corgi_ssp_lock); diff --git a/arch/arm/mach-pxa/cpu-pxa.c b/arch/arm/mach-pxa/cpu-pxa.c new file mode 100644 index 00000000000..cbc583beedc --- /dev/null +++ b/arch/arm/mach-pxa/cpu-pxa.c @@ -0,0 +1,294 @@ +/* + * linux/arch/arm/mach-pxa/cpu-pxa.c + * + * Copyright (C) 2002,2003 Intrinsyc Software + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * History: + * 31-Jul-2002 : Initial version [FB] + * 29-Jan-2003 : added PXA255 support [FB] + * 20-Apr-2003 : ported to v2.5 (Dustin McIntire, Sensoria Corp.) + * + * Note: + * This driver may change the memory bus clock rate, but will not do any + * platform specific access timing changes... for example if you have flash + * memory connected to CS0, you will need to register a platform specific + * notifier which will adjust the memory access strobes to maintain a + * minimum strobe width. + * + */ + +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/sched.h> +#include <linux/init.h> +#include <linux/cpufreq.h> + +#include <asm/hardware.h> +#include <asm/arch/pxa-regs.h> +#include <asm/arch/pxa2xx-regs.h> + +#ifdef DEBUG +static unsigned int freq_debug; +MODULE_PARM(freq_debug, "i"); +MODULE_PARM_DESC(freq_debug, "Set the debug messages to on=1/off=0"); +#else +#define freq_debug 0 +#endif + +typedef struct { + unsigned int khz; + unsigned int membus; + unsigned int cccr; + unsigned int div2; +} pxa_freqs_t; + +/* Define the refresh period in mSec for the SDRAM and the number of rows */ +#define SDRAM_TREF 64 /* standard 64ms SDRAM */ +#define SDRAM_ROWS 4096 /* 64MB=8192 32MB=4096 */ +#define MDREFR_DRI(x) (((x) * SDRAM_TREF) / (SDRAM_ROWS * 32)) + +#define CCLKCFG_TURBO 0x1 +#define CCLKCFG_FCS 0x2 +#define PXA25x_MIN_FREQ 99500 +#define PXA25x_MAX_FREQ 398100 +#define MDREFR_DB2_MASK (MDREFR_K2DB2 | MDREFR_K1DB2) +#define MDREFR_DRI_MASK 0xFFF + + +/* Use the run mode frequencies for the CPUFREQ_POLICY_PERFORMANCE policy */ +static pxa_freqs_t pxa255_run_freqs[] = +{ + /* CPU MEMBUS CCCR DIV2*/ + { 99500, 99500, 0x121, 1}, /* run= 99, turbo= 99, PXbus=50, SDRAM=50 */ + {132700, 132700, 0x123, 1}, /* run=133, turbo=133, PXbus=66, SDRAM=66 */ + {199100, 99500, 0x141, 0}, /* run=199, turbo=199, PXbus=99, SDRAM=99 */ + {265400, 132700, 0x143, 1}, /* run=265, turbo=265, PXbus=133, SDRAM=66 */ + {331800, 165900, 0x145, 1}, /* run=331, turbo=331, PXbus=166, SDRAM=83 */ + {398100, 99500, 0x161, 0}, /* run=398, turbo=398, PXbus=196, SDRAM=99 */ + {0,} +}; +#define NUM_RUN_FREQS ARRAY_SIZE(pxa255_run_freqs) + +static struct cpufreq_frequency_table pxa255_run_freq_table[NUM_RUN_FREQS+1]; + +/* Use the turbo mode frequencies for the CPUFREQ_POLICY_POWERSAVE policy */ +static pxa_freqs_t pxa255_turbo_freqs[] = +{ + /* CPU MEMBUS CCCR DIV2*/ + { 99500, 99500, 0x121, 1}, /* run=99, turbo= 99, PXbus=50, SDRAM=50 */ + {199100, 99500, 0x221, 0}, /* run=99, turbo=199, PXbus=50, SDRAM=99 */ + {298500, 99500, 0x321, 0}, /* run=99, turbo=287, PXbus=50, SDRAM=99 */ + {298600, 99500, 0x1c1, 0}, /* run=199, turbo=287, PXbus=99, SDRAM=99 */ + {398100, 99500, 0x241, 0}, /* run=199, turbo=398, PXbus=99, SDRAM=99 */ + {0,} +}; +#define NUM_TURBO_FREQS ARRAY_SIZE(pxa255_turbo_freqs) + +static struct cpufreq_frequency_table pxa255_turbo_freq_table[NUM_TURBO_FREQS+1]; + +extern unsigned get_clk_frequency_khz(int info); + +/* find a valid frequency point */ +static int pxa_verify_policy(struct cpufreq_policy *policy) +{ + struct cpufreq_frequency_table *pxa_freqs_table; + int ret; + + if (policy->policy == CPUFREQ_POLICY_PERFORMANCE) { + pxa_freqs_table = pxa255_run_freq_table; + } else if (policy->policy == CPUFREQ_POLICY_POWERSAVE) { + pxa_freqs_table = pxa255_turbo_freq_table; + } else { + printk("CPU PXA: Unknown policy found. " + "Using CPUFREQ_POLICY_PERFORMANCE\n"); + pxa_freqs_table = pxa255_run_freq_table; + } + + ret = cpufreq_frequency_table_verify(policy, pxa_freqs_table); + + if (freq_debug) + pr_debug("Verified CPU policy: %dKhz min to %dKhz max\n", + policy->min, policy->max); + + return ret; +} + +static int pxa_set_target(struct cpufreq_policy *policy, + unsigned int target_freq, + unsigned int relation) +{ + struct cpufreq_frequency_table *pxa_freqs_table; + pxa_freqs_t *pxa_freq_settings; + struct cpufreq_freqs freqs; + int idx; + unsigned long flags; + unsigned int unused, preset_mdrefr, postset_mdrefr; + void *ramstart = phys_to_virt(0xa0000000); + + /* Get the current policy */ + if (policy->policy == CPUFREQ_POLICY_PERFORMANCE) { + pxa_freq_settings = pxa255_run_freqs; + pxa_freqs_table = pxa255_run_freq_table; + } else if (policy->policy == CPUFREQ_POLICY_POWERSAVE) { + pxa_freq_settings = pxa255_turbo_freqs; + pxa_freqs_table = pxa255_turbo_freq_table; + } else { + printk("CPU PXA: Unknown policy found. " + "Using CPUFREQ_POLICY_PERFORMANCE\n"); + pxa_freq_settings = pxa255_run_freqs; + pxa_freqs_table = pxa255_run_freq_table; + } + + /* Lookup the next frequency */ + if (cpufreq_frequency_table_target(policy, pxa_freqs_table, + target_freq, relation, &idx)) { + return -EINVAL; + } + + freqs.old = policy->cur; + freqs.new = pxa_freq_settings[idx].khz; + freqs.cpu = policy->cpu; + + if (freq_debug) + pr_debug(KERN_INFO "Changing CPU frequency to %d Mhz, (SDRAM %d Mhz)\n", + freqs.new / 1000, (pxa_freq_settings[idx].div2) ? + (pxa_freq_settings[idx].membus / 2000) : + (pxa_freq_settings[idx].membus / 1000)); + + /* + * Tell everyone what we're about to do... + * you should add a notify client with any platform specific + * Vcc changing capability + */ + cpufreq_notify_transition(&freqs, CPUFREQ_PRECHANGE); + + /* Calculate the next MDREFR. If we're slowing down the SDRAM clock + * we need to preset the smaller DRI before the change. If we're speeding + * up we need to set the larger DRI value after the change. + */ + preset_mdrefr = postset_mdrefr = MDREFR; + if ((MDREFR & MDREFR_DRI_MASK) > MDREFR_DRI(pxa_freq_settings[idx].membus)) { + preset_mdrefr = (preset_mdrefr & ~MDREFR_DRI_MASK) | + MDREFR_DRI(pxa_freq_settings[idx].membus); + } + postset_mdrefr = (postset_mdrefr & ~MDREFR_DRI_MASK) | + MDREFR_DRI(pxa_freq_settings[idx].membus); + + /* If we're dividing the memory clock by two for the SDRAM clock, this + * must be set prior to the change. Clearing the divide must be done + * after the change. + */ + if (pxa_freq_settings[idx].div2) { + preset_mdrefr |= MDREFR_DB2_MASK; + postset_mdrefr |= MDREFR_DB2_MASK; + } else { + postset_mdrefr &= ~MDREFR_DB2_MASK; + } + + local_irq_save(flags); + + /* Set new the CCCR */ + CCCR = pxa_freq_settings[idx].cccr; + + asm volatile(" \n\ + ldr r4, [%1] /* load MDREFR */ \n\ + b 2f \n\ + .align 5 \n\ +1: \n\ + str %4, [%1] /* preset the MDREFR */ \n\ + mcr p14, 0, %2, c6, c0, 0 /* set CCLKCFG[FCS] */ \n\ + str %5, [%1] /* postset the MDREFR */ \n\ + \n\ + b 3f \n\ +2: b 1b \n\ +3: nop \n\ + " + : "=&r" (unused) + : "r" (&MDREFR), "r" (CCLKCFG_TURBO|CCLKCFG_FCS), "r" (ramstart), + "r" (preset_mdrefr), "r" (postset_mdrefr) + : "r4", "r5"); + local_irq_restore(flags); + + /* + * Tell everyone what we've just done... + * you should add a notify client with any platform specific + * SDRAM refresh timer adjustments + */ + cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE); + + return 0; +} + +static int pxa_cpufreq_init(struct cpufreq_policy *policy) +{ + int i; + + /* set default policy and cpuinfo */ + policy->governor = CPUFREQ_DEFAULT_GOVERNOR; + policy->policy = CPUFREQ_POLICY_PERFORMANCE; + policy->cpuinfo.max_freq = PXA25x_MAX_FREQ; + policy->cpuinfo.min_freq = PXA25x_MIN_FREQ; + policy->cpuinfo.transition_latency = 1000; /* FIXME: 1 ms, assumed */ + policy->cur = get_clk_frequency_khz(0); /* current freq */ + policy->min = policy->max = policy->cur; + + /* Generate the run cpufreq_frequency_table struct */ + for (i = 0; i < NUM_RUN_FREQS; i++) { + pxa255_run_freq_table[i].frequency = pxa255_run_freqs[i].khz; + pxa255_run_freq_table[i].index = i; + } + + pxa255_run_freq_table[i].frequency = CPUFREQ_TABLE_END; + /* Generate the turbo cpufreq_frequency_table struct */ + for (i = 0; i < NUM_TURBO_FREQS; i++) { + pxa255_turbo_freq_table[i].frequency = pxa255_turbo_freqs[i].khz; + pxa255_turbo_freq_table[i].index = i; + } + pxa255_turbo_freq_table[i].frequency = CPUFREQ_TABLE_END; + + printk(KERN_INFO "PXA CPU frequency change support initialized\n"); + + return 0; +} + +static struct cpufreq_driver pxa_cpufreq_driver = { + .verify = pxa_verify_policy, + .target = pxa_set_target, + .init = pxa_cpufreq_init, + .name = "PXA25x", +}; + +static int __init pxa_cpu_init(void) +{ + int ret = -ENODEV; + if (cpu_is_pxa25x()) + ret = cpufreq_register_driver(&pxa_cpufreq_driver); + return ret; +} + +static void __exit pxa_cpu_exit(void) +{ + if (cpu_is_pxa25x()) + cpufreq_unregister_driver(&pxa_cpufreq_driver); +} + + +MODULE_AUTHOR ("Intrinsyc Software Inc."); +MODULE_DESCRIPTION ("CPU frequency changing driver for the PXA architecture"); +MODULE_LICENSE("GPL"); +module_init(pxa_cpu_init); +module_exit(pxa_cpu_exit); diff --git a/arch/arm/mach-pxa/devices.c b/arch/arm/mach-pxa/devices.c new file mode 100644 index 00000000000..50ff453ad37 --- /dev/null +++ b/arch/arm/mach-pxa/devices.c @@ -0,0 +1,662 @@ +#include <linux/module.h> +#include <linux/kernel.h> +#include <linux/init.h> +#include <linux/platform_device.h> +#include <linux/dma-mapping.h> + +#include <asm/arch/gpio.h> +#include <asm/arch/udc.h> +#include <asm/arch/pxafb.h> +#include <asm/arch/mmc.h> +#include <asm/arch/irda.h> +#include <asm/arch/i2c.h> + +#include "devices.h" + +void __init pxa_register_device(struct platform_device *dev, void *data) +{ + int ret; + + dev->dev.platform_data = data; + + ret = platform_device_register(dev); + if (ret) + dev_err(&dev->dev, "unable to register device: %d\n", ret); +} + +static struct resource pxamci_resources[] = { + [0] = { + .start = 0x41100000, + .end = 0x41100fff, + .flags = IORESOURCE_MEM, + }, + [1] = { + .start = IRQ_MMC, + .end = IRQ_MMC, + .flags = IORESOURCE_IRQ, + }, + [2] = { + .start = 21, + .end = 21, + .flags = IORESOURCE_DMA, + }, + [3] = { + .start = 22, + .end = 22, + .flags = IORESOURCE_DMA, + }, +}; + +static u64 pxamci_dmamask = 0xffffffffUL; + +struct platform_device pxa_device_mci = { + .name = "pxa2xx-mci", + .id = 0, + .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) +{ + pxa_register_device(&pxa_device_mci, 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; + +struct platform_device pxa_device_udc = { + .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 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; + +struct platform_device pxa_device_fb = { + .name = "pxa2xx-fb", + .id = -1, + .dev = { + .dma_mask = &fb_dma_mask, + .coherent_dma_mask = 0xffffffff, + }, + .num_resources = ARRAY_SIZE(pxafb_resources), + .resource = pxafb_resources, +}; + +void __init set_pxa_fb_info(struct pxafb_mach_info *info) +{ + pxa_register_device(&pxa_device_fb, info); +} + +void __init set_pxa_fb_parent(struct device *parent_dev) +{ + pxa_device_fb.dev.parent = parent_dev; +} + +static struct resource pxa_resource_ffuart[] = { + { + .start = __PREG(FFUART), + .end = __PREG(FFUART) + 35, + .flags = IORESOURCE_MEM, + }, { + .start = IRQ_FFUART, + .end = IRQ_FFUART, + .flags = IORESOURCE_IRQ, + } +}; + +struct platform_device pxa_device_ffuart= { + .name = "pxa2xx-uart", + .id = 0, + .resource = pxa_resource_ffuart, + .num_resources = ARRAY_SIZE(pxa_resource_ffuart), +}; + +static struct resource pxa_resource_btuart[] = { + { + .start = __PREG(BTUART), + .end = __PREG(BTUART) + 35, + .flags = IORESOURCE_MEM, + }, { + .start = IRQ_BTUART, + .end = IRQ_BTUART, + .flags = IORESOURCE_IRQ, + } +}; + +struct platform_device pxa_device_btuart = { + .name = "pxa2xx-uart", + .id = 1, + .resource = pxa_resource_btuart, + .num_resources = ARRAY_SIZE(pxa_resource_btuart), +}; + +static struct resource pxa_resource_stuart[] = { + { + .start = __PREG(STUART), + .end = __PREG(STUART) + 35, + .flags = IORESOURCE_MEM, + }, { + .start = IRQ_STUART, + .end = IRQ_STUART, + .flags = IORESOURCE_IRQ, + } +}; + +struct platform_device pxa_device_stuart = { + .name = "pxa2xx-uart", + .id = 2, + .resource = pxa_resource_stuart, + .num_resources = ARRAY_SIZE(pxa_resource_stuart), +}; + +static struct resource pxa_resource_hwuart[] = { + { + .start = __PREG(HWUART), + .end = __PREG(HWUART) + 47, + .flags = IORESOURCE_MEM, + }, { + .start = IRQ_HWUART, + .end = IRQ_HWUART, + .flags = IORESOURCE_IRQ, + } +}; + +struct platform_device pxa_device_hwuart = { + .name = "pxa2xx-uart", + .id = 3, + .resource = pxa_resource_hwuart, + .num_resources = ARRAY_SIZE(pxa_resource_hwuart), +}; + +static struct resource pxai2c_resources[] = { + { + .start = 0x40301680, + .end = 0x403016a3, + .flags = IORESOURCE_MEM, + }, { + .start = IRQ_I2C, + .end = IRQ_I2C, + .flags = IORESOURCE_IRQ, + }, +}; + +struct platform_device pxa_device_i2c = { + .name = "pxa2xx-i2c", + .id = 0, + .resource = pxai2c_resources, + .num_resources = ARRAY_SIZE(pxai2c_resources), +}; + +void __init pxa_set_i2c_info(struct i2c_pxa_platform_data *info) +{ + pxa_register_device(&pxa_device_i2c, info); +} + +static struct resource pxai2s_resources[] = { + { + .start = 0x40400000, + .end = 0x40400083, + .flags = IORESOURCE_MEM, + }, { + .start = IRQ_I2S, + .end = IRQ_I2S, + .flags = IORESOURCE_IRQ, + }, +}; + +struct platform_device pxa_device_i2s = { + .name = "pxa2xx-i2s", + .id = -1, + .resource = pxai2s_resources, + .num_resources = ARRAY_SIZE(pxai2s_resources), +}; + +static u64 pxaficp_dmamask = ~(u32)0; + +struct platform_device pxa_device_ficp = { + .name = "pxa2xx-ir", + .id = -1, + .dev = { + .dma_mask = &pxaficp_dmamask, + .coherent_dma_mask = 0xffffffff, + }, +}; + +void __init pxa_set_ficp_info(struct pxaficp_platform_data *info) +{ + pxa_register_device(&pxa_device_ficp, info); +} + +struct platform_device pxa_device_rtc = { + .name = "sa1100-rtc", + .id = -1, +}; + +#ifdef CONFIG_PXA25x + +static u64 pxa25x_ssp_dma_mask = DMA_BIT_MASK(32); + +static struct resource pxa25x_resource_ssp[] = { + [0] = { + .start = 0x41000000, + .end = 0x4100001f, + .flags = IORESOURCE_MEM, + }, + [1] = { + .start = IRQ_SSP, + .end = IRQ_SSP, + .flags = IORESOURCE_IRQ, + }, + [2] = { + /* DRCMR for RX */ + .start = 13, + .end = 13, + .flags = IORESOURCE_DMA, + }, + [3] = { + /* DRCMR for TX */ + .start = 14, + .end = 14, + .flags = IORESOURCE_DMA, + }, +}; + +struct platform_device pxa25x_device_ssp = { + .name = "pxa25x-ssp", + .id = 0, + .dev = { + .dma_mask = &pxa25x_ssp_dma_mask, + .coherent_dma_mask = DMA_BIT_MASK(32), + }, + .resource = pxa25x_resource_ssp, + .num_resources = ARRAY_SIZE(pxa25x_resource_ssp), +}; + +static u64 pxa25x_nssp_dma_mask = DMA_BIT_MASK(32); + +static struct resource pxa25x_resource_nssp[] = { + [0] = { + .start = 0x41400000, + .end = 0x4140002f, + .flags = IORESOURCE_MEM, + }, + [1] = { + .start = IRQ_NSSP, + .end = IRQ_NSSP, + .flags = IORESOURCE_IRQ, + }, + [2] = { + /* DRCMR for RX */ + .start = 15, + .end = 15, + .flags = IORESOURCE_DMA, + }, + [3] = { + /* DRCMR for TX */ + .start = 16, + .end = 16, + .flags = IORESOURCE_DMA, + }, +}; + +struct platform_device pxa25x_device_nssp = { + .name = "pxa25x-nssp", + .id = 1, + .dev = { + .dma_mask = &pxa25x_nssp_dma_mask, + .coherent_dma_mask = DMA_BIT_MASK(32), + }, + .resource = pxa25x_resource_nssp, + .num_resources = ARRAY_SIZE(pxa25x_resource_nssp), +}; + +static u64 pxa25x_assp_dma_mask = DMA_BIT_MASK(32); + +static struct resource pxa25x_resource_assp[] = { + [0] = { + .start = 0x41500000, + .end = 0x4150002f, + .flags = IORESOURCE_MEM, + }, + [1] = { + .start = IRQ_ASSP, + .end = IRQ_ASSP, + .flags = IORESOURCE_IRQ, + }, + [2] = { + /* DRCMR for RX */ + .start = 23, + .end = 23, + .flags = IORESOURCE_DMA, + }, + [3] = { + /* DRCMR for TX */ + .start = 24, + .end = 24, + .flags = IORESOURCE_DMA, + }, +}; + +struct platform_device pxa25x_device_assp = { + /* ASSP is basically equivalent to NSSP */ + .name = "pxa25x-nssp", + .id = 2, + .dev = { + .dma_mask = &pxa25x_assp_dma_mask, + .coherent_dma_mask = DMA_BIT_MASK(32), + }, + .resource = pxa25x_resource_assp, + .num_resources = ARRAY_SIZE(pxa25x_resource_assp), +}; +#endif /* CONFIG_PXA25x */ + +#if defined(CONFIG_PXA27x) || defined(CONFIG_PXA3xx) + +static u64 pxa27x_ohci_dma_mask = DMA_BIT_MASK(32); + +static struct resource pxa27x_resource_ohci[] = { + [0] = { + .start = 0x4C000000, + .end = 0x4C00ff6f, + .flags = IORESOURCE_MEM, + }, + [1] = { + .start = IRQ_USBH1, + .end = IRQ_USBH1, + .flags = IORESOURCE_IRQ, + }, +}; + +struct platform_device pxa27x_device_ohci = { + .name = "pxa27x-ohci", + .id = -1, + .dev = { + .dma_mask = &pxa27x_ohci_dma_mask, + .coherent_dma_mask = DMA_BIT_MASK(32), + }, + .num_resources = ARRAY_SIZE(pxa27x_resource_ohci), + .resource = pxa27x_resource_ohci, +}; + +void __init pxa_set_ohci_info(struct pxaohci_platform_data *info) +{ + pxa_register_device(&pxa27x_device_ohci, info); +} + +static u64 pxa27x_ssp1_dma_mask = DMA_BIT_MASK(32); + +static struct resource pxa27x_resource_ssp1[] = { + [0] = { + .start = 0x41000000, + .end = 0x4100003f, + .flags = IORESOURCE_MEM, + }, + [1] = { + .start = IRQ_SSP, + .end = IRQ_SSP, + .flags = IORESOURCE_IRQ, + }, + [2] = { + /* DRCMR for RX */ + .start = 13, + .end = 13, + .flags = IORESOURCE_DMA, + }, + [3] = { + /* DRCMR for TX */ + .start = 14, + .end = 14, + .flags = IORESOURCE_DMA, + }, +}; + +struct platform_device pxa27x_device_ssp1 = { + .name = "pxa27x-ssp", + .id = 0, + .dev = { + .dma_mask = &pxa27x_ssp1_dma_mask, + .coherent_dma_mask = DMA_BIT_MASK(32), + }, + .resource = pxa27x_resource_ssp1, + .num_resources = ARRAY_SIZE(pxa27x_resource_ssp1), +}; + +static u64 pxa27x_ssp2_dma_mask = DMA_BIT_MASK(32); + +static struct resource pxa27x_resource_ssp2[] = { + [0] = { + .start = 0x41700000, + .end = 0x4170003f, + .flags = IORESOURCE_MEM, + }, + [1] = { + .start = IRQ_SSP2, + .end = IRQ_SSP2, + .flags = IORESOURCE_IRQ, + }, + [2] = { + /* DRCMR for RX */ + .start = 15, + .end = 15, + .flags = IORESOURCE_DMA, + }, + [3] = { + /* DRCMR for TX */ + .start = 16, + .end = 16, + .flags = IORESOURCE_DMA, + }, +}; + +struct platform_device pxa27x_device_ssp2 = { + .name = "pxa27x-ssp", + .id = 1, + .dev = { + .dma_mask = &pxa27x_ssp2_dma_mask, + .coherent_dma_mask = DMA_BIT_MASK(32), + }, + .resource = pxa27x_resource_ssp2, + .num_resources = ARRAY_SIZE(pxa27x_resource_ssp2), +}; + +static u64 pxa27x_ssp3_dma_mask = DMA_BIT_MASK(32); + +static struct resource pxa27x_resource_ssp3[] = { + [0] = { + .start = 0x41900000, + .end = 0x4190003f, + .flags = IORESOURCE_MEM, + }, + [1] = { + .start = IRQ_SSP3, + .end = IRQ_SSP3, + .flags = IORESOURCE_IRQ, + }, + [2] = { + /* DRCMR for RX */ + .start = 66, + .end = 66, + .flags = IORESOURCE_DMA, + }, + [3] = { + /* DRCMR for TX */ + .start = 67, + .end = 67, + .flags = IORESOURCE_DMA, + }, +}; + +struct platform_device pxa27x_device_ssp3 = { + .name = "pxa27x-ssp", + .id = 2, + .dev = { + .dma_mask = &pxa27x_ssp3_dma_mask, + .coherent_dma_mask = DMA_BIT_MASK(32), + }, + .resource = pxa27x_resource_ssp3, + .num_resources = ARRAY_SIZE(pxa27x_resource_ssp3), +}; +#endif /* CONFIG_PXA27x || CONFIG_PXA3xx */ + +#ifdef CONFIG_PXA3xx +static u64 pxa3xx_ssp4_dma_mask = DMA_BIT_MASK(32); + +static struct resource pxa3xx_resource_ssp4[] = { + [0] = { + .start = 0x41a00000, + .end = 0x41a0003f, + .flags = IORESOURCE_MEM, + }, + [1] = { + .start = IRQ_SSP4, + .end = IRQ_SSP4, + .flags = IORESOURCE_IRQ, + }, + [2] = { + /* DRCMR for RX */ + .start = 2, + .end = 2, + .flags = IORESOURCE_DMA, + }, + [3] = { + /* DRCMR for TX */ + .start = 3, + .end = 3, + .flags = IORESOURCE_DMA, + }, +}; + +struct platform_device pxa3xx_device_ssp4 = { + /* PXA3xx SSP is basically equivalent to PXA27x */ + .name = "pxa27x-ssp", + .id = 3, + .dev = { + .dma_mask = &pxa3xx_ssp4_dma_mask, + .coherent_dma_mask = DMA_BIT_MASK(32), + }, + .resource = pxa3xx_resource_ssp4, + .num_resources = ARRAY_SIZE(pxa3xx_resource_ssp4), +}; + +static struct resource pxa3xx_resources_mci2[] = { + [0] = { + .start = 0x42000000, + .end = 0x42000fff, + .flags = IORESOURCE_MEM, + }, + [1] = { + .start = IRQ_MMC2, + .end = IRQ_MMC2, + .flags = IORESOURCE_IRQ, + }, + [2] = { + .start = 93, + .end = 93, + .flags = IORESOURCE_DMA, + }, + [3] = { + .start = 94, + .end = 94, + .flags = IORESOURCE_DMA, + }, +}; + +struct platform_device pxa3xx_device_mci2 = { + .name = "pxa2xx-mci", + .id = 1, + .dev = { + .dma_mask = &pxamci_dmamask, + .coherent_dma_mask = 0xffffffff, + }, + .num_resources = ARRAY_SIZE(pxa3xx_resources_mci2), + .resource = pxa3xx_resources_mci2, +}; + +void __init pxa3xx_set_mci2_info(struct pxamci_platform_data *info) +{ + pxa_register_device(&pxa3xx_device_mci2, info); +} + +static struct resource pxa3xx_resources_mci3[] = { + [0] = { + .start = 0x42500000, + .end = 0x42500fff, + .flags = IORESOURCE_MEM, + }, + [1] = { + .start = IRQ_MMC3, + .end = IRQ_MMC3, + .flags = IORESOURCE_IRQ, + }, + [2] = { + .start = 100, + .end = 100, + .flags = IORESOURCE_DMA, + }, + [3] = { + .start = 101, + .end = 101, + .flags = IORESOURCE_DMA, + }, +}; + +struct platform_device pxa3xx_device_mci3 = { + .name = "pxa2xx-mci", + .id = 2, + .dev = { + .dma_mask = &pxamci_dmamask, + .coherent_dma_mask = 0xffffffff, + }, + .num_resources = ARRAY_SIZE(pxa3xx_resources_mci3), + .resource = pxa3xx_resources_mci3, +}; + +void __init pxa3xx_set_mci3_info(struct pxamci_platform_data *info) +{ + pxa_register_device(&pxa3xx_device_mci3, info); +} + +#endif /* CONFIG_PXA3xx */ diff --git a/arch/arm/mach-pxa/devices.h b/arch/arm/mach-pxa/devices.h index 94c8d5cdd60..96c7c890906 100644 --- a/arch/arm/mach-pxa/devices.h +++ b/arch/arm/mach-pxa/devices.h @@ -1,4 +1,6 @@ extern struct platform_device pxa_device_mci; +extern struct platform_device pxa3xx_device_mci2; +extern struct platform_device pxa3xx_device_mci3; extern struct platform_device pxa_device_udc; extern struct platform_device pxa_device_fb; extern struct platform_device pxa_device_ffuart; @@ -12,3 +14,13 @@ extern struct platform_device pxa_device_rtc; extern struct platform_device pxa27x_device_i2c_power; extern struct platform_device pxa27x_device_ohci; + +extern struct platform_device pxa25x_device_ssp; +extern struct platform_device pxa25x_device_nssp; +extern struct platform_device pxa25x_device_assp; +extern struct platform_device pxa27x_device_ssp1; +extern struct platform_device pxa27x_device_ssp2; +extern struct platform_device pxa27x_device_ssp3; +extern struct platform_device pxa3xx_device_ssp4; + +void __init pxa_register_device(struct platform_device *dev, void *data); diff --git a/arch/arm/mach-pxa/eseries.c b/arch/arm/mach-pxa/eseries.c new file mode 100644 index 00000000000..ee0ae93c876 --- /dev/null +++ b/arch/arm/mach-pxa/eseries.c @@ -0,0 +1,101 @@ +/* + * Hardware definitions for the Toshiba eseries PDAs + * + * Copyright (c) 2003 Ian Molton <spyro@f2s.com> + * + * This file is licensed under + * the terms of the GNU General Public License version 2. This program + * is licensed "as is" without any warranty of any kind, whether express + * or implied. + * + */ + +#include <linux/init.h> + +#include <asm/setup.h> +#include <asm/mach/arch.h> +#include <asm/arch/hardware.h> +#include <asm/mach-types.h> + +#include <generic.h> + +/* Only e800 has 128MB RAM */ +static void __init eseries_fixup(struct machine_desc *desc, + struct tag *tags, char **cmdline, struct meminfo *mi) +{ + mi->nr_banks=1; + mi->bank[0].start = 0xa0000000; + mi->bank[0].node = 0; + if (machine_is_e800()) + mi->bank[0].size = (128*1024*1024); + else + mi->bank[0].size = (64*1024*1024); +} + +/* e-series machine definitions */ + +#ifdef CONFIG_MACH_E330 +MACHINE_START(E330, "Toshiba e330") + /* Maintainer: Ian Molton (spyro@f2s.com) */ + .phys_io = 0x40000000, + .io_pg_offst = (io_p2v(0x40000000) >> 18) & 0xfffc, + .boot_params = 0xa0000100, + .map_io = pxa_map_io, + .init_irq = pxa25x_init_irq, + .fixup = eseries_fixup, + .timer = &pxa_timer, +MACHINE_END +#endif + +#ifdef CONFIG_MACH_E740 +MACHINE_START(E740, "Toshiba e740") + /* Maintainer: Ian Molton (spyro@f2s.com) */ + .phys_io = 0x40000000, + .io_pg_offst = (io_p2v(0x40000000) >> 18) & 0xfffc, + .boot_params = 0xa0000100, + .map_io = pxa_map_io, + .init_irq = pxa25x_init_irq, + .fixup = eseries_fixup, + .timer = &pxa_timer, +MACHINE_END +#endif + +#ifdef CONFIG_MACH_E750 +MACHINE_START(E750, "Toshiba e750") + /* Maintainer: Ian Molton (spyro@f2s.com) */ + .phys_io = 0x40000000, + .io_pg_offst = (io_p2v(0x40000000) >> 18) & 0xfffc, + .boot_params = 0xa0000100, + .map_io = pxa_map_io, + .init_irq = pxa25x_init_irq, + .fixup = eseries_fixup, + .timer = &pxa_timer, +MACHINE_END +#endif + +#ifdef CONFIG_MACH_E400 +MACHINE_START(E400, "Toshiba e400") + /* Maintainer: Ian Molton (spyro@f2s.com) */ + .phys_io = 0x40000000, + .io_pg_offst = (io_p2v(0x40000000) >> 18) & 0xfffc, + .boot_params = 0xa0000100, + .map_io = pxa_map_io, + .init_irq = pxa25x_init_irq, + .fixup = eseries_fixup, + .timer = &pxa_timer, +MACHINE_END +#endif + +#ifdef CONFIG_MACH_E800 +MACHINE_START(E800, "Toshiba e800") + /* Maintainer: Ian Molton (spyro@f2s.com) */ + .phys_io = 0x40000000, + .io_pg_offst = (io_p2v(0x40000000) >> 18) & 0xfffc, + .boot_params = 0xa0000100, + .map_io = pxa_map_io, + .init_irq = pxa25x_init_irq, + .fixup = eseries_fixup, + .timer = &pxa_timer, +MACHINE_END +#endif + diff --git a/arch/arm/mach-pxa/generic.c b/arch/arm/mach-pxa/generic.c index 1c34946ee16..698aeec5296 100644 --- a/arch/arm/mach-pxa/generic.c +++ b/arch/arm/mach-pxa/generic.c @@ -20,7 +20,6 @@ #include <linux/kernel.h> #include <linux/init.h> #include <linux/delay.h> -#include <linux/platform_device.h> #include <linux/ioport.h> #include <linux/pm.h> #include <linux/string.h> @@ -33,13 +32,7 @@ #include <asm/arch/pxa-regs.h> #include <asm/arch/gpio.h> -#include <asm/arch/udc.h> -#include <asm/arch/pxafb.h> -#include <asm/arch/mmc.h> -#include <asm/arch/irda.h> -#include <asm/arch/i2c.h> -#include "devices.h" #include "generic.h" /* @@ -203,7 +196,7 @@ static struct map_desc standard_io_desc[] __initdata = { }, { /* Mem Ctl */ .virtual = 0xf6000000, .pfn = __phys_to_pfn(0x48000000), - .length = 0x00100000, + .length = 0x00200000, .type = MT_DEVICE }, { /* USB host */ .virtual = 0xf8000000, @@ -233,245 +226,3 @@ 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; - -struct platform_device pxa_device_mci = { - .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) -{ - pxa_device_mci.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; - -struct platform_device pxa_device_udc = { - .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 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; - -struct platform_device pxa_device_fb = { - .name = "pxa2xx-fb", - .id = -1, - .dev = { - .dma_mask = &fb_dma_mask, - .coherent_dma_mask = 0xffffffff, - }, - .num_resources = ARRAY_SIZE(pxafb_resources), - .resource = pxafb_resources, -}; - -void __init set_pxa_fb_info(struct pxafb_mach_info *info) -{ - pxa_device_fb.dev.platform_data = info; -} - -void __init set_pxa_fb_parent(struct device *parent_dev) -{ - pxa_device_fb.dev.parent = parent_dev; -} - -static struct resource pxa_resource_ffuart[] = { - { - .start = __PREG(FFUART), - .end = __PREG(FFUART) + 35, - .flags = IORESOURCE_MEM, - }, { - .start = IRQ_FFUART, - .end = IRQ_FFUART, - .flags = IORESOURCE_IRQ, - } -}; - -struct platform_device pxa_device_ffuart= { - .name = "pxa2xx-uart", - .id = 0, - .resource = pxa_resource_ffuart, - .num_resources = ARRAY_SIZE(pxa_resource_ffuart), -}; - -static struct resource pxa_resource_btuart[] = { - { - .start = __PREG(BTUART), - .end = __PREG(BTUART) + 35, - .flags = IORESOURCE_MEM, - }, { - .start = IRQ_BTUART, - .end = IRQ_BTUART, - .flags = IORESOURCE_IRQ, - } -}; - -struct platform_device pxa_device_btuart = { - .name = "pxa2xx-uart", - .id = 1, - .resource = pxa_resource_btuart, - .num_resources = ARRAY_SIZE(pxa_resource_btuart), -}; - -static struct resource pxa_resource_stuart[] = { - { - .start = __PREG(STUART), - .end = __PREG(STUART) + 35, - .flags = IORESOURCE_MEM, - }, { - .start = IRQ_STUART, - .end = IRQ_STUART, - .flags = IORESOURCE_IRQ, - } -}; - -struct platform_device pxa_device_stuart = { - .name = "pxa2xx-uart", - .id = 2, - .resource = pxa_resource_stuart, - .num_resources = ARRAY_SIZE(pxa_resource_stuart), -}; - -static struct resource pxa_resource_hwuart[] = { - { - .start = __PREG(HWUART), - .end = __PREG(HWUART) + 47, - .flags = IORESOURCE_MEM, - }, { - .start = IRQ_HWUART, - .end = IRQ_HWUART, - .flags = IORESOURCE_IRQ, - } -}; - -struct platform_device pxa_device_hwuart = { - .name = "pxa2xx-uart", - .id = 3, - .resource = pxa_resource_hwuart, - .num_resources = ARRAY_SIZE(pxa_resource_hwuart), -}; - -static struct resource pxai2c_resources[] = { - { - .start = 0x40301680, - .end = 0x403016a3, - .flags = IORESOURCE_MEM, - }, { - .start = IRQ_I2C, - .end = IRQ_I2C, - .flags = IORESOURCE_IRQ, - }, -}; - -struct platform_device pxa_device_i2c = { - .name = "pxa2xx-i2c", - .id = 0, - .resource = pxai2c_resources, - .num_resources = ARRAY_SIZE(pxai2c_resources), -}; - -void __init pxa_set_i2c_info(struct i2c_pxa_platform_data *info) -{ - pxa_device_i2c.dev.platform_data = info; -} - -static struct resource pxai2s_resources[] = { - { - .start = 0x40400000, - .end = 0x40400083, - .flags = IORESOURCE_MEM, - }, { - .start = IRQ_I2S, - .end = IRQ_I2S, - .flags = IORESOURCE_IRQ, - }, -}; - -struct platform_device pxa_device_i2s = { - .name = "pxa2xx-i2s", - .id = -1, - .resource = pxai2s_resources, - .num_resources = ARRAY_SIZE(pxai2s_resources), -}; - -static u64 pxaficp_dmamask = ~(u32)0; - -struct platform_device pxa_device_ficp = { - .name = "pxa2xx-ir", - .id = -1, - .dev = { - .dma_mask = &pxaficp_dmamask, - .coherent_dma_mask = 0xffffffff, - }, -}; - -void __init pxa_set_ficp_info(struct pxaficp_platform_data *info) -{ - pxa_device_ficp.dev.platform_data = info; -} - -struct platform_device pxa_device_rtc = { - .name = "sa1100-rtc", - .id = -1, -}; diff --git a/arch/arm/mach-pxa/idp.c b/arch/arm/mach-pxa/idp.c index 465108da285..0a9434432c5 100644 --- a/arch/arm/mach-pxa/idp.c +++ b/arch/arm/mach-pxa/idp.c @@ -54,7 +54,7 @@ static struct resource smc91x_resources[] = { [1] = { .start = IRQ_GPIO(4), .end = IRQ_GPIO(4), - .flags = IORESOURCE_IRQ, + .flags = IORESOURCE_IRQ | IORESOURCE_IRQ_HIGHEDGE, } }; diff --git a/arch/arm/mach-pxa/littleton.c b/arch/arm/mach-pxa/littleton.c new file mode 100644 index 00000000000..0a4b54c2131 --- /dev/null +++ b/arch/arm/mach-pxa/littleton.c @@ -0,0 +1,325 @@ +/* + * linux/arch/arm/mach-pxa/littleton.c + * + * Support for the Marvell Littleton Development Platform. + * + * Author: Jason Chagas (largely modified code) + * Created: Nov 20, 2006 + * Copyright: (C) Copyright 2006 Marvell International Ltd. + * + * 2007-11-22 modified to align with latest kernel + * eric miao <eric.miao@marvell.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * publishhed by the Free Software Foundation. + */ + +#include <linux/init.h> +#include <linux/interrupt.h> +#include <linux/delay.h> +#include <linux/platform_device.h> +#include <linux/clk.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/mfp-pxa300.h> +#include <asm/arch/gpio.h> +#include <asm/arch/pxafb.h> +#include <asm/arch/ssp.h> +#include <asm/arch/littleton.h> + +#include "generic.h" + +#define ARRAY_AND_SIZE(x) (x), ARRAY_SIZE(x) + +/* Littleton MFP configurations */ +static mfp_cfg_t littleton_mfp_cfg[] __initdata = { + /* LCD */ + GPIO54_LCD_LDD_0, + GPIO55_LCD_LDD_1, + GPIO56_LCD_LDD_2, + GPIO57_LCD_LDD_3, + GPIO58_LCD_LDD_4, + GPIO59_LCD_LDD_5, + GPIO60_LCD_LDD_6, + GPIO61_LCD_LDD_7, + GPIO62_LCD_LDD_8, + GPIO63_LCD_LDD_9, + GPIO64_LCD_LDD_10, + GPIO65_LCD_LDD_11, + GPIO66_LCD_LDD_12, + GPIO67_LCD_LDD_13, + GPIO68_LCD_LDD_14, + GPIO69_LCD_LDD_15, + GPIO70_LCD_LDD_16, + GPIO71_LCD_LDD_17, + GPIO72_LCD_FCLK, + GPIO73_LCD_LCLK, + GPIO74_LCD_PCLK, + GPIO75_LCD_BIAS, + + /* SSP2 */ + GPIO25_SSP2_SCLK, + GPIO17_SSP2_FRM, + GPIO27_SSP2_TXD, + + /* Debug Ethernet */ + GPIO90_GPIO, +}; + +static struct resource smc91x_resources[] = { + [0] = { + .start = (LITTLETON_ETH_PHYS + 0x300), + .end = (LITTLETON_ETH_PHYS + 0xfffff), + .flags = IORESOURCE_MEM, + }, + [1] = { + .start = IRQ_GPIO(mfp_to_gpio(MFP_PIN_GPIO90)), + .end = IRQ_GPIO(mfp_to_gpio(MFP_PIN_GPIO90)), + .flags = IORESOURCE_IRQ | IRQF_TRIGGER_FALLING, + } +}; + +static struct platform_device smc91x_device = { + .name = "smc91x", + .id = 0, + .num_resources = ARRAY_SIZE(smc91x_resources), + .resource = smc91x_resources, +}; + +#if defined(CONFIG_FB_PXA) || defined(CONFIG_FB_PXA_MODULES) +/* use bit 30, 31 as the indicator of command parameter number */ +#define CMD0(x) ((0x00000000) | ((x) << 9)) +#define CMD1(x, x1) ((0x40000000) | ((x) << 9) | 0x100 | (x1)) +#define CMD2(x, x1, x2) ((0x80000000) | ((x) << 18) | 0x20000 |\ + ((x1) << 9) | 0x100 | (x2)) + +static uint32_t lcd_panel_reset[] = { + CMD0(0x1), /* reset */ + CMD0(0x0), /* nop */ + CMD0(0x0), /* nop */ + CMD0(0x0), /* nop */ +}; + +static uint32_t lcd_panel_on[] = { + CMD0(0x29), /* Display ON */ + CMD2(0xB8, 0xFF, 0xF9), /* Output Control */ + CMD0(0x11), /* Sleep out */ + CMD1(0xB0, 0x16), /* Wake */ +}; + +static uint32_t lcd_panel_off[] = { + CMD0(0x28), /* Display OFF */ + CMD2(0xB8, 0x80, 0x02), /* Output Control */ + CMD0(0x10), /* Sleep in */ + CMD1(0xB0, 0x00), /* Deep stand by in */ +}; + +static uint32_t lcd_vga_pass_through[] = { + CMD1(0xB0, 0x16), + CMD1(0xBC, 0x80), + CMD1(0xE1, 0x00), + CMD1(0x36, 0x50), + CMD1(0x3B, 0x00), +}; + +static uint32_t lcd_qvga_pass_through[] = { + CMD1(0xB0, 0x16), + CMD1(0xBC, 0x81), + CMD1(0xE1, 0x00), + CMD1(0x36, 0x50), + CMD1(0x3B, 0x22), +}; + +static uint32_t lcd_vga_transfer[] = { + CMD1(0xcf, 0x02), /* Blanking period control (1) */ + CMD2(0xd0, 0x08, 0x04), /* Blanking period control (2) */ + CMD1(0xd1, 0x01), /* CKV timing control on/off */ + CMD2(0xd2, 0x14, 0x00), /* CKV 1,2 timing control */ + CMD2(0xd3, 0x1a, 0x0f), /* OEV timing control */ + CMD2(0xd4, 0x1f, 0xaf), /* ASW timing control (1) */ + CMD1(0xd5, 0x14), /* ASW timing control (2) */ + CMD0(0x21), /* Invert for normally black display */ + CMD0(0x29), /* Display on */ +}; + +static uint32_t lcd_qvga_transfer[] = { + CMD1(0xd6, 0x02), /* Blanking period control (1) */ + CMD2(0xd7, 0x08, 0x04), /* Blanking period control (2) */ + CMD1(0xd8, 0x01), /* CKV timing control on/off */ + CMD2(0xd9, 0x00, 0x08), /* CKV 1,2 timing control */ + CMD2(0xde, 0x05, 0x0a), /* OEV timing control */ + CMD2(0xdf, 0x0a, 0x19), /* ASW timing control (1) */ + CMD1(0xe0, 0x0a), /* ASW timing control (2) */ + CMD0(0x21), /* Invert for normally black display */ + CMD0(0x29), /* Display on */ +}; + +static uint32_t lcd_panel_config[] = { + CMD2(0xb8, 0xff, 0xf9), /* Output control */ + CMD0(0x11), /* sleep out */ + CMD1(0xba, 0x01), /* Display mode (1) */ + CMD1(0xbb, 0x00), /* Display mode (2) */ + CMD1(0x3a, 0x60), /* Display mode 18-bit RGB */ + CMD1(0xbf, 0x10), /* Drive system change control */ + CMD1(0xb1, 0x56), /* Booster operation setup */ + CMD1(0xb2, 0x33), /* Booster mode setup */ + CMD1(0xb3, 0x11), /* Booster frequency setup */ + CMD1(0xb4, 0x02), /* Op amp/system clock */ + CMD1(0xb5, 0x35), /* VCS voltage */ + CMD1(0xb6, 0x40), /* VCOM voltage */ + CMD1(0xb7, 0x03), /* External display signal */ + CMD1(0xbd, 0x00), /* ASW slew rate */ + CMD1(0xbe, 0x00), /* Dummy data for QuadData operation */ + CMD1(0xc0, 0x11), /* Sleep out FR count (A) */ + CMD1(0xc1, 0x11), /* Sleep out FR count (B) */ + CMD1(0xc2, 0x11), /* Sleep out FR count (C) */ + CMD2(0xc3, 0x20, 0x40), /* Sleep out FR count (D) */ + CMD2(0xc4, 0x60, 0xc0), /* Sleep out FR count (E) */ + CMD2(0xc5, 0x10, 0x20), /* Sleep out FR count (F) */ + CMD1(0xc6, 0xc0), /* Sleep out FR count (G) */ + CMD2(0xc7, 0x33, 0x43), /* Gamma 1 fine tuning (1) */ + CMD1(0xc8, 0x44), /* Gamma 1 fine tuning (2) */ + CMD1(0xc9, 0x33), /* Gamma 1 inclination adjustment */ + CMD1(0xca, 0x00), /* Gamma 1 blue offset adjustment */ + CMD2(0xec, 0x01, 0xf0), /* Horizontal clock cycles */ +}; + +static void ssp_reconfig(struct ssp_dev *dev, int nparam) +{ + static int last_nparam = -1; + + /* check if it is necessary to re-config SSP */ + if (nparam == last_nparam) + return; + + ssp_disable(dev); + ssp_config(dev, (nparam == 2) ? 0x0010058a : 0x00100581, 0x18, 0, 0); + + last_nparam = nparam; +} + +static void ssp_send_cmd(uint32_t *cmd, int num) +{ + static int ssp_initialized; + static struct ssp_dev ssp2; + + int i; + + if (!ssp_initialized) { + ssp_init(&ssp2, 2, SSP_NO_IRQ); + ssp_initialized = 1; + } + + clk_enable(ssp2.ssp->clk); + for (i = 0; i < num; i++, cmd++) { + ssp_reconfig(&ssp2, (*cmd >> 30) & 0x3); + ssp_write_word(&ssp2, *cmd & 0x3fffffff); + + /* FIXME: ssp_flush() is mandatory here to work */ + ssp_flush(&ssp2); + } + clk_disable(ssp2.ssp->clk); +} + +static void littleton_lcd_power(int on, struct fb_var_screeninfo *var) +{ + if (on) { + ssp_send_cmd(ARRAY_AND_SIZE(lcd_panel_on)); + ssp_send_cmd(ARRAY_AND_SIZE(lcd_panel_reset)); + if (var->xres > 240) { + /* VGA */ + ssp_send_cmd(ARRAY_AND_SIZE(lcd_vga_pass_through)); + ssp_send_cmd(ARRAY_AND_SIZE(lcd_panel_config)); + ssp_send_cmd(ARRAY_AND_SIZE(lcd_vga_transfer)); + } else { + /* QVGA */ + ssp_send_cmd(ARRAY_AND_SIZE(lcd_qvga_pass_through)); + ssp_send_cmd(ARRAY_AND_SIZE(lcd_panel_config)); + ssp_send_cmd(ARRAY_AND_SIZE(lcd_qvga_transfer)); + } + } else + ssp_send_cmd(ARRAY_AND_SIZE(lcd_panel_off)); +} + +static struct pxafb_mode_info tpo_tdo24mtea1_modes[] = { + [0] = { + /* VGA */ + .pixclock = 38250, + .xres = 480, + .yres = 640, + .bpp = 16, + .hsync_len = 8, + .left_margin = 8, + .right_margin = 24, + .vsync_len = 2, + .upper_margin = 2, + .lower_margin = 4, + .sync = 0, + }, + [1] = { + /* QVGA */ + .pixclock = 153000, + .xres = 240, + .yres = 320, + .bpp = 16, + .hsync_len = 8, + .left_margin = 8, + .right_margin = 88, + .vsync_len = 2, + .upper_margin = 2, + .lower_margin = 2, + .sync = 0, + }, +}; + +static struct pxafb_mach_info littleton_lcd_info = { + .modes = tpo_tdo24mtea1_modes, + .num_modes = 2, + .lccr0 = LCCR0_Act, + .lccr3 = LCCR3_HSP | LCCR3_VSP, + .pxafb_lcd_power = littleton_lcd_power, +}; + +static void littleton_init_lcd(void) +{ + set_pxa_fb_info(&littleton_lcd_info); +} +#else +static inline void littleton_init_lcd(void) {}; +#endif /* CONFIG_FB_PXA || CONFIG_FB_PXA_MODULES */ + +static void __init littleton_init(void) +{ + /* initialize MFP configurations */ + pxa3xx_mfp_config(ARRAY_AND_SIZE(littleton_mfp_cfg)); + + /* + * Note: we depend bootloader set the correct + * value to MSC register for SMC91x. + */ + platform_device_register(&smc91x_device); + + littleton_init_lcd(); +} + +MACHINE_START(LITTLETON, "Marvell Form Factor Development Platform (aka Littleton)") + .phys_io = 0x40000000, + .boot_params = 0xa0000100, + .io_pg_offst = (io_p2v(0x40000000) >> 18) & 0xfffc, + .map_io = pxa_map_io, + .init_irq = pxa3xx_init_irq, + .timer = &pxa_timer, + .init_machine = littleton_init, +MACHINE_END diff --git a/arch/arm/mach-pxa/lpd270.c b/arch/arm/mach-pxa/lpd270.c index 78ebad063cb..afa62ffe3ad 100644 --- a/arch/arm/mach-pxa/lpd270.c +++ b/arch/arm/mach-pxa/lpd270.c @@ -38,6 +38,7 @@ #include <asm/mach/flash.h> #include <asm/arch/pxa-regs.h> +#include <asm/arch/pxa2xx-regs.h> #include <asm/arch/lpd270.h> #include <asm/arch/audio.h> #include <asm/arch/pxafb.h> diff --git a/arch/arm/mach-pxa/lubbock.c b/arch/arm/mach-pxa/lubbock.c index 1d3112dc629..e7ae4bb3e36 100644 --- a/arch/arm/mach-pxa/lubbock.c +++ b/arch/arm/mach-pxa/lubbock.c @@ -41,6 +41,7 @@ #include <asm/hardware/sa1111.h> #include <asm/arch/pxa-regs.h> +#include <asm/arch/pxa2xx-regs.h> #include <asm/arch/lubbock.h> #include <asm/arch/udc.h> #include <asm/arch/irda.h> @@ -136,9 +137,13 @@ static struct sys_device lubbock_irq_device = { static int __init lubbock_irq_device_init(void) { - int ret = sysdev_class_register(&lubbock_irq_sysclass); - if (ret == 0) - ret = sysdev_register(&lubbock_irq_device); + int ret = -ENODEV; + + if (machine_is_lubbock()) { + ret = sysdev_class_register(&lubbock_irq_sysclass); + if (ret == 0) + ret = sysdev_register(&lubbock_irq_device); + } return ret; } @@ -191,7 +196,7 @@ static struct resource smc91x_resources[] = { [1] = { .start = LUBBOCK_ETH_IRQ, .end = LUBBOCK_ETH_IRQ, - .flags = IORESOURCE_IRQ, + .flags = IORESOURCE_IRQ | IORESOURCE_IRQ_HIGHEDGE, }, [2] = { .name = "smc91x-attrib", @@ -206,30 +211,13 @@ static struct resource smc91x_resources[] = { * (to J5) and poking board registers (as done below). Else it's only useful * for the temperature sensors. */ -static struct resource pxa_ssp_resources[] = { - [0] = { - .start = __PREG(SSCR0_P(1)), - .end = __PREG(SSCR0_P(1)) + 0x14, - .flags = IORESOURCE_MEM, - }, - [1] = { - .start = IRQ_SSP, - .end = IRQ_SSP, - .flags = IORESOURCE_IRQ, - }, -}; - static struct pxa2xx_spi_master pxa_ssp_master_info = { - .ssp_type = PXA25x_SSP, - .clock_enable = CKEN_SSP, .num_chipselect = 0, }; static struct platform_device pxa_ssp = { .name = "pxa2xx-spi", .id = 1, - .resource = pxa_ssp_resources, - .num_resources = ARRAY_SIZE(pxa_ssp_resources), .dev = { .platform_data = &pxa_ssp_master_info, }, diff --git a/arch/arm/mach-pxa/magician.c b/arch/arm/mach-pxa/magician.c new file mode 100644 index 00000000000..d98ef7ada2f --- /dev/null +++ b/arch/arm/mach-pxa/magician.c @@ -0,0 +1,218 @@ +/* + * Support for HTC Magician PDA phones: + * i-mate JAM, O2 Xda mini, Orange SPV M500, Qtek s100, Qtek s110 + * and T-Mobile MDA Compact. + * + * Copyright (c) 2006-2007 Philipp Zabel + * + * Based on hx4700.c, spitz.c and others. + * + * 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/platform_device.h> +#include <linux/gpio_keys.h> +#include <linux/input.h> +#include <linux/mtd/mtd.h> +#include <linux/mtd/map.h> +#include <linux/mtd/physmap.h> + +#include <asm/gpio.h> +#include <asm/hardware.h> +#include <asm/mach-types.h> +#include <asm/mach/arch.h> +#include <asm/arch/magician.h> +#include <asm/arch/pxa-regs.h> +#include <asm/arch/pxafb.h> +#include <asm/arch/irda.h> +#include <asm/arch/ohci.h> + +#include "generic.h" + +/* + * IRDA + */ + +static void magician_irda_transceiver_mode(struct device *dev, int mode) +{ + gpio_set_value(GPIO83_MAGICIAN_nIR_EN, mode & IR_OFF); +} + +static struct pxaficp_platform_data magician_ficp_info = { + .transceiver_cap = IR_SIRMODE | IR_OFF, + .transceiver_mode = magician_irda_transceiver_mode, +}; + +/* + * GPIO Keys + */ + +static struct gpio_keys_button magician_button_table[] = { + {KEY_POWER, GPIO0_MAGICIAN_KEY_POWER, 0, "Power button"}, + {KEY_ESC, GPIO37_MAGICIAN_KEY_HANGUP, 0, "Hangup button"}, + {KEY_F10, GPIO38_MAGICIAN_KEY_CONTACTS, 0, "Contacts button"}, + {KEY_CALENDAR, GPIO90_MAGICIAN_KEY_CALENDAR, 0, "Calendar button"}, + {KEY_CAMERA, GPIO91_MAGICIAN_KEY_CAMERA, 0, "Camera button"}, + {KEY_UP, GPIO93_MAGICIAN_KEY_UP, 0, "Up button"}, + {KEY_DOWN, GPIO94_MAGICIAN_KEY_DOWN, 0, "Down button"}, + {KEY_LEFT, GPIO95_MAGICIAN_KEY_LEFT, 0, "Left button"}, + {KEY_RIGHT, GPIO96_MAGICIAN_KEY_RIGHT, 0, "Right button"}, + {KEY_KPENTER, GPIO97_MAGICIAN_KEY_ENTER, 0, "Action button"}, + {KEY_RECORD, GPIO98_MAGICIAN_KEY_RECORD, 0, "Record button"}, + {KEY_VOLUMEUP, GPIO100_MAGICIAN_KEY_VOL_UP, 0, "Volume up"}, + {KEY_VOLUMEDOWN, GPIO101_MAGICIAN_KEY_VOL_DOWN, 0, "Volume down"}, + {KEY_PHONE, GPIO102_MAGICIAN_KEY_PHONE, 0, "Phone button"}, + {KEY_PLAY, GPIO99_MAGICIAN_HEADPHONE_IN, 0, "Headset button"}, +}; + +static struct gpio_keys_platform_data gpio_keys_data = { + .buttons = magician_button_table, + .nbuttons = ARRAY_SIZE(magician_button_table), +}; + +static struct platform_device gpio_keys = { + .name = "gpio-keys", + .dev = { + .platform_data = &gpio_keys_data, + }, + .id = -1, +}; + +/* + * LCD - Toppoly TD028STEB1 + */ + +static struct pxafb_mode_info toppoly_modes[] = { + { + .pixclock = 96153, + .bpp = 16, + .xres = 240, + .yres = 320, + .hsync_len = 11, + .vsync_len = 3, + .left_margin = 19, + .upper_margin = 2, + .right_margin = 10, + .lower_margin = 2, + .sync = 0, + }, +}; + +static struct pxafb_mach_info toppoly_info = { + .modes = toppoly_modes, + .num_modes = 1, + .fixed_modes = 1, + .lccr0 = LCCR0_Color | LCCR0_Sngl | LCCR0_Act, + .lccr3 = LCCR3_PixRsEdg, +}; + +/* + * Backlight + */ + +static void magician_set_bl_intensity(int intensity) +{ + if (intensity) { + PWM_CTRL0 = 1; + PWM_PERVAL0 = 0xc8; + PWM_PWDUTY0 = intensity; + pxa_set_cken(CKEN_PWM0, 1); + } else { + pxa_set_cken(CKEN_PWM0, 0); + } +} + +static struct generic_bl_info backlight_info = { + .default_intensity = 0x64, + .limit_mask = 0x0b, + .max_intensity = 0xc7, + .set_bl_intensity = magician_set_bl_intensity, +}; + +static struct platform_device backlight = { + .name = "corgi-bl", + .dev = { + .platform_data = &backlight_info, + }, + .id = -1, +}; + + +/* + * USB OHCI + */ + +static int magician_ohci_init(struct device *dev) +{ + UHCHR = (UHCHR | UHCHR_SSEP2 | UHCHR_PCPL | UHCHR_CGR) & + ~(UHCHR_SSEP1 | UHCHR_SSEP3 | UHCHR_SSE); + + return 0; +} + +static struct pxaohci_platform_data magician_ohci_info = { + .port_mode = PMM_PERPORT_MODE, + .init = magician_ohci_init, + .power_budget = 0, +}; + + +/* + * StrataFlash + */ + +#define PXA_CS_SIZE 0x04000000 + +static struct resource strataflash_resource = { + .start = PXA_CS0_PHYS, + .end = PXA_CS0_PHYS + PXA_CS_SIZE - 1, + .flags = IORESOURCE_MEM, +}; + +static struct physmap_flash_data strataflash_data = { + .width = 4, +}; + +static struct platform_device strataflash = { + .name = "physmap-flash", + .id = -1, + .num_resources = 1, + .resource = &strataflash_resource, + .dev = { + .platform_data = &strataflash_data, + }, +}; + +/* + * Platform devices + */ + +static struct platform_device *devices[] __initdata = { + &gpio_keys, + &backlight, + &strataflash, +}; + +static void __init magician_init(void) +{ + platform_add_devices(devices, ARRAY_SIZE(devices)); + pxa_set_ohci_info(&magician_ohci_info); + pxa_set_ficp_info(&magician_ficp_info); + set_pxa_fb_info(&toppoly_info); +} + + +MACHINE_START(MAGICIAN, "HTC Magician") + .phys_io = 0x40000000, + .io_pg_offst = (io_p2v(0x40000000) >> 18) & 0xfffc, + .boot_params = 0xa0000100, + .map_io = pxa_map_io, + .init_irq = pxa27x_init_irq, + .init_machine = magician_init, + .timer = &pxa_timer, +MACHINE_END diff --git a/arch/arm/mach-pxa/mainstone.c b/arch/arm/mach-pxa/mainstone.c index 41d8c6cea62..345c3deeb02 100644 --- a/arch/arm/mach-pxa/mainstone.c +++ b/arch/arm/mach-pxa/mainstone.c @@ -23,6 +23,7 @@ #include <linux/ioport.h> #include <linux/mtd/mtd.h> #include <linux/mtd/partitions.h> +#include <linux/backlight.h> #include <asm/types.h> #include <asm/setup.h> @@ -38,6 +39,7 @@ #include <asm/mach/flash.h> #include <asm/arch/pxa-regs.h> +#include <asm/arch/pxa2xx-regs.h> #include <asm/arch/mainstone.h> #include <asm/arch/audio.h> #include <asm/arch/pxafb.h> @@ -130,9 +132,13 @@ static struct sys_device mainstone_irq_device = { static int __init mainstone_irq_device_init(void) { - int ret = sysdev_class_register(&mainstone_irq_sysclass); - if (ret == 0) - ret = sysdev_register(&mainstone_irq_device); + int ret = -ENODEV; + + if (machine_is_mainstone()) { + ret = sysdev_class_register(&mainstone_irq_sysclass); + if (ret == 0) + ret = sysdev_register(&mainstone_irq_device); + } return ret; } @@ -150,7 +156,7 @@ static struct resource smc91x_resources[] = { [1] = { .start = MAINSTONE_IRQ(3), .end = MAINSTONE_IRQ(3), - .flags = IORESOURCE_IRQ, + .flags = IORESOURCE_IRQ | IORESOURCE_IRQ_HIGHEDGE, } }; @@ -263,21 +269,60 @@ static struct platform_device mst_flash_device[2] = { }, }; -static void mainstone_backlight_power(int on) +#ifdef CONFIG_BACKLIGHT_CLASS_DEVICE +static int mainstone_backlight_update_status(struct backlight_device *bl) { - if (on) { + int brightness = bl->props.brightness; + + if (bl->props.power != FB_BLANK_UNBLANK || + bl->props.fb_blank != FB_BLANK_UNBLANK) + brightness = 0; + + if (brightness != 0) { pxa_gpio_mode(GPIO16_PWM0_MD); pxa_set_cken(CKEN_PWM0, 1); - PWM_CTRL0 = 0; - PWM_PWDUTY0 = 0x3ff; - PWM_PERVAL0 = 0x3ff; - } else { - PWM_CTRL0 = 0; - PWM_PWDUTY0 = 0x0; - PWM_PERVAL0 = 0x3FF; + } + PWM_CTRL0 = 0; + PWM_PWDUTY0 = brightness; + PWM_PERVAL0 = bl->props.max_brightness; + if (brightness == 0) pxa_set_cken(CKEN_PWM0, 0); + return 0; /* pointless return value */ +} + +static int mainstone_backlight_get_brightness(struct backlight_device *bl) +{ + return PWM_PWDUTY0; +} + +static /*const*/ struct backlight_ops mainstone_backlight_ops = { + .update_status = mainstone_backlight_update_status, + .get_brightness = mainstone_backlight_get_brightness, +}; + +static void __init mainstone_backlight_register(void) +{ + struct backlight_device *bl; + + bl = backlight_device_register("mainstone-bl", &pxa_device_fb.dev, + NULL, &mainstone_backlight_ops); + if (IS_ERR(bl)) { + printk(KERN_ERR "mainstone: unable to register backlight: %ld\n", + PTR_ERR(bl)); + return; } + + /* + * broken design - register-then-setup interfaces are + * utterly broken by definition. + */ + bl->props.max_brightness = 1023; + bl->props.brightness = 1023; + backlight_update_status(bl); } +#else +#define mainstone_backlight_register() do { } while (0) +#endif static struct pxafb_mode_info toshiba_ltm04c380k_mode = { .pixclock = 50000, @@ -311,7 +356,6 @@ static struct pxafb_mach_info mainstone_pxafb_info = { .num_modes = 1, .lccr0 = LCCR0_Act, .lccr3 = LCCR3_PCP, - .pxafb_backlight_power = mainstone_backlight_power, }; static int mainstone_mci_init(struct device *dev, irq_handler_t mstone_detect_int, void *data) @@ -335,12 +379,10 @@ static int mainstone_mci_init(struct device *dev, irq_handler_t mstone_detect_in err = request_irq(MAINSTONE_MMC_IRQ, mstone_detect_int, IRQF_DISABLED, "MMC card detect", data); - if (err) { + if (err) printk(KERN_ERR "mainstone_mci_init: MMC/SD: can't request MMC card detect IRQ\n"); - return -1; - } - return 0; + return err; } static void mainstone_mci_setpower(struct device *dev, unsigned int vdd) @@ -473,6 +515,7 @@ static void __init mainstone_init(void) mainstone_pxafb_info.modes = &toshiba_ltm035a776c_mode; set_pxa_fb_info(&mainstone_pxafb_info); + mainstone_backlight_register(); pxa_set_mci_info(&mainstone_mci_platform_data); pxa_set_ficp_info(&mainstone_ficp_platform_data); diff --git a/arch/arm/mach-pxa/mfp.c b/arch/arm/mach-pxa/mfp.c index 436f9657496..ec1b2d8f61c 100644 --- a/arch/arm/mach-pxa/mfp.c +++ b/arch/arm/mach-pxa/mfp.c @@ -17,9 +17,11 @@ #include <linux/kernel.h> #include <linux/init.h> #include <linux/io.h> +#include <linux/sysdev.h> #include <asm/hardware.h> #include <asm/arch/mfp.h> +#include <asm/arch/mfp-pxa3xx.h> /* mfp_spin_lock is used to ensure that MFP register configuration * (most likely a read-modify-write operation) is atomic, and that @@ -28,43 +30,110 @@ static DEFINE_SPINLOCK(mfp_spin_lock); static void __iomem *mfpr_mmio_base = (void __iomem *)&__REG(MFPR_BASE); + +struct pxa3xx_mfp_pin { + unsigned long config; /* -1 for not configured */ + unsigned long mfpr_off; /* MFPRxx Register offset */ + unsigned long mfpr_run; /* Run-Mode Register Value */ + unsigned long mfpr_lpm; /* Low Power Mode Register Value */ +}; + static struct pxa3xx_mfp_pin mfp_table[MFP_PIN_MAX]; +/* mapping of MFP_LPM_* definitions to MFPR_LPM_* register bits */ +const static unsigned long mfpr_lpm[] = { + MFPR_LPM_INPUT, + MFPR_LPM_DRIVE_LOW, + MFPR_LPM_DRIVE_HIGH, + MFPR_LPM_PULL_LOW, + MFPR_LPM_PULL_HIGH, + MFPR_LPM_FLOAT, +}; + +/* mapping of MFP_PULL_* definitions to MFPR_PULL_* register bits */ +const static unsigned long mfpr_pull[] = { + MFPR_PULL_NONE, + MFPR_PULL_LOW, + MFPR_PULL_HIGH, + MFPR_PULL_BOTH, +}; + +/* mapping of MFP_LPM_EDGE_* definitions to MFPR_EDGE_* register bits */ +const static unsigned long mfpr_edge[] = { + MFPR_EDGE_NONE, + MFPR_EDGE_RISE, + MFPR_EDGE_FALL, + MFPR_EDGE_BOTH, +}; + #define mfpr_readl(off) \ __raw_readl(mfpr_mmio_base + (off)) #define mfpr_writel(off, val) \ __raw_writel(val, mfpr_mmio_base + (off)) +#define mfp_configured(p) ((p)->config != -1) + /* * perform a read-back of any MFPR register to make sure the * previous writings are finished */ #define mfpr_sync() (void)__raw_readl(mfpr_mmio_base + 0) -static inline void __mfp_config(int pin, unsigned long val) +static inline void __mfp_config_run(struct pxa3xx_mfp_pin *p) { - unsigned long off = mfp_table[pin].mfpr_off; + if (mfp_configured(p)) + mfpr_writel(p->mfpr_off, p->mfpr_run); +} - mfp_table[pin].mfpr_val = val; - mfpr_writel(off, val); +static inline void __mfp_config_lpm(struct pxa3xx_mfp_pin *p) +{ + if (mfp_configured(p)) { + unsigned long mfpr_clr = (p->mfpr_run & ~MFPR_EDGE_BOTH) | MFPR_EDGE_CLEAR; + if (mfpr_clr != p->mfpr_run) + mfpr_writel(p->mfpr_off, mfpr_clr); + if (p->mfpr_lpm != mfpr_clr) + mfpr_writel(p->mfpr_off, p->mfpr_lpm); + } } -void pxa3xx_mfp_config(mfp_cfg_t *mfp_cfgs, int num) +void pxa3xx_mfp_config(unsigned long *mfp_cfgs, int num) { - int i, pin; - unsigned long val, flags; - mfp_cfg_t *mfp_cfg = mfp_cfgs; + unsigned long flags; + int i; spin_lock_irqsave(&mfp_spin_lock, flags); - for (i = 0; i < num; i++, mfp_cfg++) { - pin = MFP_CFG_PIN(*mfp_cfg); - val = MFP_CFG_VAL(*mfp_cfg); + for (i = 0; i < num; i++, mfp_cfgs++) { + unsigned long tmp, c = *mfp_cfgs; + struct pxa3xx_mfp_pin *p; + int pin, af, drv, lpm, edge, pull; + pin = MFP_PIN(c); BUG_ON(pin >= MFP_PIN_MAX); - - __mfp_config(pin, val); + p = &mfp_table[pin]; + + af = MFP_AF(c); + drv = MFP_DS(c); + lpm = MFP_LPM_STATE(c); + edge = MFP_LPM_EDGE(c); + pull = MFP_PULL(c); + + /* run-mode pull settings will conflict with MFPR bits of + * low power mode state, calculate mfpr_run and mfpr_lpm + * individually if pull != MFP_PULL_NONE + */ + tmp = MFPR_AF_SEL(af) | MFPR_DRIVE(drv); + + if (likely(pull == MFP_PULL_NONE)) { + p->mfpr_run = tmp | mfpr_lpm[lpm] | mfpr_edge[edge]; + p->mfpr_lpm = p->mfpr_run; + } else { + p->mfpr_lpm = tmp | mfpr_lpm[lpm] | mfpr_edge[edge]; + p->mfpr_run = tmp | mfpr_pull[pull]; + } + + p->config = c; __mfp_config_run(p); } mfpr_sync(); @@ -96,140 +165,82 @@ void pxa3xx_mfp_write(int mfp, unsigned long val) spin_unlock_irqrestore(&mfp_spin_lock, flags); } -void pxa3xx_mfp_set_afds(int mfp, int af, int ds) -{ - uint32_t mfpr_off, mfpr_val; - unsigned long flags; - - BUG_ON(mfp >= MFP_PIN_MAX); - - spin_lock_irqsave(&mfp_spin_lock, flags); - mfpr_off = mfp_table[mfp].mfpr_off; - - mfpr_val = mfpr_readl(mfpr_off); - mfpr_val &= ~(MFPR_AF_MASK | MFPR_DRV_MASK); - mfpr_val |= (((af & 0x7) << MFPR_ALT_OFFSET) | - ((ds & 0x7) << MFPR_DRV_OFFSET)); - - mfpr_writel(mfpr_off, mfpr_val); - mfpr_sync(); - - spin_unlock_irqrestore(&mfp_spin_lock, flags); -} - -void pxa3xx_mfp_set_rdh(int mfp, int rdh) +void __init pxa3xx_mfp_init_addr(struct pxa3xx_mfp_addr_map *map) { - uint32_t mfpr_off, mfpr_val; - unsigned long flags; - - BUG_ON(mfp >= MFP_PIN_MAX); + struct pxa3xx_mfp_addr_map *p; + unsigned long offset, flags; + int i; spin_lock_irqsave(&mfp_spin_lock, flags); - mfpr_off = mfp_table[mfp].mfpr_off; - - mfpr_val = mfpr_readl(mfpr_off); - mfpr_val &= ~MFPR_RDH_MASK; - - if (likely(rdh)) - mfpr_val |= (1u << MFPR_SS_OFFSET); + for (p = map; p->start != MFP_PIN_INVALID; p++) { + offset = p->offset; + i = p->start; - mfpr_writel(mfpr_off, mfpr_val); - mfpr_sync(); + do { + mfp_table[i].mfpr_off = offset; + mfp_table[i].mfpr_run = 0; + mfp_table[i].mfpr_lpm = 0; + offset += 4; i++; + } while ((i <= p->end) && (p->end != -1)); + } spin_unlock_irqrestore(&mfp_spin_lock, flags); } -void pxa3xx_mfp_set_lpm(int mfp, int lpm) +void __init pxa3xx_init_mfp(void) { - uint32_t mfpr_off, mfpr_val; - unsigned long flags; - - BUG_ON(mfp >= MFP_PIN_MAX); - - spin_lock_irqsave(&mfp_spin_lock, flags); - - mfpr_off = mfp_table[mfp].mfpr_off; - mfpr_val = mfpr_readl(mfpr_off); - mfpr_val &= ~MFPR_LPM_MASK; - - if (lpm & 0x1) mfpr_val |= 1u << MFPR_SON_OFFSET; - if (lpm & 0x2) mfpr_val |= 1u << MFPR_SD_OFFSET; - if (lpm & 0x4) mfpr_val |= 1u << MFPR_PU_OFFSET; - if (lpm & 0x8) mfpr_val |= 1u << MFPR_PD_OFFSET; - if (lpm &0x10) mfpr_val |= 1u << MFPR_PS_OFFSET; - - mfpr_writel(mfpr_off, mfpr_val); - mfpr_sync(); + int i; - spin_unlock_irqrestore(&mfp_spin_lock, flags); + for (i = 0; i < ARRAY_SIZE(mfp_table); i++) + mfp_table[i].config = -1; } -void pxa3xx_mfp_set_pull(int mfp, int pull) +#ifdef CONFIG_PM +/* + * Configure the MFPs appropriately for suspend/resume. + * FIXME: this should probably depend on which system state we're + * entering - for instance, we might not want to place MFP pins in + * a pull-down mode if they're an active low chip select, and we're + * just entering standby. + */ +static int pxa3xx_mfp_suspend(struct sys_device *d, pm_message_t state) { - uint32_t mfpr_off, mfpr_val; - unsigned long flags; - - BUG_ON(mfp >= MFP_PIN_MAX); - - spin_lock_irqsave(&mfp_spin_lock, flags); + int pin; - mfpr_off = mfp_table[mfp].mfpr_off; - mfpr_val = mfpr_readl(mfpr_off); - mfpr_val &= ~MFPR_PULL_MASK; - mfpr_val |= ((pull & 0x7u) << MFPR_PD_OFFSET); - - mfpr_writel(mfpr_off, mfpr_val); - mfpr_sync(); - - spin_unlock_irqrestore(&mfp_spin_lock, flags); + for (pin = 0; pin < ARRAY_SIZE(mfp_table); pin++) { + struct pxa3xx_mfp_pin *p = &mfp_table[pin]; + __mfp_config_lpm(p); + } + return 0; } -void pxa3xx_mfp_set_edge(int mfp, int edge) +static int pxa3xx_mfp_resume(struct sys_device *d) { - uint32_t mfpr_off, mfpr_val; - unsigned long flags; - - BUG_ON(mfp >= MFP_PIN_MAX); - - spin_lock_irqsave(&mfp_spin_lock, flags); - - mfpr_off = mfp_table[mfp].mfpr_off; - mfpr_val = mfpr_readl(mfpr_off); - - mfpr_val &= ~MFPR_EDGE_MASK; - mfpr_val |= (edge & 0x3u) << MFPR_ERE_OFFSET; - mfpr_val |= (!edge & 0x1) << MFPR_EC_OFFSET; + int pin; - mfpr_writel(mfpr_off, mfpr_val); - mfpr_sync(); - - spin_unlock_irqrestore(&mfp_spin_lock, flags); + for (pin = 0; pin < ARRAY_SIZE(mfp_table); pin++) { + struct pxa3xx_mfp_pin *p = &mfp_table[pin]; + __mfp_config_run(p); + } + return 0; } -void __init pxa3xx_mfp_init_addr(struct pxa3xx_mfp_addr_map *map) -{ - struct pxa3xx_mfp_addr_map *p; - unsigned long offset, flags; - int i; - - spin_lock_irqsave(&mfp_spin_lock, flags); - - for (p = map; p->start != MFP_PIN_INVALID; p++) { - offset = p->offset; - i = p->start; - - do { - mfp_table[i].mfpr_off = offset; - mfp_table[i].mfpr_val = 0; - offset += 4; i++; - } while ((i <= p->end) && (p->end != -1)); - } +static struct sysdev_class mfp_sysclass = { + set_kset_name("mfp"), + .suspend = pxa3xx_mfp_suspend, + .resume = pxa3xx_mfp_resume, +}; - spin_unlock_irqrestore(&mfp_spin_lock, flags); -} +static struct sys_device mfp_device = { + .id = 0, + .cls = &mfp_sysclass, +}; -void __init pxa3xx_init_mfp(void) +static int __init mfp_init_devicefs(void) { - memset(mfp_table, 0, sizeof(mfp_table)); + sysdev_class_register(&mfp_sysclass); + return sysdev_register(&mfp_device); } +device_initcall(mfp_init_devicefs); +#endif diff --git a/arch/arm/mach-pxa/pcm027.c b/arch/arm/mach-pxa/pcm027.c new file mode 100644 index 00000000000..540c3bba5f9 --- /dev/null +++ b/arch/arm/mach-pxa/pcm027.c @@ -0,0 +1,216 @@ +/* + * linux/arch/arm/mach-pxa/pcm027.c + * Support for the Phytec phyCORE-PXA270 CPU card (aka PCM-027). + * + * Refer + * http://www.phytec.com/products/sbc/ARM-XScale/phyCORE-XScale-PXA270.html + * for additional hardware info + * + * Author: Juergen Kilb + * Created: April 05, 2005 + * Copyright: Phytec Messtechnik GmbH + * e-Mail: armlinux@phytec.de + * + * based on Intel Mainstone Board + * + * Copyright 2007 Juergen Beisert @ Pengutronix (j.beisert@pengutronix.de) + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#include <linux/irq.h> +#include <linux/platform_device.h> +#include <linux/mtd/physmap.h> +#include <linux/spi/spi.h> +#include <linux/leds.h> +#include <asm/mach-types.h> +#include <asm/mach/arch.h> +#include <asm/arch/hardware.h> +#include <asm/arch/pxa-regs.h> +#include <asm/arch/pxa2xx_spi.h> +#include <asm/arch/pcm027.h> +#include "generic.h" + +/* + * ABSTRACT: + * + * The PXA270 processor comes with a bunch of hardware on its silicon. + * Not all of this hardware can be used at the same time and not all + * is routed to module's connectors. Also it depends on the baseboard, what + * kind of hardware can be used in which way. + * -> So this file supports the main devices on the CPU card only! + * Refer pcm990-baseboard.c how to extend this features to get a full + * blown system with many common interfaces. + * + * The PCM-027 supports the following interfaces through its connectors and + * will be used in pcm990-baseboard.c: + * + * - LCD support + * - MMC support + * - IDE/CF card + * - FFUART + * - BTUART + * - IRUART + * - AC97 + * - SSP + * - SSP3 + * + * Claimed GPIOs: + * GPIO0 -> IRQ input from RTC + * GPIO2 -> SYS_ENA*) + * GPIO3 -> PWR_SCL + * GPIO4 -> PWR_SDA + * GPIO5 -> PowerCap0*) + * GPIO6 -> PowerCap1*) + * GPIO7 -> PowerCap2*) + * GPIO8 -> PowerCap3*) + * GPIO15 -> /CS1 + * GPIO20 -> /CS2 + * GPIO21 -> /CS3 + * GPIO33 -> /CS5 network controller select + * GPIO52 -> IRQ from network controller + * GPIO78 -> /CS2 + * GPIO80 -> /CS4 + * GPIO90 -> LED0 + * GPIO91 -> LED1 + * GPIO114 -> IRQ from CAN controller + * GPIO117 -> SCL + * GPIO118 -> SDA + * + * *) CPU internal use only + */ + +/* + * SMC91x network controller specific stuff + */ +static struct resource smc91x_resources[] = { + [0] = { + .start = PCM027_ETH_PHYS + 0x300, + .end = PCM027_ETH_PHYS + PCM027_ETH_SIZE, + .flags = IORESOURCE_MEM, + }, + [1] = { + .start = PCM027_ETH_IRQ, + .end = PCM027_ETH_IRQ, + /* note: smc91x's driver doesn't use the trigger bits yet */ + .flags = IORESOURCE_IRQ | PCM027_ETH_IRQ_EDGE, + } +}; + +static struct platform_device smc91x_device = { + .name = "smc91x", + .id = 0, + .num_resources = ARRAY_SIZE(smc91x_resources), + .resource = smc91x_resources, +}; + +static struct physmap_flash_data pcm027_flash_data = { + .width = 4, +}; + +static struct resource pcm027_flash_resource = { + .start = PCM027_FLASH_PHYS, + .end = PCM027_FLASH_PHYS + PCM027_FLASH_SIZE - 1 , + .flags = IORESOURCE_MEM, +}; + +static struct platform_device pcm027_flash = { + .name = "physmap-flash", + .id = 0, + .dev = { + .platform_data = &pcm027_flash_data, + }, + .resource = &pcm027_flash_resource, + .num_resources = 1, +}; + +#ifdef CONFIG_LEDS_GPIO + +static struct gpio_led pcm027_led[] = { + { + .name = "led0:red", /* FIXME */ + .gpio = PCM027_LED_CPU + }, + { + .name = "led1:green", /* FIXME */ + .gpio = PCM027_LED_HEARD_BEAT + }, +}; + +static struct gpio_led_platform_data pcm027_led_data = { + .num_leds = ARRAY_SIZE(pcm027_led), + .leds = pcm027_led +}; + +static struct platform_device pcm027_led_dev = { + .name = "leds-gpio", + .id = 0, + .dev = { + .platform_data = &pcm027_led_data, + }, +}; + +#endif /* CONFIG_LEDS_GPIO */ + +/* + * declare the available device resources on this board + */ +static struct platform_device *devices[] __initdata = { + &smc91x_device, + &pcm027_flash, +#ifdef CONFIG_LEDS_GPIO + &pcm027_led_dev +#endif +}; + +/* + * pcm027_init - breath some life into the board + */ +static void __init pcm027_init(void) +{ + /* system bus arbiter setting + * - Core_Park + * - LCD_wt:DMA_wt:CORE_Wt = 2:3:4 + */ + ARB_CNTRL = ARB_CORE_PARK | 0x234; + + platform_add_devices(devices, ARRAY_SIZE(devices)); + + /* LEDs (on demand only) */ +#ifdef CONFIG_LEDS_GPIO + pxa_gpio_mode(PCM027_LED_CPU | GPIO_OUT); + pxa_gpio_mode(PCM027_LED_HEARD_BEAT | GPIO_OUT); +#endif /* CONFIG_LEDS_GPIO */ + + /* at last call the baseboard to initialize itself */ +#ifdef CONFIG_MACH_PCM990_BASEBOARD + pcm990_baseboard_init(); +#endif +} + +static void __init pcm027_map_io(void) +{ + pxa_map_io(); + + /* initialize sleep mode regs (wake-up sources, etc) */ + PGSR0 = 0x01308000; + PGSR1 = 0x00CF0002; + PGSR2 = 0x0E294000; + PGSR3 = 0x0000C000; + PWER = 0x40000000 | PWER_GPIO0 | PWER_GPIO1; + PRER = 0x00000000; + PFER = 0x00000003; +} + +MACHINE_START(PCM027, "Phytec Messtechnik GmbH phyCORE-PXA270") + /* Maintainer: Pengutronix */ + .boot_params = 0xa0000100, + .phys_io = 0x40000000, + .io_pg_offst = (io_p2v(0x40000000) >> 18) & 0xfffc, + .map_io = pcm027_map_io, + .init_irq = pxa27x_init_irq, + .timer = &pxa_timer, + .init_machine = pcm027_init, +MACHINE_END diff --git a/arch/arm/mach-pxa/pcm990-baseboard.c b/arch/arm/mach-pxa/pcm990-baseboard.c new file mode 100644 index 00000000000..3dda16a2004 --- /dev/null +++ b/arch/arm/mach-pxa/pcm990-baseboard.c @@ -0,0 +1,330 @@ +/* + * arch/arm/mach-pxa/pcm990-baseboard.c + * Support for the Phytec phyCORE-PXA270 Development Platform (PCM-990). + * + * Refer + * http://www.phytec.com/products/rdk/ARM-XScale/phyCORE-XScale-PXA270.html + * for additional hardware info + * + * Author: Juergen Kilb + * Created: April 05, 2005 + * Copyright: Phytec Messtechnik GmbH + * e-Mail: armlinux@phytec.de + * + * based on Intel Mainstone Board + * + * Copyright 2007 Juergen Beisert @ Pengutronix (j.beisert@pengutronix.de) + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#include <linux/irq.h> +#include <linux/platform_device.h> +#include <linux/ide.h> +#include <asm/mach/map.h> +#include <asm/arch/pxa-regs.h> +#include <asm/arch/mmc.h> +#include <asm/arch/ohci.h> +#include <asm/arch/pcm990_baseboard.h> + +/* + * The PCM-990 development baseboard uses PCM-027's hardeware in the + * following way: + * + * - LCD support is in use + * - GPIO16 is output for back light on/off with PWM + * - GPIO58 ... GPIO73 are outputs for display data + * - GPIO74 is output output for LCDFCLK + * - GPIO75 is output for LCDLCLK + * - GPIO76 is output for LCDPCLK + * - GPIO77 is output for LCDBIAS + * - MMC support is in use + * - GPIO32 is output for MMCCLK + * - GPIO92 is MMDAT0 + * - GPIO109 is MMDAT1 + * - GPIO110 is MMCS0 + * - GPIO111 is MMCS1 + * - GPIO112 is MMCMD + * - IDE/CF card is in use + * - GPIO48 is output /POE + * - GPIO49 is output /PWE + * - GPIO50 is output /PIOR + * - GPIO51 is output /PIOW + * - GPIO54 is output /PCE2 + * - GPIO55 is output /PREG + * - GPIO56 is input /PWAIT + * - GPIO57 is output /PIOS16 + * - GPIO79 is output PSKTSEL + * - GPIO85 is output /PCE1 + * - FFUART is in use + * - GPIO34 is input FFRXD + * - GPIO35 is input FFCTS + * - GPIO36 is input FFDCD + * - GPIO37 is input FFDSR + * - GPIO38 is input FFRI + * - GPIO39 is output FFTXD + * - GPIO40 is output FFDTR + * - GPIO41 is output FFRTS + * - BTUART is in use + * - GPIO42 is input BTRXD + * - GPIO43 is output BTTXD + * - GPIO44 is input BTCTS + * - GPIO45 is output BTRTS + * - IRUART is in use + * - GPIO46 is input STDRXD + * - GPIO47 is output STDTXD + * - AC97 is in use*) + * - GPIO28 is input AC97CLK + * - GPIO29 is input AC97DatIn + * - GPIO30 is output AC97DatO + * - GPIO31 is output AC97SYNC + * - GPIO113 is output AC97_RESET + * - SSP is in use + * - GPIO23 is output SSPSCLK + * - GPIO24 is output chip select to Max7301 + * - GPIO25 is output SSPTXD + * - GPIO26 is input SSPRXD + * - GPIO27 is input for Max7301 IRQ + * - GPIO53 is input SSPSYSCLK + * - SSP3 is in use + * - GPIO81 is output SSPTXD3 + * - GPIO82 is input SSPRXD3 + * - GPIO83 is output SSPSFRM + * - GPIO84 is output SSPCLK3 + * + * Otherwise claimed GPIOs: + * GPIO1 -> IRQ from user switch + * GPIO9 -> IRQ from power management + * GPIO10 -> IRQ from WML9712 AC97 controller + * GPIO11 -> IRQ from IDE controller + * GPIO12 -> IRQ from CF controller + * GPIO13 -> IRQ from CF controller + * GPIO14 -> GPIO free + * GPIO15 -> /CS1 selects baseboard's Control CPLD (U7, 16 bit wide data path) + * GPIO19 -> GPIO free + * GPIO20 -> /SDCS2 + * GPIO21 -> /CS3 PC card socket select + * GPIO33 -> /CS5 network controller select + * GPIO78 -> /CS2 (16 bit wide data path) + * GPIO80 -> /CS4 (16 bit wide data path) + * GPIO86 -> GPIO free + * GPIO87 -> GPIO free + * GPIO90 -> LED0 on CPU module + * GPIO91 -> LED1 on CPI module + * GPIO117 -> SCL + * GPIO118 -> SDA + */ + +static unsigned long pcm990_irq_enabled; + +static void pcm990_mask_ack_irq(unsigned int irq) +{ + int pcm990_irq = (irq - PCM027_IRQ(0)); + PCM990_INTMSKENA = (pcm990_irq_enabled &= ~(1 << pcm990_irq)); +} + +static void pcm990_unmask_irq(unsigned int irq) +{ + int pcm990_irq = (irq - PCM027_IRQ(0)); + /* the irq can be acknowledged only if deasserted, so it's done here */ + PCM990_INTSETCLR |= 1 << pcm990_irq; + PCM990_INTMSKENA = (pcm990_irq_enabled |= (1 << pcm990_irq)); +} + +static struct irq_chip pcm990_irq_chip = { + .mask_ack = pcm990_mask_ack_irq, + .unmask = pcm990_unmask_irq, +}; + +static void pcm990_irq_handler(unsigned int irq, struct irq_desc *desc) +{ + unsigned long pending = (~PCM990_INTSETCLR) & pcm990_irq_enabled; + + do { + GEDR(PCM990_CTRL_INT_IRQ_GPIO) = + GPIO_bit(PCM990_CTRL_INT_IRQ_GPIO); + if (likely(pending)) { + irq = PCM027_IRQ(0) + __ffs(pending); + desc = irq_desc + irq; + desc_handle_irq(irq, desc); + } + pending = (~PCM990_INTSETCLR) & pcm990_irq_enabled; + } while (pending); +} + +static void __init pcm990_init_irq(void) +{ + int irq; + + /* setup extra PCM990 irqs */ + for (irq = PCM027_IRQ(0); irq <= PCM027_IRQ(3); irq++) { + set_irq_chip(irq, &pcm990_irq_chip); + set_irq_handler(irq, handle_level_irq); + set_irq_flags(irq, IRQF_VALID | IRQF_PROBE); + } + + PCM990_INTMSKENA = 0x00; /* disable all Interrupts */ + PCM990_INTSETCLR = 0xFF; + + set_irq_chained_handler(PCM990_CTRL_INT_IRQ, pcm990_irq_handler); + set_irq_type(PCM990_CTRL_INT_IRQ, PCM990_CTRL_INT_IRQ_EDGE); +} + +static int pcm990_mci_init(struct device *dev, irq_handler_t mci_detect_int, + void *data) +{ + int err; + + /* + * enable 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); + + err = request_irq(PCM027_MMCDET_IRQ, mci_detect_int, IRQF_DISABLED, + "MMC card detect", data); + if (err) + printk(KERN_ERR "pcm990_mci_init: MMC/SD: can't request MMC " + "card detect IRQ\n"); + + return err; +} + +static void pcm990_mci_setpower(struct device *dev, unsigned int vdd) +{ + struct pxamci_platform_data *p_d = dev->platform_data; + + if ((1 << vdd) & p_d->ocr_mask) + __PCM990_CTRL_REG(PCM990_CTRL_PHYS + PCM990_CTRL_REG5) = + PCM990_CTRL_MMC2PWR; + else + __PCM990_CTRL_REG(PCM990_CTRL_PHYS + PCM990_CTRL_REG5) = + ~PCM990_CTRL_MMC2PWR; +} + +static void pcm990_mci_exit(struct device *dev, void *data) +{ + free_irq(PCM027_MMCDET_IRQ, data); +} + +#define MSECS_PER_JIFFY (1000/HZ) + +static struct pxamci_platform_data pcm990_mci_platform_data = { + .detect_delay = 250 / MSECS_PER_JIFFY, + .ocr_mask = MMC_VDD_32_33 | MMC_VDD_33_34, + .init = pcm990_mci_init, + .setpower = pcm990_mci_setpower, + .exit = pcm990_mci_exit, +}; + +/* + * init OHCI hardware to work with + * + * Note: Only USB port 1 (host only) is connected + * + * GPIO88 (USBHPWR#1): overcurrent in, overcurrent when low + * GPIO89 (USBHPEN#1): power-on out, on when low + */ +static int pcm990_ohci_init(struct device *dev) +{ + pxa_gpio_mode(PCM990_USB_OVERCURRENT); + pxa_gpio_mode(PCM990_USB_PWR_EN); + /* + * disable USB port 2 and 3 + * power sense is active low + */ + UHCHR = ((UHCHR) | UHCHR_PCPL | UHCHR_PSPL | UHCHR_SSEP2 | + UHCHR_SSEP3) & ~(UHCHR_SSEP1 | UHCHR_SSE); + /* + * wait 10ms after Power on + * overcurrent per port + * power switch per port + */ + UHCRHDA = (5<<24) | (1<<11) | (1<<8); /* FIXME: Required? */ + + return 0; +} + +static struct pxaohci_platform_data pcm990_ohci_platform_data = { + .port_mode = PMM_PERPORT_MODE, + .init = pcm990_ohci_init, + .exit = NULL, +}; + +/* + * AC97 support + * Note: The connected AC97 mixer also reports interrupts at PCM990_AC97_IRQ + */ +static struct resource pxa27x_ac97_resources[] = { + [0] = { + .start = 0x40500000, + .end = 0x40500000 + 0xfff, + .flags = IORESOURCE_MEM, + }, + [1] = { + .start = IRQ_AC97, + .end = IRQ_AC97, + .flags = IORESOURCE_IRQ, + }, +}; + +static u64 pxa_ac97_dmamask = 0xffffffffUL; + +static struct platform_device pxa27x_device_ac97 = { + .name = "pxa2xx-ac97", + .id = -1, + .dev = { + .dma_mask = &pxa_ac97_dmamask, + .coherent_dma_mask = 0xffffffff, + }, + .num_resources = ARRAY_SIZE(pxa27x_ac97_resources), + .resource = pxa27x_ac97_resources, +}; + +/* + * enable generic access to the base board control CPLDs U6 and U7 + */ +static struct map_desc pcm990_io_desc[] __initdata = { + { + .virtual = PCM990_CTRL_BASE, + .pfn = __phys_to_pfn(PCM990_CTRL_PHYS), + .length = PCM990_CTRL_SIZE, + .type = MT_DEVICE /* CPLD */ + }, { + .virtual = PCM990_CF_PLD_BASE, + .pfn = __phys_to_pfn(PCM990_CF_PLD_PHYS), + .length = PCM990_CF_PLD_SIZE, + .type = MT_DEVICE /* CPLD */ + } +}; + +/* + * system init for baseboard usage. Will be called by pcm027 init. + * + * Add platform devices present on this baseboard and init + * them from CPU side as far as required to use them later on + */ +void __init pcm990_baseboard_init(void) +{ + /* register CPLD access */ + iotable_init(pcm990_io_desc, ARRAY_SIZE(pcm990_io_desc)); + + /* register CPLD's IRQ controller */ + pcm990_init_irq(); + + platform_device_register(&pxa27x_device_ac97); + + /* MMC */ + pxa_set_mci_info(&pcm990_mci_platform_data); + + /* USB host */ + pxa_set_ohci_info(&pcm990_ohci_platform_data); + + printk(KERN_INFO"PCM-990 Evaluation baseboard initialized\n"); +} diff --git a/arch/arm/mach-pxa/pm.c b/arch/arm/mach-pxa/pm.c index a941c71c7d0..039194cbe47 100644 --- a/arch/arm/mach-pxa/pm.c +++ b/arch/arm/mach-pxa/pm.c @@ -38,34 +38,37 @@ int pxa_pm_enter(suspend_state_t state) iwmmxt_task_disable(NULL); #endif - pxa_cpu_pm_fns->save(sleep_save); + /* skip registers saving for standby */ + if (state != PM_SUSPEND_STANDBY) { + pxa_cpu_pm_fns->save(sleep_save); + /* before sleeping, calculate and save a checksum */ + for (i = 0; i < pxa_cpu_pm_fns->save_size - 1; i++) + sleep_save_checksum += sleep_save[i]; + } /* Clear sleep reset status */ RCSR = RCSR_SMR; - /* before sleeping, calculate and save a checksum */ - for (i = 0; i < pxa_cpu_pm_fns->save_size - 1; i++) - sleep_save_checksum += sleep_save[i]; - /* *** go zzz *** */ pxa_cpu_pm_fns->enter(state); cpu_init(); - /* after sleeping, validate the checksum */ - for (i = 0; i < pxa_cpu_pm_fns->save_size - 1; i++) - checksum += sleep_save[i]; + if (state != PM_SUSPEND_STANDBY) { + /* after sleeping, validate the checksum */ + for (i = 0; i < pxa_cpu_pm_fns->save_size - 1; i++) + checksum += sleep_save[i]; - /* if invalid, display message and wait for a hardware reset */ - if (checksum != sleep_save_checksum) { + /* if invalid, display message and wait for a hardware reset */ + if (checksum != sleep_save_checksum) { #ifdef CONFIG_ARCH_LUBBOCK - LUB_HEXLED = 0xbadbadc5; + LUB_HEXLED = 0xbadbadc5; #endif - while (1) - pxa_cpu_pm_fns->enter(state); + while (1) + pxa_cpu_pm_fns->enter(state); + } + pxa_cpu_pm_fns->restore(sleep_save); } - pxa_cpu_pm_fns->restore(sleep_save); - pr_debug("*** made it back from resume\n"); return 0; diff --git a/arch/arm/mach-pxa/poodle.c b/arch/arm/mach-pxa/poodle.c index 655668d4d0e..dd54496083c 100644 --- a/arch/arm/mach-pxa/poodle.c +++ b/arch/arm/mach-pxa/poodle.c @@ -215,12 +215,10 @@ static int poodle_mci_init(struct device *dev, irq_handler_t poodle_detect_int, err = request_irq(POODLE_IRQ_GPIO_nSD_DETECT, poodle_detect_int, IRQF_DISABLED | IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING, "MMC card detect", data); - if (err) { + if (err) printk(KERN_ERR "poodle_mci_init: MMC/SD: can't request MMC card detect IRQ\n"); - return -1; - } - return 0; + return err; } static void poodle_mci_setpower(struct device *dev, unsigned int vdd) diff --git a/arch/arm/mach-pxa/pxa25x.c b/arch/arm/mach-pxa/pxa25x.c index 006a6e09589..ddd05bf78e0 100644 --- a/arch/arm/mach-pxa/pxa25x.c +++ b/arch/arm/mach-pxa/pxa25x.c @@ -123,12 +123,15 @@ static struct clk pxa25x_clks[] = { INIT_CKEN("UDCCLK", USB, 47923000, 5, &pxa_device_udc.dev), INIT_CKEN("MMCCLK", MMC, 19169000, 0, &pxa_device_mci.dev), INIT_CKEN("I2CCLK", I2C, 31949000, 0, &pxa_device_i2c.dev), + + INIT_CKEN("SSPCLK", SSP, 3686400, 0, &pxa25x_device_ssp.dev), + INIT_CKEN("SSPCLK", NSSP, 3686400, 0, &pxa25x_device_nssp.dev), + INIT_CKEN("SSPCLK", ASSP, 3686400, 0, &pxa25x_device_assp.dev), + /* INIT_CKEN("PWMCLK", PWM0, 3686400, 0, NULL), INIT_CKEN("PWMCLK", PWM0, 3686400, 0, NULL), - INIT_CKEN("SSPCLK", SSP, 3686400, 0, NULL), INIT_CKEN("I2SCLK", I2S, 14745600, 0, NULL), - INIT_CKEN("NSSPCLK", NSSP, 3686400, 0, NULL), */ INIT_CKEN("FICPCLK", FICP, 47923000, 0, NULL), }; @@ -216,8 +219,6 @@ static void pxa25x_cpu_pm_restore(unsigned long *sleep_save) static void pxa25x_cpu_pm_enter(suspend_state_t state) { - CKEN = 0; - switch (state) { case PM_SUSPEND_MEM: /* set resume return address */ @@ -239,6 +240,8 @@ static void __init pxa25x_init_pm(void) { pxa_cpu_pm_fns = &pxa25x_cpu_pm_fns; } +#else +static inline void pxa25x_init_pm(void) {} #endif /* PXA25x: supports wakeup from GPIO0..GPIO15 and RTC alarm @@ -290,16 +293,15 @@ void __init pxa25x_init_irq(void) } static struct platform_device *pxa25x_devices[] __initdata = { - &pxa_device_mci, &pxa_device_udc, - &pxa_device_fb, &pxa_device_ffuart, &pxa_device_btuart, &pxa_device_stuart, - &pxa_device_i2c, &pxa_device_i2s, - &pxa_device_ficp, &pxa_device_rtc, + &pxa25x_device_ssp, + &pxa25x_device_nssp, + &pxa25x_device_assp, }; static int __init pxa25x_init(void) @@ -315,9 +317,9 @@ static int __init pxa25x_init(void) if ((ret = pxa_init_dma(16))) return ret; -#ifdef CONFIG_PM + pxa25x_init_pm(); -#endif + ret = platform_add_devices(pxa25x_devices, ARRAY_SIZE(pxa25x_devices)); } diff --git a/arch/arm/mach-pxa/pxa27x.c b/arch/arm/mach-pxa/pxa27x.c index 57efebdc432..96cf274ec7c 100644 --- a/arch/arm/mach-pxa/pxa27x.c +++ b/arch/arm/mach-pxa/pxa27x.c @@ -21,6 +21,7 @@ #include <asm/irq.h> #include <asm/arch/irqs.h> #include <asm/arch/pxa-regs.h> +#include <asm/arch/pxa2xx-regs.h> #include <asm/arch/ohci.h> #include <asm/arch/pm.h> #include <asm/arch/dma.h> @@ -151,11 +152,12 @@ static struct clk pxa27x_clks[] = { INIT_CKEN("I2CCLK", PWRI2C, 13000000, 0, &pxa27x_device_i2c_power.dev), INIT_CKEN("KBDCLK", KEYPAD, 32768, 0, NULL), + INIT_CKEN("SSPCLK", SSP1, 13000000, 0, &pxa27x_device_ssp1.dev), + INIT_CKEN("SSPCLK", SSP2, 13000000, 0, &pxa27x_device_ssp2.dev), + INIT_CKEN("SSPCLK", SSP3, 13000000, 0, &pxa27x_device_ssp3.dev), + /* INIT_CKEN("PWMCLK", PWM0, 13000000, 0, NULL), - INIT_CKEN("SSPCLK", SSP1, 13000000, 0, NULL), - INIT_CKEN("SSPCLK", SSP2, 13000000, 0, NULL), - INIT_CKEN("SSPCLK", SSP3, 13000000, 0, NULL), INIT_CKEN("MSLCLK", MSL, 48000000, 0, NULL), INIT_CKEN("USIMCLK", USIM, 48000000, 0, NULL), INIT_CKEN("MSTKCLK", MEMSTK, 19500000, 0, NULL), @@ -264,12 +266,6 @@ void pxa27x_cpu_pm_enter(suspend_state_t state) { extern void pxa_cpu_standby(void); - if (state == PM_SUSPEND_STANDBY) - CKEN = (1 << CKEN_MEMC) | (1 << CKEN_OSTIMER) | - (1 << CKEN_LCD) | (1 << CKEN_PWM0); - else - CKEN = (1 << CKEN_MEMC) | (1 << CKEN_OSTIMER); - /* ensure voltage-change sequencer not initiated, which hangs */ PCFR &= ~PCFR_FVC; @@ -305,6 +301,8 @@ static void __init pxa27x_init_pm(void) { pxa_cpu_pm_fns = &pxa27x_cpu_pm_fns; } +#else +static inline void pxa27x_init_pm(void) {} #endif /* PXA27x: Various gpios can issue wakeup events. This logic only @@ -374,37 +372,6 @@ void __init pxa27x_init_irq(void) * 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, - }, -}; - -struct platform_device pxa27x_device_ohci = { - .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, -}; - -void __init pxa_set_ohci_info(struct pxaohci_platform_data *info) -{ - pxa27x_device_ohci.dev.platform_data = info; -} - static struct resource i2c_power_resources[] = { { .start = 0x40f00180, @@ -430,18 +397,16 @@ void __init pxa_set_i2c_power_info(struct i2c_pxa_platform_data *info) } static struct platform_device *devices[] __initdata = { - &pxa_device_mci, &pxa_device_udc, - &pxa_device_fb, &pxa_device_ffuart, &pxa_device_btuart, &pxa_device_stuart, - &pxa_device_i2c, &pxa_device_i2s, - &pxa_device_ficp, &pxa_device_rtc, &pxa27x_device_i2c_power, - &pxa27x_device_ohci, + &pxa27x_device_ssp1, + &pxa27x_device_ssp2, + &pxa27x_device_ssp3, }; static int __init pxa27x_init(void) @@ -452,9 +417,9 @@ static int __init pxa27x_init(void) if ((ret = pxa_init_dma(32))) return ret; -#ifdef CONFIG_PM + pxa27x_init_pm(); -#endif + ret = platform_add_devices(devices, ARRAY_SIZE(devices)); } return ret; diff --git a/arch/arm/mach-pxa/pxa3xx.c b/arch/arm/mach-pxa/pxa3xx.c index 37e93f9ba8f..5cbf057a1b3 100644 --- a/arch/arm/mach-pxa/pxa3xx.c +++ b/arch/arm/mach-pxa/pxa3xx.c @@ -19,6 +19,7 @@ #include <linux/pm.h> #include <linux/platform_device.h> #include <linux/irq.h> +#include <linux/io.h> #include <asm/hardware.h> #include <asm/arch/pxa3xx-regs.h> @@ -189,8 +190,237 @@ static struct clk pxa3xx_clks[] = { PXA3xx_CKEN("I2CCLK", I2C, 32842000, 0, &pxa_device_i2c.dev), PXA3xx_CKEN("UDCCLK", UDC, 48000000, 5, &pxa_device_udc.dev), + PXA3xx_CKEN("USBCLK", USBH, 48000000, 0, &pxa27x_device_ohci.dev), + + PXA3xx_CKEN("SSPCLK", SSP1, 13000000, 0, &pxa27x_device_ssp1.dev), + PXA3xx_CKEN("SSPCLK", SSP2, 13000000, 0, &pxa27x_device_ssp2.dev), + PXA3xx_CKEN("SSPCLK", SSP3, 13000000, 0, &pxa27x_device_ssp3.dev), + PXA3xx_CKEN("SSPCLK", SSP4, 13000000, 0, &pxa3xx_device_ssp4.dev), + + PXA3xx_CKEN("MMCCLK", MMC1, 19500000, 0, &pxa_device_mci.dev), + PXA3xx_CKEN("MMCCLK", MMC2, 19500000, 0, &pxa3xx_device_mci2.dev), + PXA3xx_CKEN("MMCCLK", MMC3, 19500000, 0, &pxa3xx_device_mci3.dev), +}; + +#ifdef CONFIG_PM +#define SLEEP_SAVE_SIZE 4 + +#define ISRAM_START 0x5c000000 +#define ISRAM_SIZE SZ_256K + +static void __iomem *sram; +static unsigned long wakeup_src; + +static void pxa3xx_cpu_pm_save(unsigned long *sleep_save) +{ + pr_debug("PM: CKENA=%08x CKENB=%08x\n", CKENA, CKENB); + + if (CKENA & (1 << CKEN_USBH)) { + printk(KERN_ERR "PM: USB host clock not stopped?\n"); + CKENA &= ~(1 << CKEN_USBH); + } +// CKENA |= 1 << (CKEN_ISC & 31); + + /* + * Low power modes require the HSIO2 clock to be enabled. + */ + CKENB |= 1 << (CKEN_HSIO2 & 31); +} + +static void pxa3xx_cpu_pm_restore(unsigned long *sleep_save) +{ + CKENB &= ~(1 << (CKEN_HSIO2 & 31)); +} + +/* + * Enter a standby mode (S0D1C2 or S0D2C2). Upon wakeup, the dynamic + * memory controller has to be reinitialised, so we place some code + * in the SRAM to perform this function. + * + * We disable FIQs across the standby - otherwise, we might receive a + * FIQ while the SDRAM is unavailable. + */ +static void pxa3xx_cpu_standby(unsigned int pwrmode) +{ + extern const char pm_enter_standby_start[], pm_enter_standby_end[]; + void (*fn)(unsigned int) = (void __force *)(sram + 0x8000); + + memcpy_toio(sram + 0x8000, pm_enter_standby_start, + pm_enter_standby_end - pm_enter_standby_start); + + AD2D0SR = ~0; + AD2D1SR = ~0; + AD2D0ER = wakeup_src; + AD2D1ER = 0; + ASCR = ASCR; + ARSR = ARSR; + + local_fiq_disable(); + fn(pwrmode); + local_fiq_enable(); + + AD2D0ER = 0; + AD2D1ER = 0; + + printk("PM: AD2D0SR=%08x ASCR=%08x\n", AD2D0SR, ASCR); +} + +static void pxa3xx_cpu_pm_enter(suspend_state_t state) +{ + /* + * Don't sleep if no wakeup sources are defined + */ + if (wakeup_src == 0) + return; + + switch (state) { + case PM_SUSPEND_STANDBY: + pxa3xx_cpu_standby(PXA3xx_PM_S0D2C2); + break; + + case PM_SUSPEND_MEM: + break; + } +} + +static int pxa3xx_cpu_pm_valid(suspend_state_t state) +{ + return state == PM_SUSPEND_MEM || state == PM_SUSPEND_STANDBY; +} + +static struct pxa_cpu_pm_fns pxa3xx_cpu_pm_fns = { + .save_size = SLEEP_SAVE_SIZE, + .save = pxa3xx_cpu_pm_save, + .restore = pxa3xx_cpu_pm_restore, + .valid = pxa3xx_cpu_pm_valid, + .enter = pxa3xx_cpu_pm_enter, }; +static void __init pxa3xx_init_pm(void) +{ + sram = ioremap(ISRAM_START, ISRAM_SIZE); + if (!sram) { + printk(KERN_ERR "Unable to map ISRAM: disabling standby/suspend\n"); + return; + } + + /* + * Since we copy wakeup code into the SRAM, we need to ensure + * that it is preserved over the low power modes. Note: bit 8 + * is undocumented in the developer manual, but must be set. + */ + AD1R |= ADXR_L2 | ADXR_R0; + AD2R |= ADXR_L2 | ADXR_R0; + AD3R |= ADXR_L2 | ADXR_R0; + + /* + * Clear the resume enable registers. + */ + AD1D0ER = 0; + AD2D0ER = 0; + AD2D1ER = 0; + AD3ER = 0; + + pxa_cpu_pm_fns = &pxa3xx_cpu_pm_fns; +} + +static int pxa3xx_set_wake(unsigned int irq, unsigned int on) +{ + unsigned long flags, mask = 0; + + switch (irq) { + case IRQ_SSP3: + mask = ADXER_MFP_WSSP3; + break; + case IRQ_MSL: + mask = ADXER_WMSL0; + break; + case IRQ_USBH2: + case IRQ_USBH1: + mask = ADXER_WUSBH; + break; + case IRQ_KEYPAD: + mask = ADXER_WKP; + break; + case IRQ_AC97: + mask = ADXER_MFP_WAC97; + break; + case IRQ_USIM: + mask = ADXER_WUSIM0; + break; + case IRQ_SSP2: + mask = ADXER_MFP_WSSP2; + break; + case IRQ_I2C: + mask = ADXER_MFP_WI2C; + break; + case IRQ_STUART: + mask = ADXER_MFP_WUART3; + break; + case IRQ_BTUART: + mask = ADXER_MFP_WUART2; + break; + case IRQ_FFUART: + mask = ADXER_MFP_WUART1; + break; + case IRQ_MMC: + mask = ADXER_MFP_WMMC1; + break; + case IRQ_SSP: + mask = ADXER_MFP_WSSP1; + break; + case IRQ_RTCAlrm: + mask = ADXER_WRTC; + break; + case IRQ_SSP4: + mask = ADXER_MFP_WSSP4; + break; + case IRQ_TSI: + mask = ADXER_WTSI; + break; + case IRQ_USIM2: + mask = ADXER_WUSIM1; + break; + case IRQ_MMC2: + mask = ADXER_MFP_WMMC2; + break; + case IRQ_NAND: + mask = ADXER_MFP_WFLASH; + break; + case IRQ_USB2: + mask = ADXER_WUSB2; + break; + case IRQ_WAKEUP0: + mask = ADXER_WEXTWAKE0; + break; + case IRQ_WAKEUP1: + mask = ADXER_WEXTWAKE1; + break; + case IRQ_MMC3: + mask = ADXER_MFP_GEN12; + break; + } + + local_irq_save(flags); + if (on) + wakeup_src |= mask; + else + wakeup_src &= ~mask; + local_irq_restore(flags); + + return 0; +} + +static void pxa3xx_init_irq_pm(void) +{ + pxa_init_irq_set_wake(pxa3xx_set_wake); +} + +#else +static inline void pxa3xx_init_pm(void) {} +static inline void pxa3xx_init_irq_pm(void) {} +#endif + void __init pxa3xx_init_irq(void) { /* enable CP6 access */ @@ -202,6 +432,7 @@ void __init pxa3xx_init_irq(void) pxa_init_irq_low(); pxa_init_irq_high(); pxa_init_irq_gpio(128); + pxa3xx_init_irq_pm(); } /* @@ -209,16 +440,16 @@ void __init pxa3xx_init_irq(void) */ static struct platform_device *devices[] __initdata = { - &pxa_device_mci, &pxa_device_udc, - &pxa_device_fb, &pxa_device_ffuart, &pxa_device_btuart, &pxa_device_stuart, - &pxa_device_i2c, &pxa_device_i2s, - &pxa_device_ficp, &pxa_device_rtc, + &pxa27x_device_ssp1, + &pxa27x_device_ssp2, + &pxa27x_device_ssp3, + &pxa3xx_device_ssp4, }; static int __init pxa3xx_init(void) @@ -231,6 +462,8 @@ static int __init pxa3xx_init(void) if ((ret = pxa_init_dma(32))) return ret; + pxa3xx_init_pm(); + return platform_add_devices(devices, ARRAY_SIZE(devices)); } return 0; diff --git a/arch/arm/mach-pxa/sharpsl.h b/arch/arm/mach-pxa/sharpsl.h index da4769caaf7..047909a7665 100644 --- a/arch/arm/mach-pxa/sharpsl.h +++ b/arch/arm/mach-pxa/sharpsl.h @@ -26,28 +26,15 @@ void corgi_ssp_set_machinfo(struct corgissp_machinfo *machinfo); /* - * SharpSL Backlight + * SharpSL/Corgi LCD Driver */ -void corgi_bl_set_intensity(int intensity); -void spitz_bl_set_intensity(int intensity); -void akita_bl_set_intensity(int intensity); - - -/* - * SharpSL Touchscreen Driver - */ -unsigned long corgi_get_hsync_len(void); -unsigned long spitz_get_hsync_len(void); -void corgi_put_hsync(void); -void spitz_put_hsync(void); -void corgi_wait_hsync(void); -void spitz_wait_hsync(void); +void corgi_lcdtg_suspend(void); +void corgi_lcdtg_hw_init(int mode); /* * SharpSL Battery/PM Driver */ - #define READ_GPIO_BIT(x) (GPLR(x) & GPIO_bit(x)) /* MAX1111 Channel Definitions */ diff --git a/arch/arm/mach-pxa/sleep.S b/arch/arm/mach-pxa/sleep.S index d0447723b73..14bb4a93ea5 100644 --- a/arch/arm/mach-pxa/sleep.S +++ b/arch/arm/mach-pxa/sleep.S @@ -16,6 +16,7 @@ #include <asm/hardware.h> #include <asm/arch/pxa-regs.h> +#include <asm/arch/pxa2xx-regs.h> #define MDREFR_KDIV 0x200a4000 // all banks #define CCCR_SLEEP 0x00000107 // L=7 2N=2 A=0 PPDIS=0 CPDIS=0 @@ -49,6 +50,7 @@ pxa_cpu_save_sp: str r0, [r1] ldr pc, [sp], #4 +#ifdef CONFIG_PXA27x /* * pxa27x_cpu_suspend() * @@ -104,9 +106,11 @@ ENTRY(pxa27x_cpu_suspend) @ align execution to a cache line b pxa_cpu_do_suspend +#endif +#ifdef CONFIG_PXA25x /* - * pxa27x_cpu_suspend() + * pxa25x_cpu_suspend() * * Forces CPU into sleep state. * @@ -169,6 +173,7 @@ ENTRY(pxa25x_cpu_suspend) mcr p14, 0, r0, c6, c0, 0 orr r0, r0, #2 @ initiate change bit b pxa_cpu_do_suspend +#endif .ltorg .align 5 @@ -208,7 +213,7 @@ pxa_cpu_do_suspend: 20: b 20b @ loop waiting for sleep /* - * cpu_pxa_resume() + * pxa_cpu_resume() * * entry point from bootloader into kernel during resume * diff --git a/arch/arm/mach-pxa/spitz.c b/arch/arm/mach-pxa/spitz.c index 2d78199d24a..5078edeadf9 100644 --- a/arch/arm/mach-pxa/spitz.c +++ b/arch/arm/mach-pxa/spitz.c @@ -271,6 +271,55 @@ static struct platform_device spitzled_device = { /* * Spitz Touch Screen Device */ + +static unsigned long (*get_hsync_invperiod)(struct device *dev); + +static void inline sharpsl_wait_sync(int gpio) +{ + while((GPLR(gpio) & GPIO_bit(gpio)) == 0); + while((GPLR(gpio) & GPIO_bit(gpio)) != 0); +} + +static struct device *spitz_pxafb_dev; + +static int is_pxafb_device(struct device * dev, void * data) +{ + struct platform_device *pdev = container_of(dev, struct platform_device, dev); + + return (strncmp(pdev->name, "pxa2xx-fb", 9) == 0); +} + +static unsigned long spitz_get_hsync_invperiod(void) +{ +#ifdef CONFIG_FB_PXA + if (!spitz_pxafb_dev) { + spitz_pxafb_dev = bus_find_device(&platform_bus_type, NULL, NULL, is_pxafb_device); + if (!spitz_pxafb_dev) + return 0; + } + if (!get_hsync_invperiod) + get_hsync_invperiod = symbol_get(pxafb_get_hsync_time); + if (!get_hsync_invperiod) +#endif + return 0; + + return get_hsync_invperiod(spitz_pxafb_dev); +} + +static void spitz_put_hsync(void) +{ + put_device(spitz_pxafb_dev); + if (get_hsync_invperiod) + symbol_put(pxafb_get_hsync_time); + spitz_pxafb_dev = NULL; + get_hsync_invperiod = NULL; +} + +static void spitz_wait_hsync(void) +{ + sharpsl_wait_sync(SPITZ_GPIO_HSYNC); +} + static struct resource spitzts_resources[] = { [0] = { .start = SPITZ_IRQ_GPIO_TP_INT, @@ -280,9 +329,9 @@ static struct resource spitzts_resources[] = { }; static struct corgits_machinfo spitz_ts_machinfo = { - .get_hsync_len = spitz_get_hsync_len, - .put_hsync = spitz_put_hsync, - .wait_hsync = spitz_wait_hsync, + .get_hsync_invperiod = spitz_get_hsync_invperiod, + .put_hsync = spitz_put_hsync, + .wait_hsync = spitz_wait_hsync, }; static struct platform_device spitzts_device = { @@ -325,12 +374,10 @@ static int spitz_mci_init(struct device *dev, irq_handler_t spitz_detect_int, vo err = request_irq(SPITZ_IRQ_GPIO_nSD_DETECT, spitz_detect_int, IRQF_DISABLED | IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING, "MMC card detect", data); - if (err) { + if (err) printk(KERN_ERR "spitz_mci_init: MMC/SD: can't request MMC card detect IRQ\n"); - return -1; - } - return 0; + return err; } static void spitz_mci_setpower(struct device *dev, unsigned int vdd) @@ -423,6 +470,14 @@ static struct pxaficp_platform_data spitz_ficp_platform_data = { * Spitz PXA Framebuffer */ +static void spitz_lcd_power(int on, struct fb_var_screeninfo *var) +{ + if (on) + corgi_lcdtg_hw_init(var->xres); + else + corgi_lcdtg_suspend(); +} + static struct pxafb_mode_info spitz_pxafb_modes[] = { { .pixclock = 19231, @@ -520,6 +575,27 @@ static void __init common_init(void) set_pxa_fb_info(&spitz_pxafb_info); } +#if defined(CONFIG_MACH_SPITZ) || defined(CONFIG_MACH_BORZOI) +static void spitz_bl_set_intensity(int intensity) +{ + if (intensity > 0x10) + intensity += 0x10; + + /* Bits 0-4 are accessed via the SSP interface */ + corgi_ssp_blduty_set(intensity & 0x1f); + + /* Bit 5 is via SCOOP */ + if (intensity & 0x0020) + reset_scoop_gpio(&spitzscoop2_device.dev, SPITZ_SCP2_BACKLIGHT_CONT); + else + set_scoop_gpio(&spitzscoop2_device.dev, SPITZ_SCP2_BACKLIGHT_CONT); + + if (intensity) + set_scoop_gpio(&spitzscoop2_device.dev, SPITZ_SCP2_BACKLIGHT_ON); + else + reset_scoop_gpio(&spitzscoop2_device.dev, SPITZ_SCP2_BACKLIGHT_ON); +} + static void __init spitz_init(void) { platform_scoop_config = &spitz_pcmcia_config; @@ -530,6 +606,7 @@ static void __init spitz_init(void) platform_device_register(&spitzscoop2_device); } +#endif #ifdef CONFIG_MACH_AKITA /* @@ -542,6 +619,26 @@ struct platform_device akitaioexp_device = { EXPORT_SYMBOL_GPL(akitaioexp_device); +static void akita_bl_set_intensity(int intensity) +{ + if (intensity > 0x10) + intensity += 0x10; + + /* Bits 0-4 are accessed via the SSP interface */ + corgi_ssp_blduty_set(intensity & 0x1f); + + /* Bit 5 is via IO-Expander */ + if (intensity & 0x0020) + akita_reset_ioexp(&akitaioexp_device.dev, AKITA_IOEXP_BACKLIGHT_CONT); + else + akita_set_ioexp(&akitaioexp_device.dev, AKITA_IOEXP_BACKLIGHT_CONT); + + if (intensity) + akita_set_ioexp(&akitaioexp_device.dev, AKITA_IOEXP_BACKLIGHT_ON); + else + akita_reset_ioexp(&akitaioexp_device.dev, AKITA_IOEXP_BACKLIGHT_ON); +} + static void __init akita_init(void) { spitz_ficp_platform_data.transceiver_mode = akita_irda_transceiver_mode; @@ -558,7 +655,6 @@ static void __init akita_init(void) } #endif - static void __init fixup_spitz(struct machine_desc *desc, struct tag *tags, char **cmdline, struct meminfo *mi) { diff --git a/arch/arm/mach-pxa/ssp.c b/arch/arm/mach-pxa/ssp.c index b2eb38543d1..00af7f2fed6 100644 --- a/arch/arm/mach-pxa/ssp.c +++ b/arch/arm/mach-pxa/ssp.c @@ -32,45 +32,27 @@ #include <linux/ioport.h> #include <linux/init.h> #include <linux/mutex.h> +#include <linux/clk.h> +#include <linux/err.h> +#include <linux/platform_device.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 +#include <asm/arch/regs-ssp.h> #define TIMEOUT 100000 -struct ssp_info_ { - int irq; - u32 clock; -}; - -/* - * SSP port clock and IRQ settings - */ -static const struct ssp_info_ ssp_info[PXA_SSP_PORTS] = { -#if defined (CONFIG_PXA27x) - {IRQ_SSP, CKEN_SSP1}, - {IRQ_SSP2, CKEN_SSP2}, - {IRQ_SSP3, CKEN_SSP3}, -#else - {IRQ_SSP, CKEN_SSP}, - {IRQ_NSSP, CKEN_NSSP}, - {IRQ_ASSP, CKEN_ASSP}, -#endif -}; - -static DEFINE_MUTEX(mutex); -static int use_count[PXA_SSP_PORTS] = {0, 0, 0}; - static irqreturn_t ssp_interrupt(int irq, void *dev_id) { struct ssp_dev *dev = dev_id; - unsigned int status = SSSR_P(dev->port); + struct ssp_device *ssp = dev->ssp; + unsigned int status; - SSSR_P(dev->port) = status; /* clear status bits */ + status = __raw_readl(ssp->mmio_base + SSSR); + __raw_writel(status, ssp->mmio_base + SSSR); if (status & SSSR_ROR) printk(KERN_WARNING "SSP(%d): receiver overrun\n", dev->port); @@ -99,15 +81,16 @@ static irqreturn_t ssp_interrupt(int irq, void *dev_id) */ int ssp_write_word(struct ssp_dev *dev, u32 data) { + struct ssp_device *ssp = dev->ssp; int timeout = TIMEOUT; - while (!(SSSR_P(dev->port) & SSSR_TNF)) { + while (!(__raw_readl(ssp->mmio_base + SSSR) & SSSR_TNF)) { if (!--timeout) return -ETIMEDOUT; cpu_relax(); } - SSDR_P(dev->port) = data; + __raw_writel(data, ssp->mmio_base + SSDR); return 0; } @@ -129,15 +112,16 @@ int ssp_write_word(struct ssp_dev *dev, u32 data) */ int ssp_read_word(struct ssp_dev *dev, u32 *data) { + struct ssp_device *ssp = dev->ssp; int timeout = TIMEOUT; - while (!(SSSR_P(dev->port) & SSSR_RNE)) { + while (!(__raw_readl(ssp->mmio_base + SSSR) & SSSR_RNE)) { if (!--timeout) return -ETIMEDOUT; cpu_relax(); } - *data = SSDR_P(dev->port); + *data = __raw_readl(ssp->mmio_base + SSDR); return 0; } @@ -151,17 +135,28 @@ int ssp_read_word(struct ssp_dev *dev, u32 *data) */ int ssp_flush(struct ssp_dev *dev) { + struct ssp_device *ssp = dev->ssp; int timeout = TIMEOUT * 2; + /* ensure TX FIFO is empty instead of not full */ + if (cpu_is_pxa3xx()) { + while (__raw_readl(ssp->mmio_base + SSSR) & 0xf00) { + if (!--timeout) + return -ETIMEDOUT; + cpu_relax(); + } + timeout = TIMEOUT * 2; + } + do { - while (SSSR_P(dev->port) & SSSR_RNE) { + while (__raw_readl(ssp->mmio_base + SSSR) & SSSR_RNE) { if (!--timeout) return -ETIMEDOUT; - (void) SSDR_P(dev->port); + (void)__raw_readl(ssp->mmio_base + SSDR); } if (!--timeout) return -ETIMEDOUT; - } while (SSSR_P(dev->port) & SSSR_BSY); + } while (__raw_readl(ssp->mmio_base + SSSR) & SSSR_BSY); return 0; } @@ -173,7 +168,12 @@ int ssp_flush(struct ssp_dev *dev) */ void ssp_enable(struct ssp_dev *dev) { - SSCR0_P(dev->port) |= SSCR0_SSE; + struct ssp_device *ssp = dev->ssp; + uint32_t sscr0; + + sscr0 = __raw_readl(ssp->mmio_base + SSCR0); + sscr0 |= SSCR0_SSE; + __raw_writel(sscr0, ssp->mmio_base + SSCR0); } /** @@ -183,7 +183,12 @@ void ssp_enable(struct ssp_dev *dev) */ void ssp_disable(struct ssp_dev *dev) { - SSCR0_P(dev->port) &= ~SSCR0_SSE; + struct ssp_device *ssp = dev->ssp; + uint32_t sscr0; + + sscr0 = __raw_readl(ssp->mmio_base + SSCR0); + sscr0 &= ~SSCR0_SSE; + __raw_writel(sscr0, ssp->mmio_base + SSCR0); } /** @@ -192,14 +197,16 @@ void ssp_disable(struct ssp_dev *dev) * * Save the configured SSP state for suspend. */ -void ssp_save_state(struct ssp_dev *dev, struct ssp_state *ssp) +void ssp_save_state(struct ssp_dev *dev, struct ssp_state *state) { - ssp->cr0 = SSCR0_P(dev->port); - ssp->cr1 = SSCR1_P(dev->port); - ssp->to = SSTO_P(dev->port); - ssp->psp = SSPSP_P(dev->port); + struct ssp_device *ssp = dev->ssp; + + state->cr0 = __raw_readl(ssp->mmio_base + SSCR0); + state->cr1 = __raw_readl(ssp->mmio_base + SSCR1); + state->to = __raw_readl(ssp->mmio_base + SSTO); + state->psp = __raw_readl(ssp->mmio_base + SSPSP); - SSCR0_P(dev->port) &= ~SSCR0_SSE; + ssp_disable(dev); } /** @@ -208,16 +215,18 @@ void ssp_save_state(struct ssp_dev *dev, struct ssp_state *ssp) * * Restore the SSP configuration saved previously by ssp_save_state. */ -void ssp_restore_state(struct ssp_dev *dev, struct ssp_state *ssp) +void ssp_restore_state(struct ssp_dev *dev, struct ssp_state *state) { - SSSR_P(dev->port) = SSSR_ROR | SSSR_TUR | SSSR_BCE; + struct ssp_device *ssp = dev->ssp; + uint32_t sssr = 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; + __raw_writel(sssr, ssp->mmio_base + SSSR); - SSCR0_P(dev->port) = ssp->cr0; + __raw_writel(state->cr0 & ~SSCR0_SSE, ssp->mmio_base + SSCR0); + __raw_writel(state->cr1, ssp->mmio_base + SSCR1); + __raw_writel(state->to, ssp->mmio_base + SSTO); + __raw_writel(state->psp, ssp->mmio_base + SSPSP); + __raw_writel(state->cr0, ssp->mmio_base + SSCR0); } /** @@ -231,15 +240,17 @@ void ssp_restore_state(struct ssp_dev *dev, struct ssp_state *ssp) */ int ssp_config(struct ssp_dev *dev, u32 mode, u32 flags, u32 psp_flags, u32 speed) { + struct ssp_device *ssp = dev->ssp; + 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; + __raw_writel((dev->speed | dev->mode), ssp->mmio_base + SSCR0); + __raw_writel(dev->flags, ssp->mmio_base + SSCR1); + __raw_writel(dev->psp_flags, ssp->mmio_base + SSPSP); return 0; } @@ -256,44 +267,32 @@ int ssp_config(struct ssp_dev *dev, u32 mode, u32 flags, u32 psp_flags, u32 spee */ int ssp_init(struct ssp_dev *dev, u32 port, u32 init_flags) { + struct ssp_device *ssp; int ret; - if (port > PXA_SSP_PORTS || port == 0) + ssp = ssp_request(port, "SSP"); + if (ssp == NULL) return -ENODEV; - mutex_lock(&mutex); - if (use_count[port - 1]) { - mutex_unlock(&mutex); - return -EBUSY; - } - use_count[port - 1]++; - - if (!request_mem_region(__PREG(SSCR0_P(port)), 0x2c, "SSP")) { - use_count[port - 1]--; - mutex_unlock(&mutex); - return -EBUSY; - } + dev->ssp = ssp; dev->port = port; /* do we need to get irq */ if (!(init_flags & SSP_NO_IRQ)) { - ret = request_irq(ssp_info[port-1].irq, ssp_interrupt, + ret = request_irq(ssp->irq, ssp_interrupt, 0, "SSP", dev); if (ret) goto out_region; - dev->irq = ssp_info[port-1].irq; + dev->irq = ssp->irq; } else dev->irq = 0; /* turn on SSP port clock */ - pxa_set_cken(ssp_info[port-1].clock, 1); - mutex_unlock(&mutex); + clk_enable(ssp->clk); return 0; out_region: - release_mem_region(__PREG(SSCR0_P(port)), 0x2c); - use_count[port - 1]--; - mutex_unlock(&mutex); + ssp_free(ssp); return ret; } @@ -304,23 +303,240 @@ out_region: */ void ssp_exit(struct ssp_dev *dev) { - mutex_lock(&mutex); - SSCR0_P(dev->port) &= ~SSCR0_SSE; + struct ssp_device *ssp = dev->ssp; + + ssp_disable(dev); + free_irq(dev->irq, dev); + clk_disable(ssp->clk); + ssp_free(ssp); +} + +static DEFINE_MUTEX(ssp_lock); +static LIST_HEAD(ssp_list); + +struct ssp_device *ssp_request(int port, const char *label) +{ + struct ssp_device *ssp = NULL; + + mutex_lock(&ssp_lock); + + list_for_each_entry(ssp, &ssp_list, node) { + if (ssp->port_id == port && ssp->use_count == 0) { + ssp->use_count++; + ssp->label = label; + break; + } + } + + mutex_unlock(&ssp_lock); + + if (ssp->port_id != port) + return NULL; + + return ssp; +} +EXPORT_SYMBOL(ssp_request); + +void ssp_free(struct ssp_device *ssp) +{ + mutex_lock(&ssp_lock); + if (ssp->use_count) { + ssp->use_count--; + ssp->label = NULL; + } else + dev_err(&ssp->pdev->dev, "device already free\n"); + mutex_unlock(&ssp_lock); +} +EXPORT_SYMBOL(ssp_free); + +static int __devinit ssp_probe(struct platform_device *pdev, int type) +{ + struct resource *res; + struct ssp_device *ssp; + int ret = 0; + + ssp = kzalloc(sizeof(struct ssp_device), GFP_KERNEL); + if (ssp == NULL) { + dev_err(&pdev->dev, "failed to allocate memory"); + return -ENOMEM; + } + + ssp->clk = clk_get(&pdev->dev, "SSPCLK"); + if (IS_ERR(ssp->clk)) { + ret = PTR_ERR(ssp->clk); + goto err_free; + } + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (res == NULL) { + dev_err(&pdev->dev, "no memory resource defined\n"); + ret = -ENODEV; + goto err_free_clk; + } + + res = request_mem_region(res->start, res->end - res->start + 1, + pdev->name); + if (res == NULL) { + dev_err(&pdev->dev, "failed to request memory resource\n"); + ret = -EBUSY; + goto err_free_clk; + } + + ssp->phys_base = res->start; + + ssp->mmio_base = ioremap(res->start, res->end - res->start + 1); + if (ssp->mmio_base == NULL) { + dev_err(&pdev->dev, "failed to ioremap() registers\n"); + ret = -ENODEV; + goto err_free_mem; + } + + ssp->irq = platform_get_irq(pdev, 0); + if (ssp->irq < 0) { + dev_err(&pdev->dev, "no IRQ resource defined\n"); + ret = -ENODEV; + goto err_free_io; + } + + res = platform_get_resource(pdev, IORESOURCE_DMA, 0); + if (res == NULL) { + dev_err(&pdev->dev, "no SSP RX DRCMR defined\n"); + ret = -ENODEV; + goto err_free_io; + } + ssp->drcmr_rx = res->start; + + res = platform_get_resource(pdev, IORESOURCE_DMA, 1); + if (res == NULL) { + dev_err(&pdev->dev, "no SSP TX DRCMR defined\n"); + ret = -ENODEV; + goto err_free_io; + } + ssp->drcmr_tx = res->start; + + /* PXA2xx/3xx SSP ports starts from 1 and the internal pdev->id + * starts from 0, do a translation here + */ + ssp->port_id = pdev->id + 1; + ssp->use_count = 0; + ssp->type = type; + + mutex_lock(&ssp_lock); + list_add(&ssp->node, &ssp_list); + mutex_unlock(&ssp_lock); + + platform_set_drvdata(pdev, ssp); + return 0; + +err_free_io: + iounmap(ssp->mmio_base); +err_free_mem: + release_mem_region(res->start, res->end - res->start + 1); +err_free_clk: + clk_put(ssp->clk); +err_free: + kfree(ssp); + return ret; +} + +static int __devexit ssp_remove(struct platform_device *pdev) +{ + struct resource *res; + struct ssp_device *ssp; + + ssp = platform_get_drvdata(pdev); + if (ssp == NULL) + return -ENODEV; + + iounmap(ssp->mmio_base); + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + release_mem_region(res->start, res->end - res->start + 1); + + clk_put(ssp->clk); - if (dev->port > PXA_SSP_PORTS || dev->port == 0) { - printk(KERN_WARNING "SSP: tried to close invalid port\n"); - mutex_unlock(&mutex); - return; + mutex_lock(&ssp_lock); + list_del(&ssp->node); + mutex_unlock(&ssp_lock); + + kfree(ssp); + return 0; +} + +static int __devinit pxa25x_ssp_probe(struct platform_device *pdev) +{ + return ssp_probe(pdev, PXA25x_SSP); +} + +static int __devinit pxa25x_nssp_probe(struct platform_device *pdev) +{ + return ssp_probe(pdev, PXA25x_NSSP); +} + +static int __devinit pxa27x_ssp_probe(struct platform_device *pdev) +{ + return ssp_probe(pdev, PXA27x_SSP); +} + +static struct platform_driver pxa25x_ssp_driver = { + .driver = { + .name = "pxa25x-ssp", + }, + .probe = pxa25x_ssp_probe, + .remove = __devexit_p(ssp_remove), +}; + +static struct platform_driver pxa25x_nssp_driver = { + .driver = { + .name = "pxa25x-nssp", + }, + .probe = pxa25x_nssp_probe, + .remove = __devexit_p(ssp_remove), +}; + +static struct platform_driver pxa27x_ssp_driver = { + .driver = { + .name = "pxa27x-ssp", + }, + .probe = pxa27x_ssp_probe, + .remove = __devexit_p(ssp_remove), +}; + +static int __init pxa_ssp_init(void) +{ + int ret = 0; + + ret = platform_driver_register(&pxa25x_ssp_driver); + if (ret) { + printk(KERN_ERR "failed to register pxa25x_ssp_driver"); + return ret; + } + + ret = platform_driver_register(&pxa25x_nssp_driver); + if (ret) { + printk(KERN_ERR "failed to register pxa25x_nssp_driver"); + return ret; + } + + ret = platform_driver_register(&pxa27x_ssp_driver); + if (ret) { + printk(KERN_ERR "failed to register pxa27x_ssp_driver"); + return ret; } - pxa_set_cken(ssp_info[dev->port-1].clock, 0); - if (dev->irq) - free_irq(dev->irq, dev); - release_mem_region(__PREG(SSCR0_P(dev->port)), 0x2c); - use_count[dev->port - 1]--; - mutex_unlock(&mutex); + return ret; +} + +static void __exit pxa_ssp_exit(void) +{ + platform_driver_unregister(&pxa25x_ssp_driver); + platform_driver_unregister(&pxa25x_nssp_driver); + platform_driver_unregister(&pxa27x_ssp_driver); } +arch_initcall(pxa_ssp_init); +module_exit(pxa_ssp_exit); + EXPORT_SYMBOL(ssp_write_word); EXPORT_SYMBOL(ssp_read_word); EXPORT_SYMBOL(ssp_flush); diff --git a/arch/arm/mach-pxa/standby.S b/arch/arm/mach-pxa/standby.S index d774430d02c..167412e6bec 100644 --- a/arch/arm/mach-pxa/standby.S +++ b/arch/arm/mach-pxa/standby.S @@ -17,6 +17,7 @@ .text +#ifdef CONFIG_PXA27x ENTRY(pxa_cpu_standby) ldr r0, =PSSR mov r1, #(PSSR_PH | PSSR_STS) @@ -29,3 +30,85 @@ ENTRY(pxa_cpu_standby) 1: mcr p14, 0, r2, c7, c0, 0 @ put the system into Standby str r1, [r0] @ make sure PSSR_PH/STS are clear mov pc, lr + +#endif + +#ifdef CONFIG_PXA3xx + +#define MDCNFG 0x0000 +#define MDCNFG_DMCEN (1 << 30) +#define DDR_HCAL 0x0060 +#define DDR_HCAL_HCRNG 0x1f +#define DDR_HCAL_HCPROG (1 << 28) +#define DDR_HCAL_HCEN (1 << 31) +#define DMCIER 0x0070 +#define DMCIER_EDLP (1 << 29) +#define DMCISR 0x0078 +#define RCOMP 0x0100 +#define RCOMP_SWEVAL (1 << 31) + +ENTRY(pm_enter_standby_start) + mov r1, #0xf6000000 @ DMEMC_REG_BASE (MDCNFG) + add r1, r1, #0x00100000 + + /* + * Preload the TLB entry for accessing the dynamic memory + * controller registers. Note that page table lookups will + * fail until the dynamic memory controller has been + * reinitialised - and that includes MMU page table walks. + * This also means that only the dynamic memory controller + * can be reliably accessed in the code following standby. + */ + ldr r2, [r1] @ Dummy read MDCNFG + + mcr p14, 0, r0, c7, c0, 0 + .rept 8 + nop + .endr + + ldr r0, [r1, #DDR_HCAL] @ Clear (and wait for) HCEN + bic r0, r0, #DDR_HCAL_HCEN + str r0, [r1, #DDR_HCAL] +1: ldr r0, [r1, #DDR_HCAL] + tst r0, #DDR_HCAL_HCEN + bne 1b + + ldr r0, [r1, #RCOMP] @ Initiate RCOMP + orr r0, r0, #RCOMP_SWEVAL + str r0, [r1, #RCOMP] + + mov r0, #~0 @ Clear interrupts + str r0, [r1, #DMCISR] + + ldr r0, [r1, #DMCIER] @ set DMIER[EDLP] + orr r0, r0, #DMCIER_EDLP + str r0, [r1, #DMCIER] + + ldr r0, [r1, #DDR_HCAL] @ clear HCRNG, set HCPROG, HCEN + bic r0, r0, #DDR_HCAL_HCRNG + orr r0, r0, #DDR_HCAL_HCEN | DDR_HCAL_HCPROG + str r0, [r1, #DDR_HCAL] + +1: ldr r0, [r1, #DMCISR] + tst r0, #DMCIER_EDLP + beq 1b + + ldr r0, [r1, #MDCNFG] @ set MDCNFG[DMCEN] + orr r0, r0, #MDCNFG_DMCEN + str r0, [r1, #MDCNFG] +1: ldr r0, [r1, #MDCNFG] + tst r0, #MDCNFG_DMCEN + beq 1b + + ldr r0, [r1, #DDR_HCAL] @ set DDR_HCAL[HCRNG] + orr r0, r0, #2 @ HCRNG + str r0, [r1, #DDR_HCAL] + + ldr r0, [r1, #DMCIER] @ Clear the interrupt + bic r0, r0, #0x20000000 + str r0, [r1, #DMCIER] + + mov pc, lr +ENTRY(pm_enter_standby_end) + +#endif diff --git a/arch/arm/mach-pxa/time.c b/arch/arm/mach-pxa/time.c index fbfa1920353..7b7c0179795 100644 --- a/arch/arm/mach-pxa/time.c +++ b/arch/arm/mach-pxa/time.c @@ -59,55 +59,17 @@ unsigned long long sched_clock(void) } +#define MIN_OSCR_DELTA 16 + static irqreturn_t pxa_ost0_interrupt(int irq, void *dev_id) { - int next_match; struct clock_event_device *c = dev_id; - if (c->mode == CLOCK_EVT_MODE_ONESHOT) { - /* Disarm the compare/match, signal the event. */ - OIER &= ~OIER_E0; - OSSR = OSSR_M0; - c->event_handler(c); - } else if (c->mode == CLOCK_EVT_MODE_PERIODIC) { - /* Call the event handler as many times as necessary - * to recover missed events, if any (if we update - * OSMR0 and OSCR0 is still ahead of us, we've missed - * the event). As we're dealing with that, re-arm the - * compare/match for the next event. - * - * HACK ALERT: - * - * There's a latency between the instruction that - * writes to OSMR0 and the actual commit to the - * physical hardware, because the CPU doesn't (have - * to) run at bus speed, there's a write buffer - * between the CPU and the bus, etc. etc. So if the - * target OSCR0 is "very close", to the OSMR0 load - * value, the update to OSMR0 might not get to the - * hardware in time and we'll miss that interrupt. - * - * To be safe, if the new OSMR0 is "very close" to the - * target OSCR0 value, we call the event_handler as - * though the event actually happened. According to - * Nico's comment in the previous version of this - * code, experience has shown that 6 OSCR ticks is - * "very close" but he went with 8. We will use 16, - * based on the results of testing on PXA270. - * - * To be doubly sure, we also tell clkevt via - * clockevents_register_device() not to ask for - * anything that might put us "very close". - */ -#define MIN_OSCR_DELTA 16 - do { - OSSR = OSSR_M0; - next_match = (OSMR0 += LATCH); - c->event_handler(c); - } while (((signed long)(next_match - OSCR) <= MIN_OSCR_DELTA) - && (c->mode == CLOCK_EVT_MODE_PERIODIC)); - } + /* Disarm the compare/match, signal the event. */ + OIER &= ~OIER_E0; + OSSR = OSSR_M0; + c->event_handler(c); return IRQ_HANDLED; } @@ -133,14 +95,6 @@ pxa_osmr0_set_mode(enum clock_event_mode mode, struct clock_event_device *dev) unsigned long irqflags; switch (mode) { - case CLOCK_EVT_MODE_PERIODIC: - raw_local_irq_save(irqflags); - OSSR = OSSR_M0; - OIER |= OIER_E0; - OSMR0 = OSCR + LATCH; - raw_local_irq_restore(irqflags); - break; - case CLOCK_EVT_MODE_ONESHOT: raw_local_irq_save(irqflags); OIER &= ~OIER_E0; @@ -158,13 +112,14 @@ pxa_osmr0_set_mode(enum clock_event_mode mode, struct clock_event_device *dev) break; case CLOCK_EVT_MODE_RESUME: + case CLOCK_EVT_MODE_PERIODIC: break; } } static struct clock_event_device ckevt_pxa_osmr0 = { .name = "osmr0", - .features = CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT, + .features = CLOCK_EVT_FEAT_ONESHOT, .shift = 32, .rating = 200, .cpumask = CPU_MASK_CPU0, @@ -214,7 +169,7 @@ static void __init pxa_timer_init(void) ckevt_pxa_osmr0.max_delta_ns = clockevent_delta2ns(0x7fffffff, &ckevt_pxa_osmr0); ckevt_pxa_osmr0.min_delta_ns = - clockevent_delta2ns(MIN_OSCR_DELTA, &ckevt_pxa_osmr0) + 1; + clockevent_delta2ns(MIN_OSCR_DELTA * 2, &ckevt_pxa_osmr0) + 1; cksrc_pxa_oscr0.mult = clocksource_hz2mult(clock_tick_rate, cksrc_pxa_oscr0.shift); @@ -226,7 +181,7 @@ static void __init pxa_timer_init(void) } #ifdef CONFIG_PM -static unsigned long osmr[4], oier; +static unsigned long osmr[4], oier, oscr; static void pxa_timer_suspend(void) { @@ -235,23 +190,26 @@ static void pxa_timer_suspend(void) osmr[2] = OSMR2; osmr[3] = OSMR3; oier = OIER; + oscr = OSCR; } static void pxa_timer_resume(void) { + /* + * Ensure that we have at least MIN_OSCR_DELTA between match + * register 0 and the OSCR, to guarantee that we will receive + * the one-shot timer interrupt. We adjust OSMR0 in preference + * to OSCR to guarantee that OSCR is monotonically incrementing. + */ + if (osmr[0] - oscr < MIN_OSCR_DELTA) + osmr[0] += MIN_OSCR_DELTA; + OSMR0 = osmr[0]; OSMR1 = osmr[1]; OSMR2 = osmr[2]; OSMR3 = osmr[3]; OIER = oier; - - /* - * OSCR0 is the system timer, which has to increase - * monotonically until it rolls over in hardware. The value - * (OSMR0 - LATCH) is OSCR0 at the most recent system tick, - * which is a handy value to restore to OSCR0. - */ - OSCR = OSMR0 - LATCH; + OSCR = oscr; } #else #define pxa_timer_suspend NULL diff --git a/arch/arm/mach-pxa/tosa.c b/arch/arm/mach-pxa/tosa.c index 240fd042083..1919756900f 100644 --- a/arch/arm/mach-pxa/tosa.c +++ b/arch/arm/mach-pxa/tosa.c @@ -184,16 +184,13 @@ static int tosa_mci_init(struct device *dev, irq_handler_t tosa_detect_int, void tosa_mci_platform_data.detect_delay = msecs_to_jiffies(250); - err = request_irq(TOSA_IRQ_GPIO_nSD_DETECT, tosa_detect_int, IRQF_DISABLED, + err = request_irq(TOSA_IRQ_GPIO_nSD_DETECT, tosa_detect_int, + IRQF_DISABLED | IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING, "MMC/SD card detect", data); - if (err) { + if (err) printk(KERN_ERR "tosa_mci_init: MMC/SD: can't request MMC card detect IRQ\n"); - return -1; - } - - set_irq_type(TOSA_IRQ_GPIO_nSD_DETECT, IRQT_BOTHEDGE); - return 0; + return err; } static void tosa_mci_setpower(struct device *dev, unsigned int vdd) diff --git a/arch/arm/mach-pxa/trizeps4.c b/arch/arm/mach-pxa/trizeps4.c index e4ba43bdf85..853fc943375 100644 --- a/arch/arm/mach-pxa/trizeps4.c +++ b/arch/arm/mach-pxa/trizeps4.c @@ -296,11 +296,10 @@ static int trizeps4_mci_init(struct device *dev, irq_handler_t mci_detect_int, v err = request_irq(TRIZEPS4_MMC_IRQ, mci_detect_int, IRQF_DISABLED | IRQF_TRIGGER_RISING, "MMC card detect", data); - if (err) { + if (err) printk(KERN_ERR "trizeps4_mci_init: MMC/SD: can't request MMC card detect IRQ\n"); - return -1; - } - return 0; + + return err; } static void trizeps4_mci_exit(struct device *dev, void *data) diff --git a/arch/arm/mach-pxa/zylonite.c b/arch/arm/mach-pxa/zylonite.c index 743a87b2faa..7731d50dd86 100644 --- a/arch/arm/mach-pxa/zylonite.c +++ b/arch/arm/mach-pxa/zylonite.c @@ -25,9 +25,13 @@ #include <asm/arch/gpio.h> #include <asm/arch/pxafb.h> #include <asm/arch/zylonite.h> +#include <asm/arch/mmc.h> #include "generic.h" +#define MAX_SLOTS 3 +struct platform_mmc_slot zylonite_mmc_slot[MAX_SLOTS]; + int gpio_backlight; int gpio_eth_irq; @@ -43,7 +47,7 @@ static struct resource smc91x_resources[] = { [1] = { .start = -1, /* for run-time assignment */ .end = -1, - .flags = IORESOURCE_IRQ, + .flags = IORESOURCE_IRQ | IORESOURCE_IRQ_HIGHEDGE, } }; @@ -156,6 +160,95 @@ static void __init zylonite_init_lcd(void) static inline void zylonite_init_lcd(void) {} #endif +#if defined(CONFIG_MMC) +static int zylonite_mci_ro(struct device *dev) +{ + struct platform_device *pdev = to_platform_device(dev); + + return gpio_get_value(zylonite_mmc_slot[pdev->id].gpio_wp); +} + +static int zylonite_mci_init(struct device *dev, + irq_handler_t zylonite_detect_int, + void *data) +{ + struct platform_device *pdev = to_platform_device(dev); + int err, cd_irq, gpio_cd, gpio_wp; + + cd_irq = gpio_to_irq(zylonite_mmc_slot[pdev->id].gpio_cd); + gpio_cd = zylonite_mmc_slot[pdev->id].gpio_cd; + gpio_wp = zylonite_mmc_slot[pdev->id].gpio_wp; + + /* + * setup GPIO for Zylonite MMC controller + */ + err = gpio_request(gpio_cd, "mmc card detect"); + if (err) + goto err_request_cd; + gpio_direction_input(gpio_cd); + + err = gpio_request(gpio_wp, "mmc write protect"); + if (err) + goto err_request_wp; + gpio_direction_input(gpio_wp); + + err = request_irq(cd_irq, zylonite_detect_int, + IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING, + "MMC card detect", data); + if (err) { + printk(KERN_ERR "%s: MMC/SD/SDIO: " + "can't request card detect IRQ\n", __func__); + goto err_request_irq; + } + + return 0; + +err_request_irq: + gpio_free(gpio_wp); +err_request_wp: + gpio_free(gpio_cd); +err_request_cd: + return err; +} + +static void zylonite_mci_exit(struct device *dev, void *data) +{ + struct platform_device *pdev = to_platform_device(dev); + int cd_irq, gpio_cd, gpio_wp; + + cd_irq = gpio_to_irq(zylonite_mmc_slot[pdev->id].gpio_cd); + gpio_cd = zylonite_mmc_slot[pdev->id].gpio_cd; + gpio_wp = zylonite_mmc_slot[pdev->id].gpio_wp; + + free_irq(cd_irq, data); + gpio_free(gpio_cd); + gpio_free(gpio_wp); +} + +static struct pxamci_platform_data zylonite_mci_platform_data = { + .detect_delay = 20, + .ocr_mask = MMC_VDD_32_33|MMC_VDD_33_34, + .init = zylonite_mci_init, + .exit = zylonite_mci_exit, + .get_ro = zylonite_mci_ro, +}; + +static struct pxamci_platform_data zylonite_mci2_platform_data = { + .detect_delay = 20, + .ocr_mask = MMC_VDD_32_33|MMC_VDD_33_34, +}; + +static void __init zylonite_init_mmc(void) +{ + pxa_set_mci_info(&zylonite_mci_platform_data); + pxa3xx_set_mci2_info(&zylonite_mci2_platform_data); + if (cpu_is_pxa310()) + pxa3xx_set_mci3_info(&zylonite_mci_platform_data); +} +#else +static inline void zylonite_init_mmc(void) {} +#endif + static void __init zylonite_init(void) { /* board-processor specific initialization */ @@ -171,6 +264,7 @@ static void __init zylonite_init(void) platform_device_register(&smc91x_device); zylonite_init_lcd(); + zylonite_init_mmc(); } MACHINE_START(ZYLONITE, "PXA3xx Platform Development Kit (aka Zylonite)") diff --git a/arch/arm/mach-pxa/zylonite_pxa300.c b/arch/arm/mach-pxa/zylonite_pxa300.c index 1832bc31650..6ac04c09b0e 100644 --- a/arch/arm/mach-pxa/zylonite_pxa300.c +++ b/arch/arm/mach-pxa/zylonite_pxa300.c @@ -53,13 +53,13 @@ static mfp_cfg_t common_mfp_cfg[] __initdata = { /* BTUART */ GPIO111_UART2_RTS, - GPIO112_UART2_RXD, + GPIO112_UART2_RXD | MFP_LPM_EDGE_FALL, GPIO113_UART2_TXD, - GPIO114_UART2_CTS, + GPIO114_UART2_CTS | MFP_LPM_EDGE_BOTH, /* STUART */ GPIO109_UART3_TXD, - GPIO110_UART3_RXD, + GPIO110_UART3_RXD | MFP_LPM_EDGE_FALL, /* AC97 */ GPIO23_AC97_nACRESET, @@ -70,16 +70,16 @@ static mfp_cfg_t common_mfp_cfg[] __initdata = { GPIO28_AC97_SYNC, /* Keypad */ - GPIO107_KP_DKIN_0, - GPIO108_KP_DKIN_1, - GPIO115_KP_MKIN_0, - GPIO116_KP_MKIN_1, - GPIO117_KP_MKIN_2, - GPIO118_KP_MKIN_3, - GPIO119_KP_MKIN_4, - GPIO120_KP_MKIN_5, - GPIO2_2_KP_MKIN_6, - GPIO3_2_KP_MKIN_7, + GPIO107_KP_DKIN_0 | MFP_LPM_EDGE_BOTH, + GPIO108_KP_DKIN_1 | MFP_LPM_EDGE_BOTH, + GPIO115_KP_MKIN_0 | MFP_LPM_EDGE_BOTH, + GPIO116_KP_MKIN_1 | MFP_LPM_EDGE_BOTH, + GPIO117_KP_MKIN_2 | MFP_LPM_EDGE_BOTH, + GPIO118_KP_MKIN_3 | MFP_LPM_EDGE_BOTH, + GPIO119_KP_MKIN_4 | MFP_LPM_EDGE_BOTH, + GPIO120_KP_MKIN_5 | MFP_LPM_EDGE_BOTH, + GPIO2_2_KP_MKIN_6 | MFP_LPM_EDGE_BOTH, + GPIO3_2_KP_MKIN_7 | MFP_LPM_EDGE_BOTH, GPIO121_KP_MKOUT_0, GPIO122_KP_MKOUT_1, GPIO123_KP_MKOUT_2, @@ -88,16 +88,33 @@ static mfp_cfg_t common_mfp_cfg[] __initdata = { GPIO4_2_KP_MKOUT_5, GPIO5_2_KP_MKOUT_6, GPIO6_2_KP_MKOUT_7, + + /* MMC1 */ + GPIO3_MMC1_DAT0, + GPIO4_MMC1_DAT1 | MFP_LPM_EDGE_BOTH, + GPIO5_MMC1_DAT2, + GPIO6_MMC1_DAT3, + GPIO7_MMC1_CLK, + GPIO8_MMC1_CMD, /* CMD0 for slot 0 */ + GPIO15_GPIO, /* CMD1 default as GPIO for slot 0 */ + + /* MMC2 */ + GPIO9_MMC2_DAT0, + GPIO10_MMC2_DAT1 | MFP_LPM_EDGE_BOTH, + GPIO11_MMC2_DAT2, + GPIO12_MMC2_DAT3, + GPIO13_MMC2_CLK, + GPIO14_MMC2_CMD, }; static mfp_cfg_t pxa300_mfp_cfg[] __initdata = { /* FFUART */ - GPIO30_UART1_RXD, + GPIO30_UART1_RXD | MFP_LPM_EDGE_FALL, GPIO31_UART1_TXD, GPIO32_UART1_CTS, GPIO37_UART1_RTS, GPIO33_UART1_DCD, - GPIO34_UART1_DSR, + GPIO34_UART1_DSR | MFP_LPM_EDGE_FALL, GPIO35_UART1_RI, GPIO36_UART1_DTR, @@ -108,7 +125,7 @@ static mfp_cfg_t pxa300_mfp_cfg[] __initdata = { static mfp_cfg_t pxa310_mfp_cfg[] __initdata = { /* FFUART */ - GPIO99_UART1_RXD, + GPIO99_UART1_RXD | MFP_LPM_EDGE_FALL, GPIO100_UART1_TXD, GPIO101_UART1_CTS, GPIO106_UART1_RTS, @@ -116,6 +133,14 @@ static mfp_cfg_t pxa310_mfp_cfg[] __initdata = { /* Ethernet */ GPIO2_nCS3, GPIO102_GPIO, + + /* MMC3 */ + GPIO7_2_MMC3_DAT0, + GPIO8_2_MMC3_DAT1 | MFP_LPM_EDGE_BOTH, + GPIO9_2_MMC3_DAT2, + GPIO10_2_MMC3_DAT3, + GPIO103_MMC3_CLK, + GPIO105_MMC3_CMD, }; #define NUM_LCD_DETECT_PINS 7 @@ -174,6 +199,10 @@ void __init zylonite_pxa300_init(void) /* GPIO pin assignment */ gpio_backlight = mfp_to_gpio(MFP_PIN_GPIO20); + + /* MMC card detect & write protect for controller 0 */ + zylonite_mmc_slot[0].gpio_cd = EXT_GPIO(0); + zylonite_mmc_slot[0].gpio_wp = EXT_GPIO(2); } if (cpu_is_pxa300()) { @@ -184,5 +213,9 @@ void __init zylonite_pxa300_init(void) if (cpu_is_pxa310()) { pxa3xx_mfp_config(ARRAY_AND_SIZE(pxa310_mfp_cfg)); gpio_eth_irq = mfp_to_gpio(MFP_PIN_GPIO102); + + /* MMC card detect & write protect for controller 2 */ + zylonite_mmc_slot[2].gpio_cd = EXT_GPIO(30); + zylonite_mmc_slot[2].gpio_wp = EXT_GPIO(31); } } diff --git a/arch/arm/mach-pxa/zylonite_pxa320.c b/arch/arm/mach-pxa/zylonite_pxa320.c index 94c715808b5..dfa79992b8a 100644 --- a/arch/arm/mach-pxa/zylonite_pxa320.c +++ b/arch/arm/mach-pxa/zylonite_pxa320.c @@ -51,11 +51,11 @@ static mfp_cfg_t mfp_cfg[] __initdata = { GPIO17_2_LCD_BIAS, /* FFUART */ - GPIO41_UART1_RXD, + GPIO41_UART1_RXD | MFP_LPM_EDGE_FALL, GPIO42_UART1_TXD, GPIO43_UART1_CTS, GPIO44_UART1_DCD, - GPIO45_UART1_DSR, + GPIO45_UART1_DSR | MFP_LPM_EDGE_FALL, GPIO46_UART1_RI, GPIO47_UART1_DTR, GPIO48_UART1_RTS, @@ -73,16 +73,16 @@ static mfp_cfg_t mfp_cfg[] __initdata = { GPIO33_I2C_SDA, /* Keypad */ - GPIO105_KP_DKIN_0, - GPIO106_KP_DKIN_1, - GPIO113_KP_MKIN_0, - GPIO114_KP_MKIN_1, - GPIO115_KP_MKIN_2, - GPIO116_KP_MKIN_3, - GPIO117_KP_MKIN_4, - GPIO118_KP_MKIN_5, - GPIO119_KP_MKIN_6, - GPIO120_KP_MKIN_7, + GPIO105_KP_DKIN_0 | MFP_LPM_EDGE_BOTH, + GPIO106_KP_DKIN_1 | MFP_LPM_EDGE_BOTH, + GPIO113_KP_MKIN_0 | MFP_LPM_EDGE_BOTH, + GPIO114_KP_MKIN_1 | MFP_LPM_EDGE_BOTH, + GPIO115_KP_MKIN_2 | MFP_LPM_EDGE_BOTH, + GPIO116_KP_MKIN_3 | MFP_LPM_EDGE_BOTH, + GPIO117_KP_MKIN_4 | MFP_LPM_EDGE_BOTH, + GPIO118_KP_MKIN_5 | MFP_LPM_EDGE_BOTH, + GPIO119_KP_MKIN_6 | MFP_LPM_EDGE_BOTH, + GPIO120_KP_MKIN_7 | MFP_LPM_EDGE_BOTH, GPIO121_KP_MKOUT_0, GPIO122_KP_MKOUT_1, GPIO123_KP_MKOUT_2, @@ -95,6 +95,23 @@ static mfp_cfg_t mfp_cfg[] __initdata = { /* Ethernet */ GPIO4_nCS3, GPIO90_GPIO, + + /* MMC1 */ + GPIO18_MMC1_DAT0, + GPIO19_MMC1_DAT1 | MFP_LPM_EDGE_BOTH, + GPIO20_MMC1_DAT2, + GPIO21_MMC1_DAT3, + GPIO22_MMC1_CLK, + GPIO23_MMC1_CMD,/* CMD0 for slot 0 */ + GPIO31_GPIO, /* CMD1 default as GPIO for slot 0 */ + + /* MMC2 */ + GPIO24_MMC2_DAT0, + GPIO25_MMC2_DAT1 | MFP_LPM_EDGE_BOTH, + GPIO26_MMC2_DAT2, + GPIO27_MMC2_DAT3, + GPIO28_MMC2_CLK, + GPIO29_MMC2_CMD, }; #define NUM_LCD_DETECT_PINS 7 @@ -169,5 +186,9 @@ void __init zylonite_pxa320_init(void) /* GPIO pin assignment */ gpio_backlight = mfp_to_gpio(MFP_PIN_GPIO14); gpio_eth_irq = mfp_to_gpio(MFP_PIN_GPIO9); + + /* MMC card detect & write protect for controller 0 */ + zylonite_mmc_slot[0].gpio_cd = mfp_to_gpio(MFP_PIN_GPIO1); + zylonite_mmc_slot[0].gpio_wp = mfp_to_gpio(MFP_PIN_GPIO5); } } |