diff --git a/drivers/pcmcia/Makefile b/drivers/pcmcia/Makefile index 4276965..143f193 100644 --- a/drivers/pcmcia/Makefile +++ b/drivers/pcmcia/Makefile @@ -69,4 +69,5 @@ sa1100_cs-$(CONFIG_SA1100_SIMPAD) += sa pxa2xx_cs-$(CONFIG_ARCH_LUBBOCK) += pxa2xx_lubbock.o sa1111_generic.o pxa2xx_cs-$(CONFIG_MACH_MAINSTONE) += pxa2xx_mainstone.o pxa2xx_cs-$(CONFIG_PXA_SHARPSL) += pxa2xx_sharpsl.o +pxa2xx_cs-$(CONFIG_MACH_TRIZEPS4) += pxa2xx_trizeps4.o diff --git a/drivers/pcmcia/pxa2xx_trizeps4.c b/drivers/pcmcia/pxa2xx_trizeps4.c new file mode 100644 index 0000000..dd219a7 --- /dev/null +++ b/drivers/pcmcia/pxa2xx_trizeps4.c @@ -0,0 +1,234 @@ +/* + * linux/drivers/pcmcia/pxa2xx_trizeps4.c + * + * TRIZEPS4 PCMCIA specific routines. + * + * Author: Jürgen Schindele + * Created: 20 02, 2006 + * Copyright: Jürgen Schindele + * + * 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 +#include +#include +#include +#include +#include + +#include + +#include +#include + +#include +#include + +#include "soc_common.h" + +extern void board_pcmcia_power(int power); + +static struct pcmcia_irqs irqs[] = { + { 0, TRIZEPS4_CD_IRQ, "PCMCIA0 CD" } +}; + +static int trizeps_pcmcia_hw_init(struct soc_pcmcia_socket *skt) +{ + /* we dont have voltage/card/ready detection + * so we dont need interrupts for it + * TODO set default state on power + */ + /* + * Setup default state of GPIO outputs + * before we enable them as outputs. + */ + GPSR(GPIO48_nPOE) = + GPIO_bit(GPIO48_nPOE) | + GPIO_bit(GPIO49_nPWE) | + GPIO_bit(GPIO50_nPIOR) | + GPIO_bit(GPIO51_nPIOW) | + GPIO_bit(GPIO54_nPCE_2); + + GPSR(GPIO102_nPCE_1) = GPIO102_nPCE_1; + + pxa_gpio_mode(GPIO48_nPOE_MD); + pxa_gpio_mode(GPIO49_nPWE_MD); + pxa_gpio_mode(GPIO50_nPIOR_MD); + pxa_gpio_mode(GPIO51_nPIOW_MD); + pxa_gpio_mode(GPIO102_nPCE_1_MD); + pxa_gpio_mode(GPIO54_nPCE_2_MD); + pxa_gpio_mode(GPIO104_pSKTSEL_MD); + pxa_gpio_mode(GPIO55_nPREG_MD); + pxa_gpio_mode(GPIO56_nPWAIT_MD); + pxa_gpio_mode(GPIO57_nIOIS16_MD); + /* card detect */ + pxa_gpio_mode(GPIO_PCD | GPIO_IN); + /* card interrupt */ + pxa_gpio_mode(GPIO_PRDY | GPIO_IN); + + switch (skt->nr) { + case 0: + skt->irq = TRIZEPS4_READY_NINT; + break; + + case 1: + default: + break; + } + /* release the reset of this card */ + /* FIXME Remove Card Reset ?? */ + printk(KERN_DEBUG "%s: sock %d irq %d\n", __FUNCTION__, skt->nr, skt->irq); + + /* supplementory irqs for the socket */ + /* FIXME are interrupts delivered by ConXS Board ?? */ + return soc_pcmcia_request_irqs(skt, irqs, ARRAY_SIZE(irqs)); +} + +static void trizeps_pcmcia_hw_shutdown(struct soc_pcmcia_socket *skt) +{ + /* nothing to do */ +} + +static unsigned long trizeps_pcmcia_status[2]; + +static void trizeps_pcmcia_socket_state(struct soc_pcmcia_socket *skt, struct pcmcia_state *state) +{ + unsigned short status=0, change; +#ifdef CONFIG_MACH_TRIZEPS4_CONXS + status = ConXS_CFSR; + change = (status ^ trizeps_pcmcia_status[skt->nr]) & ConXS_CFSR_BVD_MASK; + + if (change) { + trizeps_pcmcia_status[skt->nr] = status; + if (status & ConXS_CFSR_BVD1) { + /* enable_irq empty */ + } + else { + /* disable_irq empty */ + } + } + + switch (skt->nr) { + case 0: + /* just fill in fix states */ + state->detect = (GPLR(GPIO_PCD) & GPIO_bit(GPIO_PCD)) ? 0 : 1; + state->ready = (GPLR(GPIO_PRDY) & GPIO_bit(GPIO_PRDY)) ? 1 : 0; + state->bvd1 = (status & ConXS_CFSR_BVD1) ? 1 : 0; + state->bvd2 = (status & ConXS_CFSR_BVD2) ? 1 : 0; + state->vs_3v = (status & ConXS_CFSR_VS1) ? 0 : 1; + state->vs_Xv = (status & ConXS_CFSR_VS2) ? 0 : 1; + state->wrprot = 0; /* not available */ + break; + + case 1: + /* on ConXS we only have one slot second is inactive */ + state->detect = 0; + state->ready = 0; + state->bvd1 = 0; + state->bvd2 = 0; + state->vs_3v = 0; + state->vs_Xv = 0; + state->wrprot = 0; + break; + + } +#endif +} + +static int trizeps_pcmcia_configure_socket(struct soc_pcmcia_socket *skt, const socket_state_t *state) +{ + int ret = 0; + unsigned short power = 0; + + /* we do nothing here just check a bit */ + switch (state->Vcc) { + case 0: power &= 0xfc; break; + case 33: power |= ConXS_BCR_S0_VCC_3V3; break; + case 50: + printk(KERN_ERR "%s(): Vcc 5V not supported in socket\n", __FUNCTION__); + break; + default: + printk(KERN_ERR "%s(): bad Vcc %u\n", __FUNCTION__, state->Vcc); + ret = -1; + } + + switch (state->Vpp) { + case 0: power &= 0xf3; break; + case 33: power |= ConXS_BCR_S0_VPP_3V3; break; + case 120: + printk(KERN_ERR "%s(): Vpp 12V not supported in socket\n", __FUNCTION__); + break; + default: + if(state->Vpp != state->Vcc) { + printk(KERN_ERR "%s(): bad Vpp %u\n", __FUNCTION__, state->Vpp); + ret = -1; + } + } + + switch (skt->nr) { + case 0: /* ony have one socket */ + board_pcmcia_power(power); + break; + + case 1: /* do nothing */ + default: + break; + } + + return ret; +} + +static void trizeps_pcmcia_socket_init(struct soc_pcmcia_socket *skt) +{ + /* default is on */ + board_pcmcia_power(0x9); +} + +static void trizeps_pcmcia_socket_suspend(struct soc_pcmcia_socket *skt) +{ +} + +static struct pcmcia_low_level trizeps_pcmcia_ops = { + .owner = THIS_MODULE, + .hw_init = trizeps_pcmcia_hw_init, + .hw_shutdown = trizeps_pcmcia_hw_shutdown, + .socket_state = trizeps_pcmcia_socket_state, + .configure_socket = trizeps_pcmcia_configure_socket, + .socket_init = trizeps_pcmcia_socket_init, + .socket_suspend = trizeps_pcmcia_socket_suspend, + .nr = 2, + .first = 0, +}; + +static struct platform_device *trizeps_pcmcia_device; + +static int __init trizeps_pcmcia_init(void) +{ + int ret; + + trizeps_pcmcia_device = platform_device_alloc("pxa2xx-pcmcia", -1); + if (!trizeps_pcmcia_device) + return -ENOMEM; + + trizeps_pcmcia_device->dev.platform_data = &trizeps_pcmcia_ops; + + ret = platform_device_add(trizeps_pcmcia_device); + + if (ret) + platform_device_put(trizeps_pcmcia_device); + + return ret; +} + +static void __exit trizeps_pcmcia_exit(void) +{ + platform_device_unregister(trizeps_pcmcia_device); +} + +fs_initcall(trizeps_pcmcia_init); +module_exit(trizeps_pcmcia_exit); + +MODULE_LICENSE("GPL");