Index: linux/drivers/pcmcia/sa1100_collie.c =================================================================== --- /dev/null +++ linux/drivers/pcmcia/sa1100_collie.c @@ -0,0 +1,215 @@ +/* + * drivers/pcmcia/sa1100_collie.c + * + * PCMCIA implementation routines for Collie + * + * May be copied or modified under the terms of the GNU General Public + * License. See linux/COPYING for more information. + * + */ + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#include "sa1100_generic.h" + +static unsigned short keep_vs[2]; +#define NO_KEEP_VS 0x0001 + +static struct pcmcia_irqs irqs[] = { + { 1, COLLIE_IRQ_GPIO_CF_CD, "CF_CD"}, +}; + +static void collie_pcmcia_init_reset(void) +{ + reset_scoop(); + keep_vs[0] = NO_KEEP_VS; +} + +static int collie_pcmcia_hw_init(struct soc_pcmcia_socket *skt) +{ + int ret; + + /* set COLLIE_GPIO_CF_CD & COLLIE_GPIO_CF_IRQ as inputs */ + GPDR &= ~(COLLIE_GPIO_CF_CD|COLLIE_GPIO_CF_IRQ); + + /* Set transition detect */ + set_irq_type(COLLIE_IRQ_GPIO_CF_IRQ, IRQT_FALLING); + + ret = soc_pcmcia_request_irqs(skt, irqs, ARRAY_SIZE(irqs)); + + if (ret) + return ret; + + /* enable interrupt */ + write_scoop_reg(SCOOP_IMR, 0x00C0); + write_scoop_reg(SCOOP_MCR, 0x0101); + keep_vs[0] = keep_vs[1] = NO_KEEP_VS; + + return 0; +} + +static void collie_pcmcia_hw_shutdown(struct soc_pcmcia_socket *skt) +{ + soc_pcmcia_free_irqs(skt, irqs, ARRAY_SIZE(irqs)); + + /* CF_BUS_OFF */ + collie_pcmcia_init_reset(); +} + +static void +collie_pcmcia_socket_state(struct soc_pcmcia_socket *skt, struct pcmcia_state *state) +{ + unsigned short cpr, csr; + + cpr = read_scoop_reg(SCOOP_CPR); + //COLLIE_SCP_REG_CDR = 0x0002; + write_scoop_reg(SCOOP_IRM, 0x00FF); + write_scoop_reg(SCOOP_ISR, 0x0000); + write_scoop_reg(SCOOP_IRM, 0x0000); + csr = read_scoop_reg(SCOOP_CSR); + if( csr & 0x0004 ){ + /* card eject */ + write_scoop_reg(SCOOP_CDR, 0x0000); + keep_vs[0] = NO_KEEP_VS; + } + else if( !(keep_vs[0] & NO_KEEP_VS) ){ + /* keep vs1,vs2 */ + write_scoop_reg(SCOOP_CDR, 0x0000); + csr |= keep_vs[0]; + } + else if( cpr & 0x0003 ){ + /* power on */ + write_scoop_reg(SCOOP_CDR, 0x0000); + keep_vs[0] = (csr & 0x00C0); + } + else{ /* card detect */ + write_scoop_reg(SCOOP_CDR, 0x0002); + } + + state->detect = (csr & 0x0004)? 0:1; + state->ready = (csr & 0x0002)? 1:0; + state->bvd1 = (csr & 0x0010)? 1:0; + state->bvd2 = (csr & 0x0020)? 1:0; + state->wrprot = (csr & 0x0008)? 1:0; + state->vs_3v = (csr & 0x0040)? 0:1; + state->vs_Xv = (csr & 0x0080)? 0:1; + + if( (cpr & 0x0080) && ((cpr & 0x8040) != 0x8040) ){ + printk(KERN_ERR "%s(): CPR=%04X, Low voltage!\n", + __FUNCTION__, cpr); + } + +} + +static int +collie_pcmcia_configure_socket(struct soc_pcmcia_socket *skt, const socket_state_t *state) +{ + unsigned long flags; + unsigned short cpr, ncpr, ccr, nccr, mcr, nmcr, imr, nimr; + + switch( state->Vcc ){ + case 0: break; + case 33: break; + case 50: break; + default: + printk(KERN_ERR "%s(): unrecognized Vcc %u\n", + __FUNCTION__, state->Vcc); + return -1; + } + if( (state->Vpp!=state->Vcc) && (state->Vpp!=0) ){ + printk(KERN_ERR "%s(): CF slot cannot support Vpp %u\n", + __FUNCTION__, state->Vpp); + return -1; + } + + local_irq_save(flags); + + nmcr = (mcr = read_scoop_reg(SCOOP_MCR)) & ~0x0010; + ncpr = (cpr = read_scoop_reg(SCOOP_CPR)) & ~0x0083; + nccr = (ccr = read_scoop_reg(SCOOP_CCR)) & ~0x0080; + nimr = (imr = read_scoop_reg(SCOOP_IMR)) & ~0x003E; + + ncpr |= (state->Vcc == 33) ? 0x0001: + (state->Vcc == 50) ? 0x0002: + 0; + /* the 2.5 tree on linux-cl.bkbits.net had this code + nccr = ((state->flags & SS_RESET) ? (nccr | 0x0080) : (nccr &= ~0x0080)); + ncpr = ((state->flags & SS_OUTPUT_ENA) ? (ncpr | 0x0080) : (ncpr &= ~0x0080)); */ + + nmcr |= (state->flags&SS_IOCARD)? 0x0010: 0; + ncpr |= (state->flags&SS_OUTPUT_ENA)? 0x0080: 0; + nccr |= (state->flags&SS_RESET)? 0x0080: 0; + nimr |= ((skt->status&SS_DETECT) ? 0x0004: 0)| + ((skt->status&SS_READY) ? 0x0002: 0)| + ((skt->status&SS_BATDEAD)? 0x0010: 0)| + ((skt->status&SS_BATWARN)? 0x0020: 0)| + ((skt->status&SS_STSCHG) ? 0x0010: 0)| + ((skt->status&SS_WRPROT) ? 0x0008: 0); + + if (mcr != nmcr) write_scoop_reg(SCOOP_MCR, nmcr); + if (cpr != ncpr) write_scoop_reg(SCOOP_CPR, ncpr); + if (ccr != nccr) write_scoop_reg(SCOOP_CCR, nccr); + if (imr != nimr) write_scoop_reg(SCOOP_IMR, nimr); + + local_irq_restore(flags); + + return 0; +} + +/* + * Enable card status IRQs on (re-)initialisation. This can + * be called at initialisation, power management event, or + * pcmcia event. + */ +static void collie_pcmcia_socket_init(struct soc_pcmcia_socket *skt) +{ + soc_pcmcia_request_irqs(skt, irqs, ARRAY_SIZE(irqs)); + + /* We need to disable SS_OUTPUT_ENA here. */ + write_scoop_reg(SCOOP_CPR, read_scoop_reg(SCOOP_CPR) & ~0x0080) +} + +static void collie_pcmcia_socket_suspend(struct soc_pcmcia_socket *skt) +{ + soc_pcmcia_free_irqs(skt, irqs, ARRAY_SIZE(irqs)); + + /* We need to disable SS_OUTPUT_ENA here. */ + write_scoop_reg(SCOOP_CPR, read_scoop_reg(SCOOP_CPR) & ~0x0080) +} + +struct pcmcia_low_level collie_pcmcia_ops = { + .owner = THIS_MODULE, + + .hw_init = collie_pcmcia_hw_init, + .hw_shutdown = collie_pcmcia_hw_shutdown, + + .socket_state = collie_pcmcia_socket_state, + .configure_socket = collie_pcmcia_configure_socket, + + .socket_init = collie_pcmcia_socket_init, + .socket_suspend = collie_pcmcia_socket_suspend, +}; + + +int __init pcmcia_collie_init(struct device *dev) +{ + int ret = -ENODEV; + + if (machine_is_collie()) + ret = sa11xx_drv_pcmcia_probe(dev, &collie_pcmcia_ops, 1, 1); + + return ret; +} Index: linux/drivers/pcmcia/Makefile =================================================================== --- linux.orig/drivers/pcmcia/Makefile +++ linux/drivers/pcmcia/Makefile @@ -58,6 +58,7 @@ sa1100_cs-$(CONFIG_SA1100_H3600) += sa1100_h3600.o sa1100_cs-$(CONFIG_SA1100_SHANNON) += sa1100_shannon.o sa1100_cs-$(CONFIG_SA1100_SIMPAD) += sa1100_simpad.o +sa1100_cs-$(CONFIG_SA1100_COLLIE) += sa1100_collie.o pxa2xx_cs-$(CONFIG_ARCH_LUBBOCK) += pxa2xx_lubbock.o sa1111_generic.o pxa2xx_cs-$(CONFIG_MACH_MAINSTONE) += pxa2xx_mainstone.o Index: linux/drivers/pcmcia/sa1100_generic.c =================================================================== --- linux.orig/drivers/pcmcia/sa1100_generic.c +++ linux/drivers/pcmcia/sa1100_generic.c @@ -48,6 +48,9 @@ #ifdef CONFIG_SA1100_CERF pcmcia_cerf_init, #endif +#ifdef CONFIG_SA1100_COLLIE + pcmcia_collie_init, +#endif #ifdef CONFIG_SA1100_H3600 pcmcia_h3600_init, #endif Index: linux/drivers/pcmcia/sa1100_generic.h =================================================================== --- linux.orig/drivers/pcmcia/sa1100_generic.h +++ linux/drivers/pcmcia/sa1100_generic.h @@ -8,6 +8,7 @@ extern int pcmcia_assabet_init(struct device *); extern int pcmcia_badge4_init(struct device *); extern int pcmcia_cerf_init(struct device *); +extern int pcmcia_collie_init(struct device *); extern int pcmcia_flexanet_init(struct device *); extern int pcmcia_freebird_init(struct device *); extern int pcmcia_gcplus_init(struct device *);