1/* 2 * linux/drivers/pcmcia/sa1111_generic.c 3 * 4 * We implement the generic parts of a SA1111 PCMCIA driver. This 5 * basically means we handle everything except controlling the 6 * power. Power is machine specific... 7 */ 8#include <linux/module.h> 9#include <linux/kernel.h> 10#include <linux/ioport.h> 11#include <linux/device.h> 12#include <linux/interrupt.h> 13#include <linux/init.h> 14 15#include <pcmcia/ss.h> 16 17#include <asm/hardware.h> 18#include <asm/hardware/sa1111.h> 19#include <asm/io.h> 20#include <asm/irq.h> 21 22#include "sa1111_generic.h" 23 24static struct pcmcia_irqs irqs[] = { 25 { 0, IRQ_S0_CD_VALID, "SA1111 PCMCIA card detect" }, 26 { 0, IRQ_S0_BVD1_STSCHG, "SA1111 PCMCIA BVD1" }, 27 { 1, IRQ_S1_CD_VALID, "SA1111 CF card detect" }, 28 { 1, IRQ_S1_BVD1_STSCHG, "SA1111 CF BVD1" }, 29}; 30 31int sa1111_pcmcia_hw_init(struct soc_pcmcia_socket *skt) 32{ 33 if (skt->irq == NO_IRQ) 34 skt->irq = skt->nr ? IRQ_S1_READY_NINT : IRQ_S0_READY_NINT; 35 36 return soc_pcmcia_request_irqs(skt, irqs, ARRAY_SIZE(irqs)); 37} 38 39void sa1111_pcmcia_hw_shutdown(struct soc_pcmcia_socket *skt) 40{ 41 soc_pcmcia_free_irqs(skt, irqs, ARRAY_SIZE(irqs)); 42} 43 44void sa1111_pcmcia_socket_state(struct soc_pcmcia_socket *skt, struct pcmcia_state *state) 45{ 46 struct sa1111_dev *sadev = SA1111_DEV(skt->dev); 47 unsigned long status = sa1111_readl(sadev->mapbase + SA1111_PCSR); 48 49 switch (skt->nr) { 50 case 0: 51 state->detect = status & PCSR_S0_DETECT ? 0 : 1; 52 state->ready = status & PCSR_S0_READY ? 1 : 0; 53 state->bvd1 = status & PCSR_S0_BVD1 ? 1 : 0; 54 state->bvd2 = status & PCSR_S0_BVD2 ? 1 : 0; 55 state->wrprot = status & PCSR_S0_WP ? 1 : 0; 56 state->vs_3v = status & PCSR_S0_VS1 ? 0 : 1; 57 state->vs_Xv = status & PCSR_S0_VS2 ? 0 : 1; 58 break; 59 60 case 1: 61 state->detect = status & PCSR_S1_DETECT ? 0 : 1; 62 state->ready = status & PCSR_S1_READY ? 1 : 0; 63 state->bvd1 = status & PCSR_S1_BVD1 ? 1 : 0; 64 state->bvd2 = status & PCSR_S1_BVD2 ? 1 : 0; 65 state->wrprot = status & PCSR_S1_WP ? 1 : 0; 66 state->vs_3v = status & PCSR_S1_VS1 ? 0 : 1; 67 state->vs_Xv = status & PCSR_S1_VS2 ? 0 : 1; 68 break; 69 } 70} 71 72int sa1111_pcmcia_configure_socket(struct soc_pcmcia_socket *skt, const socket_state_t *state) 73{ 74 struct sa1111_dev *sadev = SA1111_DEV(skt->dev); 75 unsigned int pccr_skt_mask, pccr_set_mask, val; 76 unsigned long flags; 77 78 switch (skt->nr) { 79 case 0: 80 pccr_skt_mask = PCCR_S0_RST|PCCR_S0_FLT|PCCR_S0_PWAITEN|PCCR_S0_PSE; 81 break; 82 83 case 1: 84 pccr_skt_mask = PCCR_S1_RST|PCCR_S1_FLT|PCCR_S1_PWAITEN|PCCR_S1_PSE; 85 break; 86 87 default: 88 return -1; 89 } 90 91 pccr_set_mask = 0; 92 93 if (state->Vcc != 0) 94 pccr_set_mask |= PCCR_S0_PWAITEN|PCCR_S1_PWAITEN; 95 if (state->Vcc == 50) 96 pccr_set_mask |= PCCR_S0_PSE|PCCR_S1_PSE; 97 if (state->flags & SS_RESET) 98 pccr_set_mask |= PCCR_S0_RST|PCCR_S1_RST; 99 if (state->flags & SS_OUTPUT_ENA) 100 pccr_set_mask |= PCCR_S0_FLT|PCCR_S1_FLT; 101 102 local_irq_save(flags); 103 val = sa1111_readl(sadev->mapbase + SA1111_PCCR); 104 val &= ~pccr_skt_mask; 105 val |= pccr_set_mask & pccr_skt_mask; 106 sa1111_writel(val, sadev->mapbase + SA1111_PCCR); 107 local_irq_restore(flags); 108 109 return 0; 110} 111 112void sa1111_pcmcia_socket_init(struct soc_pcmcia_socket *skt) 113{ 114 soc_pcmcia_enable_irqs(skt, irqs, ARRAY_SIZE(irqs)); 115} 116 117void sa1111_pcmcia_socket_suspend(struct soc_pcmcia_socket *skt) 118{ 119 soc_pcmcia_disable_irqs(skt, irqs, ARRAY_SIZE(irqs)); 120} 121 122static int pcmcia_probe(struct sa1111_dev *dev) 123{ 124 void __iomem *base; 125 126 if (!request_mem_region(dev->res.start, 512, 127 SA1111_DRIVER_NAME(dev))) 128 return -EBUSY; 129 130 base = dev->mapbase; 131 132 /* 133 * Initialise the suspend state. 134 */ 135 sa1111_writel(PCSSR_S0_SLEEP | PCSSR_S1_SLEEP, base + SA1111_PCSSR); 136 sa1111_writel(PCCR_S0_FLT | PCCR_S1_FLT, base + SA1111_PCCR); 137 138#ifdef CONFIG_SA1100_BADGE4 139 pcmcia_badge4_init(&dev->dev); 140#endif 141#ifdef CONFIG_SA1100_JORNADA720 142 pcmcia_jornada720_init(&dev->dev); 143#endif 144#ifdef CONFIG_ARCH_LUBBOCK 145 pcmcia_lubbock_init(dev); 146#endif 147#ifdef CONFIG_ASSABET_NEPONSET 148 pcmcia_neponset_init(dev); 149#endif 150 return 0; 151} 152 153static int __devexit pcmcia_remove(struct sa1111_dev *dev) 154{ 155 soc_common_drv_pcmcia_remove(&dev->dev); 156 release_mem_region(dev->res.start, 512); 157 return 0; 158} 159 160static int pcmcia_suspend(struct sa1111_dev *dev, pm_message_t state) 161{ 162 return pcmcia_socket_dev_suspend(&dev->dev, state); 163} 164 165static int pcmcia_resume(struct sa1111_dev *dev) 166{ 167 return pcmcia_socket_dev_resume(&dev->dev); 168} 169 170static struct sa1111_driver pcmcia_driver = { 171 .drv = { 172 .name = "sa1111-pcmcia", 173 }, 174 .devid = SA1111_DEVID_PCMCIA, 175 .probe = pcmcia_probe, 176 .remove = __devexit_p(pcmcia_remove), 177 .suspend = pcmcia_suspend, 178 .resume = pcmcia_resume, 179}; 180 181static int __init sa1111_drv_pcmcia_init(void) 182{ 183 return sa1111_driver_register(&pcmcia_driver); 184} 185 186static void __exit sa1111_drv_pcmcia_exit(void) 187{ 188 sa1111_driver_unregister(&pcmcia_driver); 189} 190 191fs_initcall(sa1111_drv_pcmcia_init); 192module_exit(sa1111_drv_pcmcia_exit); 193 194MODULE_DESCRIPTION("SA1111 PCMCIA card socket driver"); 195MODULE_LICENSE("GPL"); 196