Loading...
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 | /* * drivers/pcmcia/sa1100_graphicsclient.c * * PCMCIA implementation routines for Graphics Client Plus * * 9/12/01 Woojung * Turn power OFF at startup * 1/31/2001 Woojung Huh * Fix for GC Plus PCMCIA Reset Problem * 2/27/2001 Woojung Huh [whuh@applieddata.net] * Fix * */ #include <linux/kernel.h> #include <linux/sched.h> #include <linux/delay.h> #include <linux/init.h> #include <asm/hardware.h> #include <asm/mach-types.h> #include <asm/irq.h> #include "sa1100_generic.h" #error This is broken! #define S0_CD_IRQ 60 // Socket 0 Card Detect IRQ #define S0_STS_IRQ 55 // Socket 0 PCMCIA IRQ static volatile unsigned long *PCMCIA_Status = ((volatile unsigned long *) ADS_p2v(_ADS_CS_STATUS)); static volatile unsigned long *PCMCIA_Power = ((volatile unsigned long *) ADS_p2v(_ADS_CS_PR)); static int gcplus_pcmcia_init(struct pcmcia_init *init) { int irq, res; // Reset PCMCIA // Reset Timing for CPLD(U2) version 8001E or later *PCMCIA_Power &= ~ ADS_CS_PR_A_RESET; udelay(12); // 12 uSec *PCMCIA_Power |= ADS_CS_PR_A_RESET; mdelay(30); // 30 mSec // Turn off 5V *PCMCIA_Power &= ~0x03; /* Register interrupts */ irq = S0_CD_IRQ; res = request_irq(irq, init->handler, SA_INTERRUPT, "PCMCIA 0 CD", NULL); if (res < 0) { printk(KERN_ERR "%s: request for IRQ%d failed (%d)\n", __FUNCTION__, irq, res); return res; } return 1; // 1 PCMCIA Slot } static int gcplus_pcmcia_shutdown(void) { /* disable IRQs */ free_irq( S0_CD_IRQ, NULL); /* Shutdown PCMCIA power */ mdelay(2); // 2msec *PCMCIA_Power &= ~0x03; return 0; } static int gcplus_pcmcia_socket_state(struct pcmcia_state_array *state_array){ unsigned long levels; if(state_array->size<1) return -1; memset(state_array->state, 0, (state_array->size)*sizeof(struct pcmcia_state)); levels=*PCMCIA_Status; state_array->state[0].detect=(levels & ADS_CS_ST_A_CD)?1:0; state_array->state[0].ready=(levels & ADS_CS_ST_A_READY)?1:0; state_array->state[0].bvd1= 0; state_array->state[0].bvd2= 0; state_array->state[0].wrprot=0; state_array->state[0].vs_3v=0; state_array->state[0].vs_Xv=0; return 1; } static int gcplus_pcmcia_get_irq_info(struct pcmcia_irq_info *info) { if (info->sock > 1) return -1; if (info->sock == 0) info->irq = S0_STS_IRQ; return 0; } static int gcplus_pcmcia_configure_socket(const struct pcmcia_configure *configure) { unsigned long flags; if(configure->sock>1) return -1; local_irq_save(flags); switch (configure->vcc) { case 0: *PCMCIA_Power &= ~(ADS_CS_PR_A_3V_POWER | ADS_CS_PR_A_5V_POWER); break; case 50: *PCMCIA_Power &= ~(ADS_CS_PR_A_3V_POWER | ADS_CS_PR_A_5V_POWER); *PCMCIA_Power |= ADS_CS_PR_A_5V_POWER; break; case 33: *PCMCIA_Power &= ~(ADS_CS_PR_A_3V_POWER | ADS_CS_PR_A_5V_POWER); *PCMCIA_Power |= ADS_CS_PR_A_3V_POWER; break; default: printk(KERN_ERR "%s(): unrecognized Vcc %u\n", __FUNCTION__, configure->vcc); local_irq_restore(flags); return -1; } /* Silently ignore Vpp, output enable, speaker enable. */ // Reset PCMCIA *PCMCIA_Power &= ~ ADS_CS_PR_A_RESET; udelay(12); *PCMCIA_Power |= ADS_CS_PR_A_RESET; mdelay(30); local_irq_restore(flags); return 0; } static int gcplus_pcmcia_socket_init(int sock) { return 0; } static int gcplus_pcmcia_socket_suspend(int sock) { return 0; } static struct pcmcia_low_level gcplus_pcmcia_ops = { .init = gcplus_pcmcia_init, .shutdown = gcplus_pcmcia_shutdown, .socket_state = gcplus_pcmcia_socket_state, .get_irq_info = gcplus_pcmcia_get_irq_info, .configure_socket = gcplus_pcmcia_configure_socket, .socket_init = gcplus_pcmcia_socket_init, .socket_suspend = gcplus_pcmcia_socket_suspend, }; int __init pcmcia_gcplus_init(void) { int ret = -ENODEV; if (machine_is_gcplus()) ret = sa1100_register_pcmcia(&gcplus_pcmcia_ops); return ret; } void __exit pcmcia_gcplus_exit(void) { sa1100_unregister_pcmcia(&gcplus_pcmcia_ops); } |