1/* 2 * 3 * Alchemy Semi Db1x00 boards specific pcmcia routines. 4 * 5 * Copyright 2002 MontaVista Software Inc. 6 * Author: MontaVista Software, Inc. 7 * ppopov@mvista.com or source@mvista.com 8 * 9 * ######################################################################## 10 * 11 * This program is free software; you can distribute it and/or modify it 12 * under the terms of the GNU General Public License (Version 2) as 13 * published by the Free Software Foundation. 14 * 15 * This program is distributed in the hope it will be useful, but WITHOUT 16 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 17 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 18 * for more details. 19 * 20 * You should have received a copy of the GNU General Public License along 21 * with this program; if not, write to the Free Software Foundation, Inc., 22 * 59 Temple Place - Suite 330, Boston MA 02111-1307, USA. 23 * 24 * ######################################################################## 25 * 26 * 27 */ 28#include <linux/module.h> 29#include <linux/init.h> 30#include <linux/config.h> 31#include <linux/delay.h> 32#include <linux/ioport.h> 33#include <linux/kernel.h> 34#include <linux/tqueue.h> 35#include <linux/timer.h> 36#include <linux/mm.h> 37#include <linux/proc_fs.h> 38#include <linux/version.h> 39#include <linux/types.h> 40 41#include <pcmcia/version.h> 42#include <pcmcia/cs_types.h> 43#include <pcmcia/cs.h> 44#include <pcmcia/ss.h> 45#include <pcmcia/bulkmem.h> 46#include <pcmcia/cistpl.h> 47#include <pcmcia/bus_ops.h> 48#include "cs_internal.h" 49 50#include <asm/io.h> 51#include <asm/irq.h> 52#include <asm/system.h> 53 54#include <asm/au1000.h> 55#include <asm/au1000_pcmcia.h> 56 57#include <asm/db1x00.h> 58 59static BCSR * const bcsr = (BCSR *)0xAE000000; 60 61static int db1x00_pcmcia_init(struct pcmcia_init *init) 62{ 63 bcsr->pcmcia = 0; /* turn off power */ 64 au_sync_delay(2); 65 return PCMCIA_NUM_SOCKS; 66} 67 68static int db1x00_pcmcia_shutdown(void) 69{ 70 bcsr->pcmcia = 0; /* turn off power */ 71 au_sync_delay(2); 72 return 0; 73} 74 75static int 76db1x00_pcmcia_socket_state(unsigned sock, struct pcmcia_state *state) 77{ 78 u32 inserted; 79 unsigned char vs; 80 81 if(sock > PCMCIA_MAX_SOCK) return -1; 82 83 state->ready = 0; 84 state->vs_Xv = 0; 85 state->vs_3v = 0; 86 state->detect = 0; 87 88 if (sock == 0) { 89 vs = bcsr->status & 0x3; 90 inserted = !(bcsr->status & (1<<4)); 91 } 92 else { 93 vs = (bcsr->status & 0xC)>>2; 94 inserted = !(bcsr->status & (1<<5)); 95 } 96 97 DEBUG(KERN_DEBUG "db1x00 socket %d: inserted %d, vs %d\n", 98 sock, inserted, vs); 99 100 if (inserted) { 101 switch (vs) { 102 case 0: 103 case 2: 104 state->vs_3v=1; 105 break; 106 case 3: /* 5V */ 107 break; 108 default: 109 /* return without setting 'detect' */ 110 printk(KERN_ERR "db1x00 bad VS (%d)\n", 111 vs); 112 return -1; 113 } 114 state->detect = 1; 115 state->ready = 1; 116 } 117 else { 118 /* if the card was previously inserted and then ejected, 119 * we should turn off power to it 120 */ 121 if ((sock == 0) && (bcsr->pcmcia & BCSR_PCMCIA_PC0RST)) { 122 bcsr->pcmcia &= ~(BCSR_PCMCIA_PC0RST | 123 BCSR_PCMCIA_PC0DRVEN | 124 BCSR_PCMCIA_PC0VPP | 125 BCSR_PCMCIA_PC0VCC); 126 } 127 else if ((sock == 1) && (bcsr->pcmcia & BCSR_PCMCIA_PC1RST)) { 128 bcsr->pcmcia &= ~(BCSR_PCMCIA_PC1RST | 129 BCSR_PCMCIA_PC1DRVEN | 130 BCSR_PCMCIA_PC1VPP | 131 BCSR_PCMCIA_PC1VCC); 132 } 133 } 134 135 state->bvd1=1; 136 state->bvd2=1; 137 state->wrprot=0; 138 return 1; 139} 140 141 142static int db1x00_pcmcia_get_irq_info(struct pcmcia_irq_info *info) 143{ 144 if(info->sock > PCMCIA_MAX_SOCK) return -1; 145 146 if(info->sock == 0) { 147 info->irq = AU1000_GPIO_2; 148 } 149 else 150 info->irq = AU1000_GPIO_5; 151 152 return 0; 153} 154 155 156static int 157db1x00_pcmcia_configure_socket(const struct pcmcia_configure *configure) 158{ 159 u16 pwr; 160 int sock = configure->sock; 161 162 if(sock > PCMCIA_MAX_SOCK) return -1; 163 164 DEBUG(KERN_DEBUG "socket %d Vcc %dV Vpp %dV, reset %d\n", 165 sock, configure->vcc, configure->vpp, configure->reset); 166 167 /* pcmcia reg was set to zero at init time. Be careful when 168 * initializing a socket not to wipe out the settings of the 169 * other socket. 170 */ 171 pwr = bcsr->pcmcia; 172 pwr &= ~(0xf << sock*8); /* clear voltage settings */ 173 174 switch(configure->vcc){ 175 case 0: /* Vcc 0 */ 176 pwr |= SET_VCC_VPP(0,0,sock); 177 break; 178 case 50: /* Vcc 5V */ 179 switch(configure->vpp) { 180 case 0: 181 pwr |= SET_VCC_VPP(2,0,sock); 182 break; 183 case 50: 184 pwr |= SET_VCC_VPP(2,1,sock); 185 break; 186 case 12: 187 pwr |= SET_VCC_VPP(2,2,sock); 188 break; 189 case 33: 190 default: 191 pwr |= SET_VCC_VPP(0,0,sock); 192 printk("%s: bad Vcc/Vpp (%d:%d)\n", 193 __FUNCTION__, 194 configure->vcc, 195 configure->vpp); 196 break; 197 } 198 break; 199 case 33: /* Vcc 3.3V */ 200 switch(configure->vpp) { 201 case 0: 202 pwr |= SET_VCC_VPP(1,0,sock); 203 break; 204 case 12: 205 pwr |= SET_VCC_VPP(1,2,sock); 206 break; 207 case 33: 208 pwr |= SET_VCC_VPP(1,1,sock); 209 break; 210 case 50: 211 default: 212 pwr |= SET_VCC_VPP(0,0,sock); 213 printk("%s: bad Vcc/Vpp (%d:%d)\n", 214 __FUNCTION__, 215 configure->vcc, 216 configure->vpp); 217 break; 218 } 219 break; 220 default: /* what's this ? */ 221 pwr |= SET_VCC_VPP(0,0,sock); 222 printk(KERN_ERR "%s: bad Vcc %d\n", 223 __FUNCTION__, configure->vcc); 224 break; 225 } 226 227 bcsr->pcmcia = pwr; 228 au_sync_delay(300); 229 230 if (sock == 0) { 231 if (!configure->reset) { 232 pwr |= BCSR_PCMCIA_PC0DRVEN; 233 bcsr->pcmcia = pwr; 234 au_sync_delay(300); 235 pwr |= BCSR_PCMCIA_PC0RST; 236 bcsr->pcmcia = pwr; 237 au_sync_delay(100); 238 } 239 else { 240 pwr &= ~(BCSR_PCMCIA_PC0RST | BCSR_PCMCIA_PC0DRVEN); 241 bcsr->pcmcia = pwr; 242 au_sync_delay(100); 243 } 244 } 245 else { 246 if (!configure->reset) { 247 pwr |= BCSR_PCMCIA_PC1DRVEN; 248 bcsr->pcmcia = pwr; 249 au_sync_delay(300); 250 pwr |= BCSR_PCMCIA_PC1RST; 251 bcsr->pcmcia = pwr; 252 au_sync_delay(100); 253 } 254 else { 255 pwr &= ~(BCSR_PCMCIA_PC1RST | BCSR_PCMCIA_PC1DRVEN); 256 bcsr->pcmcia = pwr; 257 au_sync_delay(100); 258 } 259 } 260 return 0; 261} 262 263struct pcmcia_low_level db1x00_pcmcia_ops = { 264 db1x00_pcmcia_init, 265 db1x00_pcmcia_shutdown, 266 db1x00_pcmcia_socket_state, 267 db1x00_pcmcia_get_irq_info, 268 db1x00_pcmcia_configure_socket 269}; 270