diff options
-rw-r--r-- | arch/arm/mach-pxa/e330.c | 36 | ||||
-rw-r--r-- | arch/arm/mach-pxa/e350.c | 36 | ||||
-rw-r--r-- | arch/arm/mach-pxa/e400.c | 65 | ||||
-rw-r--r-- | arch/arm/mach-pxa/e740.c | 46 | ||||
-rw-r--r-- | arch/arm/mach-pxa/e750.c | 36 | ||||
-rw-r--r-- | arch/arm/mach-pxa/e800.c | 30 | ||||
-rw-r--r-- | arch/arm/mach-pxa/eseries.c | 124 | ||||
-rw-r--r-- | arch/arm/mach-pxa/eseries.h | 12 | ||||
-rw-r--r-- | arch/arm/mach-pxa/include/mach/eseries-gpio.h | 4 | ||||
-rw-r--r-- | drivers/pcmcia/Kconfig | 2 | ||||
-rw-r--r-- | drivers/pcmcia/Makefile | 1 | ||||
-rw-r--r-- | drivers/pcmcia/pxa2xx_e740.c | 176 |
12 files changed, 558 insertions, 10 deletions
diff --git a/arch/arm/mach-pxa/e330.c b/arch/arm/mach-pxa/e330.c index d488eded205..1bd7f740427 100644 --- a/arch/arm/mach-pxa/e330.c +++ b/arch/arm/mach-pxa/e330.c @@ -1,5 +1,5 @@ /* - * Hardware definitions for the Toshiba eseries PDAs + * Hardware definitions for the Toshiba e330 PDAs * * Copyright (c) 2003 Ian Molton <spyro@f2s.com> * @@ -12,6 +12,9 @@ #include <linux/kernel.h> #include <linux/init.h> +#include <linux/clk.h> +#include <linux/platform_device.h> +#include <linux/mfd/tc6387xb.h> #include <asm/setup.h> #include <asm/mach/arch.h> @@ -19,13 +22,44 @@ #include <mach/mfp-pxa25x.h> #include <mach/hardware.h> +#include <mach/pxa-regs.h> +#include <mach/eseries-gpio.h> #include <mach/udc.h> #include "generic.h" #include "eseries.h" +#include "clock.h" + +/* -------------------- e330 tc6387xb parameters -------------------- */ + +static struct tc6387xb_platform_data e330_tc6387xb_info = { + .enable = &eseries_tmio_enable, + .disable = &eseries_tmio_disable, + .suspend = &eseries_tmio_suspend, + .resume = &eseries_tmio_resume, +}; + +static struct platform_device e330_tc6387xb_device = { + .name = "tc6387xb", + .id = -1, + .dev = { + .platform_data = &e330_tc6387xb_info, + }, + .num_resources = 2, + .resource = eseries_tmio_resources, +}; + +/* --------------------------------------------------------------- */ + +static struct platform_device *devices[] __initdata = { + &e330_tc6387xb_device, +}; static void __init e330_init(void) { + eseries_register_clks(); + eseries_get_tmio_gpios(); + platform_add_devices(devices, ARRAY_SIZE(devices)); pxa_set_udc_info(&e7xx_udc_mach_info); } diff --git a/arch/arm/mach-pxa/e350.c b/arch/arm/mach-pxa/e350.c index 8ecbc547982..251129391d7 100644 --- a/arch/arm/mach-pxa/e350.c +++ b/arch/arm/mach-pxa/e350.c @@ -1,5 +1,5 @@ /* - * Hardware definitions for the Toshiba eseries PDAs + * Hardware definitions for the Toshiba e350 PDAs * * Copyright (c) 2003 Ian Molton <spyro@f2s.com> * @@ -12,20 +12,54 @@ #include <linux/kernel.h> #include <linux/init.h> +#include <linux/clk.h> +#include <linux/platform_device.h> +#include <linux/mfd/t7l66xb.h> #include <asm/setup.h> #include <asm/mach/arch.h> #include <asm/mach-types.h> #include <mach/mfp-pxa25x.h> +#include <mach/pxa-regs.h> #include <mach/hardware.h> +#include <mach/eseries-gpio.h> #include <mach/udc.h> #include "generic.h" #include "eseries.h" +#include "clock.h" + +/* -------------------- e350 t7l66xb parameters -------------------- */ + +static struct t7l66xb_platform_data e350_t7l66xb_info = { + .irq_base = IRQ_BOARD_START, + .enable = &eseries_tmio_enable, + .suspend = &eseries_tmio_suspend, + .resume = &eseries_tmio_resume, +}; + +static struct platform_device e350_t7l66xb_device = { + .name = "t7l66xb", + .id = -1, + .dev = { + .platform_data = &e350_t7l66xb_info, + }, + .num_resources = 2, + .resource = eseries_tmio_resources, +}; + +/* ---------------------------------------------------------- */ + +static struct platform_device *devices[] __initdata = { + &e350_t7l66xb_device, +}; static void __init e350_init(void) { + eseries_register_clks(); + eseries_get_tmio_gpios(); + platform_add_devices(devices, ARRAY_SIZE(devices)); pxa_set_udc_info(&e7xx_udc_mach_info); } diff --git a/arch/arm/mach-pxa/e400.c b/arch/arm/mach-pxa/e400.c index 544bbaa2062..7716ad0c3b3 100644 --- a/arch/arm/mach-pxa/e400.c +++ b/arch/arm/mach-pxa/e400.c @@ -12,20 +12,26 @@ #include <linux/kernel.h> #include <linux/init.h> +#include <linux/clk.h> +#include <linux/platform_device.h> +#include <linux/mfd/t7l66xb.h> +#include <linux/mtd/nand.h> +#include <linux/mtd/partitions.h> #include <asm/setup.h> #include <asm/mach/arch.h> #include <asm/mach-types.h> -#include <mach/pxa-regs.h> #include <mach/mfp-pxa25x.h> +#include <mach/pxa-regs.h> #include <mach/hardware.h> - +#include <mach/eseries-gpio.h> #include <mach/pxafb.h> #include <mach/udc.h> #include "generic.h" #include "eseries.h" +#include "clock.h" /* ------------------------ E400 LCD definitions ------------------------ */ @@ -65,7 +71,10 @@ static unsigned long e400_pin_config[] __initdata = { GPIO42_BTUART_RXD, GPIO43_BTUART_TXD, GPIO44_BTUART_CTS, - GPIO45_GPIO, /* Used by TMIO for #SUSPEND */ + + /* TMIO controller */ + GPIO19_GPIO, /* t7l66xb #PCLR */ + GPIO45_GPIO, /* t7l66xb #SUSPEND (NOT BTUART!) */ /* wakeup */ GPIO0_GPIO | WAKEUP_ON_EDGE_RISE, @@ -73,10 +82,60 @@ static unsigned long e400_pin_config[] __initdata = { /* ---------------------------------------------------------------------- */ +static struct mtd_partition partition_a = { + .name = "Internal NAND flash", + .offset = 0, + .size = MTDPART_SIZ_FULL, +}; + +static uint8_t scan_ff_pattern[] = { 0xff, 0xff }; + +static struct nand_bbt_descr e400_t7l66xb_nand_bbt = { + .options = 0, + .offs = 4, + .len = 2, + .pattern = scan_ff_pattern +}; + +static struct tmio_nand_data e400_t7l66xb_nand_config = { + .num_partitions = 1, + .partition = &partition_a, + .badblock_pattern = &e400_t7l66xb_nand_bbt, +}; + +static struct t7l66xb_platform_data e400_t7l66xb_info = { + .irq_base = IRQ_BOARD_START, + .enable = &eseries_tmio_enable, + .suspend = &eseries_tmio_suspend, + .resume = &eseries_tmio_resume, + + .nand_data = &e400_t7l66xb_nand_config, +}; + +static struct platform_device e400_t7l66xb_device = { + .name = "t7l66xb", + .id = -1, + .dev = { + .platform_data = &e400_t7l66xb_info, + }, + .num_resources = 2, + .resource = eseries_tmio_resources, +}; + +/* ---------------------------------------------------------- */ + +static struct platform_device *devices[] __initdata = { + &e400_t7l66xb_device, +}; + static void __init e400_init(void) { pxa2xx_mfp_config(ARRAY_AND_SIZE(e400_pin_config)); + /* Fixme - e400 may have a switched clock */ + eseries_register_clks(); + eseries_get_tmio_gpios(); set_pxa_fb_info(&e400_pxafb_mach_info); + platform_add_devices(devices, ARRAY_SIZE(devices)); pxa_set_udc_info(&e7xx_udc_mach_info); } diff --git a/arch/arm/mach-pxa/e740.c b/arch/arm/mach-pxa/e740.c index c57a15b37f0..b00d670b2ea 100644 --- a/arch/arm/mach-pxa/e740.c +++ b/arch/arm/mach-pxa/e740.c @@ -15,6 +15,8 @@ #include <linux/device.h> #include <linux/platform_device.h> #include <linux/fb.h> +#include <linux/clk.h> +#include <linux/mfd/t7l66xb.h> #include <video/w100fb.h> @@ -23,12 +25,16 @@ #include <asm/mach-types.h> #include <mach/mfp-pxa25x.h> +#include <mach/pxa-regs.h> #include <mach/hardware.h> +#include <mach/eseries-gpio.h> #include <mach/udc.h> +#include <mach/irda.h> #include "generic.h" #include "eseries.h" - +#include "clock.h" +#include "devices.h" /* ------------------------ e740 video support --------------------------- */ @@ -116,7 +122,17 @@ static unsigned long e740_pin_config[] __initdata = { GPIO42_BTUART_RXD, GPIO43_BTUART_TXD, GPIO44_BTUART_CTS, - GPIO45_GPIO, /* Used by TMIO for #SUSPEND */ + + /* TMIO controller */ + GPIO19_GPIO, /* t7l66xb #PCLR */ + GPIO45_GPIO, /* t7l66xb #SUSPEND (NOT BTUART!) */ + + /* UDC */ + GPIO13_GPIO, + GPIO3_GPIO, + + /* IrDA */ + GPIO38_GPIO | MFP_LPM_DRIVE_HIGH, /* PC Card */ GPIO8_GPIO, /* CD0 */ @@ -142,17 +158,43 @@ static unsigned long e740_pin_config[] __initdata = { GPIO0_GPIO | WAKEUP_ON_EDGE_RISE, }; +/* -------------------- e740 t7l66xb parameters -------------------- */ + +static struct t7l66xb_platform_data e740_t7l66xb_info = { + .irq_base = IRQ_BOARD_START, + .enable = &eseries_tmio_enable, + .suspend = &eseries_tmio_suspend, + .resume = &eseries_tmio_resume, +}; + +static struct platform_device e740_t7l66xb_device = { + .name = "t7l66xb", + .id = -1, + .dev = { + .platform_data = &e740_t7l66xb_info, + }, + .num_resources = 2, + .resource = eseries_tmio_resources, +}; + /* ----------------------------------------------------------------------- */ static struct platform_device *devices[] __initdata = { &e740_fb_device, + &e740_t7l66xb_device, }; static void __init e740_init(void) { pxa2xx_mfp_config(ARRAY_AND_SIZE(e740_pin_config)); + eseries_register_clks(); + clk_add_alias("CLK_CK48M", &e740_t7l66xb_device.dev, + "UDCCLK", &pxa25x_device_udc.dev), + eseries_get_tmio_gpios(); platform_add_devices(devices, ARRAY_SIZE(devices)); pxa_set_udc_info(&e7xx_udc_mach_info); + e7xx_irda_init(); + pxa_set_ficp_info(&e7xx_ficp_platform_data); } MACHINE_START(E740, "Toshiba e740") diff --git a/arch/arm/mach-pxa/e750.c b/arch/arm/mach-pxa/e750.c index 640e738b85d..84d7c1aac58 100644 --- a/arch/arm/mach-pxa/e750.c +++ b/arch/arm/mach-pxa/e750.c @@ -15,6 +15,7 @@ #include <linux/device.h> #include <linux/platform_device.h> #include <linux/fb.h> +#include <linux/mfd/tc6393xb.h> #include <video/w100fb.h> @@ -23,11 +24,15 @@ #include <asm/mach-types.h> #include <mach/mfp-pxa25x.h> +#include <mach/pxa-regs.h> #include <mach/hardware.h> +#include <mach/eseries-gpio.h> #include <mach/udc.h> +#include <mach/irda.h> #include "generic.h" #include "eseries.h" +#include "clock.h" /* ---------------------- E750 LCD definitions -------------------- */ @@ -100,16 +105,45 @@ static struct platform_device e750_fb_device = { .resource = e750_fb_resources, }; -/* ----------------------------------------------------------------------- */ +/* ----------------- e750 tc6393xb parameters ------------------ */ + +static struct tc6393xb_platform_data e750_tc6393xb_info = { + .irq_base = IRQ_BOARD_START, + .scr_pll2cr = 0x0cc1, + .scr_gper = 0, + .gpio_base = -1, + .suspend = &eseries_tmio_suspend, + .resume = &eseries_tmio_resume, + .enable = &eseries_tmio_enable, + .disable = &eseries_tmio_disable, +}; + +static struct platform_device e750_tc6393xb_device = { + .name = "tc6393xb", + .id = -1, + .dev = { + .platform_data = &e750_tc6393xb_info, + }, + .num_resources = 2, + .resource = eseries_tmio_resources, +}; + +/* ------------------------------------------------------------- */ static struct platform_device *devices[] __initdata = { &e750_fb_device, + &e750_tc6393xb_device, }; static void __init e750_init(void) { + clk_add_alias("CLK_CK3P6MI", &e750_tc6393xb_device.dev, + "GPIO11_CLK", NULL), + eseries_get_tmio_gpios(); platform_add_devices(devices, ARRAY_SIZE(devices)); pxa_set_udc_info(&e7xx_udc_mach_info); + e7xx_irda_init(); + pxa_set_ficp_info(&e7xx_ficp_platform_data); } MACHINE_START(E750, "Toshiba e750") diff --git a/arch/arm/mach-pxa/e800.c b/arch/arm/mach-pxa/e800.c index a293e09bfe2..9a86a426f92 100644 --- a/arch/arm/mach-pxa/e800.c +++ b/arch/arm/mach-pxa/e800.c @@ -15,6 +15,7 @@ #include <linux/device.h> #include <linux/platform_device.h> #include <linux/fb.h> +#include <linux/mfd/tc6393xb.h> #include <video/w100fb.h> @@ -23,12 +24,14 @@ #include <asm/mach-types.h> #include <mach/mfp-pxa25x.h> +#include <mach/pxa-regs.h> #include <mach/hardware.h> #include <mach/eseries-gpio.h> #include <mach/udc.h> #include "generic.h" #include "eseries.h" +#include "clock.h" /* ------------------------ e800 LCD definitions ------------------------- */ @@ -160,14 +163,41 @@ static struct pxa2xx_udc_mach_info e800_udc_mach_info = { .gpio_pullup_inverted = 1 }; +/* ----------------- e800 tc6393xb parameters ------------------ */ + +static struct tc6393xb_platform_data e800_tc6393xb_info = { + .irq_base = IRQ_BOARD_START, + .scr_pll2cr = 0x0cc1, + .scr_gper = 0, + .gpio_base = -1, + .suspend = &eseries_tmio_suspend, + .resume = &eseries_tmio_resume, + .enable = &eseries_tmio_enable, + .disable = &eseries_tmio_disable, +}; + +static struct platform_device e800_tc6393xb_device = { + .name = "tc6393xb", + .id = -1, + .dev = { + .platform_data = &e800_tc6393xb_info, + }, + .num_resources = 2, + .resource = eseries_tmio_resources, +}; + /* ----------------------------------------------------------------------- */ static struct platform_device *devices[] __initdata = { &e800_fb_device, + &e800_tc6393xb_device, }; static void __init e800_init(void) { + clk_add_alias("CLK_CK3P6MI", &e800_tc6393xb_device.dev, + "GPIO11_CLK", NULL), + eseries_get_tmio_gpios(); platform_add_devices(devices, ARRAY_SIZE(devices)); pxa_set_udc_info(&e800_udc_mach_info); } diff --git a/arch/arm/mach-pxa/eseries.c b/arch/arm/mach-pxa/eseries.c index d28849b50a1..dfce7d5b659 100644 --- a/arch/arm/mach-pxa/eseries.c +++ b/arch/arm/mach-pxa/eseries.c @@ -12,6 +12,9 @@ #include <linux/kernel.h> #include <linux/init.h> +#include <linux/gpio.h> +#include <linux/delay.h> +#include <linux/platform_device.h> #include <asm/setup.h> #include <asm/mach/arch.h> @@ -21,8 +24,10 @@ #include <mach/hardware.h> #include <mach/eseries-gpio.h> #include <mach/udc.h> +#include <mach/irda.h> #include "generic.h" +#include "clock.h" /* Only e800 has 128MB RAM */ void __init eseries_fixup(struct machine_desc *desc, @@ -43,3 +48,122 @@ struct pxa2xx_udc_mach_info e7xx_udc_mach_info = { .gpio_pullup_inverted = 1 }; +static void e7xx_irda_transceiver_mode(struct device *dev, int mode) +{ + if (mode & IR_OFF) { + gpio_set_value(GPIO_E7XX_IR_OFF, 1); + pxa2xx_transceiver_mode(dev, mode); + } else { + pxa2xx_transceiver_mode(dev, mode); + gpio_set_value(GPIO_E7XX_IR_OFF, 0); + } +} + +int e7xx_irda_init(void) +{ + int ret; + + ret = gpio_request(GPIO_E7XX_IR_OFF, "IrDA power"); + if (ret) + goto out; + + ret = gpio_direction_output(GPIO_E7XX_IR_OFF, 0); + if (ret) + goto out; + + e7xx_irda_transceiver_mode(NULL, IR_SIRMODE | IR_OFF); +out: + return ret; +} + +static void e7xx_irda_shutdown(struct device *dev) +{ + e7xx_irda_transceiver_mode(dev, IR_SIRMODE | IR_OFF); + gpio_free(GPIO_E7XX_IR_OFF); +} + +struct pxaficp_platform_data e7xx_ficp_platform_data = { + .transceiver_cap = IR_SIRMODE | IR_OFF, + .transceiver_mode = e7xx_irda_transceiver_mode, + .shutdown = e7xx_irda_shutdown, +}; + +int eseries_tmio_enable(struct platform_device *dev) +{ + /* Reset - bring SUSPEND high before PCLR */ + gpio_set_value(GPIO_ESERIES_TMIO_SUSPEND, 0); + gpio_set_value(GPIO_ESERIES_TMIO_PCLR, 0); + msleep(1); + gpio_set_value(GPIO_ESERIES_TMIO_SUSPEND, 1); + msleep(1); + gpio_set_value(GPIO_ESERIES_TMIO_PCLR, 1); + msleep(1); + return 0; +} + +int eseries_tmio_disable(struct platform_device *dev) +{ + gpio_set_value(GPIO_ESERIES_TMIO_SUSPEND, 0); + gpio_set_value(GPIO_ESERIES_TMIO_PCLR, 0); + return 0; +} + +int eseries_tmio_suspend(struct platform_device *dev) +{ + gpio_set_value(GPIO_ESERIES_TMIO_SUSPEND, 0); + return 0; +} + +int eseries_tmio_resume(struct platform_device *dev) +{ + gpio_set_value(GPIO_ESERIES_TMIO_SUSPEND, 1); + msleep(1); + return 0; +} + +void eseries_get_tmio_gpios(void) +{ + gpio_request(GPIO_ESERIES_TMIO_SUSPEND, NULL); + gpio_request(GPIO_ESERIES_TMIO_PCLR, NULL); + gpio_direction_output(GPIO_ESERIES_TMIO_SUSPEND, 0); + gpio_direction_output(GPIO_ESERIES_TMIO_PCLR, 0); +} + +/* TMIO controller uses the same resources on all e-series machines. */ +struct resource eseries_tmio_resources[] = { + [0] = { + .start = PXA_CS4_PHYS, + .end = PXA_CS4_PHYS + 0x1fffff, + .flags = IORESOURCE_MEM, + }, + [1] = { + .start = IRQ_GPIO(GPIO_ESERIES_TMIO_IRQ), + .end = IRQ_GPIO(GPIO_ESERIES_TMIO_IRQ), + .flags = IORESOURCE_IRQ, + }, +}; + +/* Some e-series hardware cannot control the 32K clock */ +static void clk_32k_dummy(struct clk *clk) +{ +} + +static const struct clkops clk_32k_dummy_ops = { + .enable = clk_32k_dummy, + .disable = clk_32k_dummy, +}; + +static struct clk tmio_dummy_clk = { + .ops = &clk_32k_dummy_ops, + .rate = 32768, +}; + +static struct clk_lookup eseries_clkregs[] = { + INIT_CLKREG(&tmio_dummy_clk, NULL, "CLK_CK32K"), +}; + +void eseries_register_clks(void) +{ + clks_register(eseries_clkregs, ARRAY_SIZE(eseries_clkregs)); +} + diff --git a/arch/arm/mach-pxa/eseries.h b/arch/arm/mach-pxa/eseries.h index a83f88d4b6a..5930f5e2a12 100644 --- a/arch/arm/mach-pxa/eseries.h +++ b/arch/arm/mach-pxa/eseries.h @@ -2,3 +2,15 @@ void __init eseries_fixup(struct machine_desc *desc, struct tag *tags, char **cmdline, struct meminfo *mi); extern struct pxa2xx_udc_mach_info e7xx_udc_mach_info; +extern struct pxaficp_platform_data e7xx_ficp_platform_data; +extern int e7xx_irda_init(void); + +extern int eseries_tmio_enable(struct platform_device *dev); +extern int eseries_tmio_disable(struct platform_device *dev); +extern int eseries_tmio_suspend(struct platform_device *dev); +extern int eseries_tmio_resume(struct platform_device *dev); +extern void eseries_get_tmio_gpios(void); +extern struct resource eseries_tmio_resources[]; +extern struct platform_device e300_tc6387xb_device; +extern void eseries_register_clks(void); + diff --git a/arch/arm/mach-pxa/include/mach/eseries-gpio.h b/arch/arm/mach-pxa/include/mach/eseries-gpio.h index 4c90b131027..efbd2aa9ece 100644 --- a/arch/arm/mach-pxa/include/mach/eseries-gpio.h +++ b/arch/arm/mach-pxa/include/mach/eseries-gpio.h @@ -43,8 +43,10 @@ #define GPIO_E800_PCMCIA_PWR1 73 /* e7xx IrDA power control */ -#define GPIO_E7XX_IR_ON 38 +#define GPIO_E7XX_IR_OFF 38 /* ASIC related GPIOs */ #define GPIO_ESERIES_TMIO_IRQ 5 +#define GPIO_ESERIES_TMIO_PCLR 19 +#define GPIO_ESERIES_TMIO_SUSPEND 45 #define GPIO_E800_ANGELX_IRQ 8 diff --git a/drivers/pcmcia/Kconfig b/drivers/pcmcia/Kconfig index 222904411a1..27647354398 100644 --- a/drivers/pcmcia/Kconfig +++ b/drivers/pcmcia/Kconfig @@ -217,7 +217,7 @@ config PCMCIA_PXA2XX depends on ARM && ARCH_PXA && PCMCIA depends on (ARCH_LUBBOCK || MACH_MAINSTONE || PXA_SHARPSL \ || MACH_ARMCORE || ARCH_PXA_PALM || TRIZEPS_PCMCIA \ - || ARCH_VIPER) + || ARCH_VIPER || ARCH_PXA_ESERIES) help Say Y here to include support for the PXA2xx PCMCIA controller diff --git a/drivers/pcmcia/Makefile b/drivers/pcmcia/Makefile index 238629ad7f7..bbac4632722 100644 --- a/drivers/pcmcia/Makefile +++ b/drivers/pcmcia/Makefile @@ -72,5 +72,6 @@ pxa2xx-obj-$(CONFIG_ARCH_VIPER) += pxa2xx_viper.o pxa2xx-obj-$(CONFIG_TRIZEPS_PCMCIA) += pxa2xx_trizeps4.o pxa2xx-obj-$(CONFIG_MACH_PALMTX) += pxa2xx_palmtx.o pxa2xx-obj-$(CONFIG_MACH_PALMLD) += pxa2xx_palmld.o +pxa2xx-obj-$(CONFIG_MACH_E740) += pxa2xx_e740.o obj-$(CONFIG_PCMCIA_PXA2XX) += pxa2xx_core.o $(pxa2xx-obj-y) diff --git a/drivers/pcmcia/pxa2xx_e740.c b/drivers/pcmcia/pxa2xx_e740.c new file mode 100644 index 00000000000..f663a011bf4 --- /dev/null +++ b/drivers/pcmcia/pxa2xx_e740.c @@ -0,0 +1,176 @@ +/* + * Toshiba e740 PCMCIA specific routines. + * + * (c) 2004 Ian Molton <spyro@f2s.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#include <linux/init.h> +#include <linux/module.h> +#include <linux/kernel.h> +#include <linux/errno.h> +#include <linux/gpio.h> +#include <linux/interrupt.h> +#include <linux/platform_device.h> + +#include <mach/hardware.h> +#include <mach/pxa-regs.h> +#include <mach/eseries-gpio.h> + +#include <asm/irq.h> +#include <asm/mach-types.h> + +#include "soc_common.h" + +static struct pcmcia_irqs cd_irqs[] = { + { + .sock = 0, + .irq = IRQ_GPIO(GPIO_E740_PCMCIA_CD0), + .str = "CF card detect" + }, + { + .sock = 1, + .irq = IRQ_GPIO(GPIO_E740_PCMCIA_CD1), + .str = "Wifi switch" + }, +}; + +static int e740_pcmcia_hw_init(struct soc_pcmcia_socket *skt) +{ + skt->irq = skt->nr == 0 ? IRQ_GPIO(GPIO_E740_PCMCIA_RDY0) : + IRQ_GPIO(GPIO_E740_PCMCIA_RDY1); + + return soc_pcmcia_request_irqs(skt, &cd_irqs[skt->nr], 1); +} + +/* + * Release all resources. + */ +static void e740_pcmcia_hw_shutdown(struct soc_pcmcia_socket *skt) +{ + soc_pcmcia_free_irqs(skt, &cd_irqs[skt->nr], 1); +} + +static void e740_pcmcia_socket_state(struct soc_pcmcia_socket *skt, + struct pcmcia_state *state) +{ + if (skt->nr == 0) { + state->detect = gpio_get_value(GPIO_E740_PCMCIA_CD0) ? 0 : 1; + state->ready = gpio_get_value(GPIO_E740_PCMCIA_RDY0) ? 1 : 0; + } else { + state->detect = gpio_get_value(GPIO_E740_PCMCIA_CD1) ? 0 : 1; + state->ready = gpio_get_value(GPIO_E740_PCMCIA_RDY1) ? 1 : 0; + } + + state->vs_3v = 1; + state->bvd1 = 1; + state->bvd2 = 1; + state->wrprot = 0; + state->vs_Xv = 0; +} + +static int e740_pcmcia_configure_socket(struct soc_pcmcia_socket *skt, + const socket_state_t *state) +{ + if (state->flags & SS_RESET) { + if (skt->nr == 0) + gpio_set_value(GPIO_E740_PCMCIA_RST0, 1); + else + gpio_set_value(GPIO_E740_PCMCIA_RST1, 1); + } else { + if (skt->nr == 0) + gpio_set_value(GPIO_E740_PCMCIA_RST0, 0); + else + gpio_set_value(GPIO_E740_PCMCIA_RST1, 0); + } + + switch (state->Vcc) { + case 0: /* Socket off */ + if (skt->nr == 0) + gpio_set_value(GPIO_E740_PCMCIA_PWR0, 0); + else + gpio_set_value(GPIO_E740_PCMCIA_PWR1, 1); + break; + case 50: + case 33: /* socket on */ + if (skt->nr == 0) + gpio_set_value(GPIO_E740_PCMCIA_PWR0, 1); + else + gpio_set_value(GPIO_E740_PCMCIA_PWR1, 0); + break; + default: + printk(KERN_ERR "e740_cs: Unsupported Vcc: %d\n", state->Vcc); + } + + return 0; +} + +/* + * Enable card status IRQs on (re-)initialisation. This can + * be called at initialisation, power management event, or + * pcmcia event. + */ +static void e740_pcmcia_socket_init(struct soc_pcmcia_socket *skt) +{ + soc_pcmcia_enable_irqs(skt, cd_irqs, ARRAY_SIZE(cd_irqs)); +} + +/* + * Disable card status IRQs on suspend. + */ +static void e740_pcmcia_socket_suspend(struct soc_pcmcia_socket *skt) +{ + soc_pcmcia_disable_irqs(skt, cd_irqs, ARRAY_SIZE(cd_irqs)); +} + +static struct pcmcia_low_level e740_pcmcia_ops = { + .owner = THIS_MODULE, + .hw_init = e740_pcmcia_hw_init, + .hw_shutdown = e740_pcmcia_hw_shutdown, + .socket_state = e740_pcmcia_socket_state, + .configure_socket = e740_pcmcia_configure_socket, + .socket_init = e740_pcmcia_socket_init, + .socket_suspend = e740_pcmcia_socket_suspend, + .nr = 2, +}; + +static struct platform_device *e740_pcmcia_device; + +static int __init e740_pcmcia_init(void) +{ + int ret; + + if (!machine_is_e740()) + return -ENODEV; + + e740_pcmcia_device = platform_device_alloc("pxa2xx-pcmcia", -1); + if (!e740_pcmcia_device) + return -ENOMEM; + + ret = platform_device_add_data(e740_pcmcia_device, &e740_pcmcia_ops, + sizeof(e740_pcmcia_ops)); + + if (!ret) + ret = platform_device_add(e740_pcmcia_device); + + if (ret) + platform_device_put(e740_pcmcia_device); + + return ret; +} + +static void __exit e740_pcmcia_exit(void) +{ + platform_device_unregister(e740_pcmcia_device); +} + +module_init(e740_pcmcia_init); +module_exit(e740_pcmcia_exit); + +MODULE_LICENSE("GPL v2"); +MODULE_AUTHOR("Ian Molton <spyro@f2s.com>"); +MODULE_ALIAS("platform:pxa2xx-pcmcia"); +MODULE_DESCRIPTION("e740 PCMCIA platform support"); |