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 <mach/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 24 static 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 31 int 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 39 void sa1111_pcmcia_hw_shutdown(struct soc_pcmcia_socket *skt) 40 { 41 soc_pcmcia_free_irqs(skt, irqs, ARRAY_SIZE(irqs)); 42 } 43 44 void 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 72 int 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 112 void sa1111_pcmcia_socket_init(struct soc_pcmcia_socket *skt) 113 { 114 soc_pcmcia_enable_irqs(skt, irqs, ARRAY_SIZE(irqs)); 115 } 116 117 void sa1111_pcmcia_socket_suspend(struct soc_pcmcia_socket *skt) 118 { 119 soc_pcmcia_disable_irqs(skt, irqs, ARRAY_SIZE(irqs)); 120 } 121 122 static 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 153 static 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 160 static int pcmcia_suspend(struct sa1111_dev *dev, pm_message_t state) 161 { 162 return pcmcia_socket_dev_suspend(&dev->dev, state); 163 } 164 165 static int pcmcia_resume(struct sa1111_dev *dev) 166 { 167 return pcmcia_socket_dev_resume(&dev->dev); 168 } 169 170 static 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 181 static int __init sa1111_drv_pcmcia_init(void) 182 { 183 return sa1111_driver_register(&pcmcia_driver); 184 } 185 186 static void __exit sa1111_drv_pcmcia_exit(void) 187 { 188 sa1111_driver_unregister(&pcmcia_driver); 189 } 190 191 fs_initcall(sa1111_drv_pcmcia_init); 192 module_exit(sa1111_drv_pcmcia_exit); 193 194 MODULE_DESCRIPTION("SA1111 PCMCIA card socket driver"); 195 MODULE_LICENSE("GPL"); 196