patch-2_6_7-vs1_9_1_12
[linux-2.6.git] / drivers / pcmcia / sa1100_graphicsclient.c
1 /*
2  * drivers/pcmcia/sa1100_graphicsclient.c
3  *
4  * PCMCIA implementation routines for Graphics Client Plus
5  *
6  * 9/12/01   Woojung
7  *    Turn power OFF at startup
8  * 1/31/2001 Woojung Huh
9  *    Fix for GC Plus PCMCIA Reset Problem
10  * 2/27/2001 Woojung Huh [whuh@applieddata.net]
11  *    Fix
12  *
13  */
14 #include <linux/module.h>
15 #include <linux/kernel.h>
16 #include <linux/sched.h>
17 #include <linux/delay.h>
18 #include <linux/device.h>
19 #include <linux/init.h>
20
21 #include <asm/hardware.h>
22 #include <asm/mach-types.h>
23 #include <asm/irq.h>
24 #include "sa1100_generic.h"
25
26 #error This is broken!
27
28 #define S0_CD_IRQ               60                              // Socket 0 Card Detect IRQ
29 #define S0_STS_IRQ              55                              // Socket 0 PCMCIA IRQ
30
31 static volatile unsigned long *PCMCIA_Status = 
32                 ((volatile unsigned long *) ADS_p2v(_ADS_CS_STATUS));
33
34 static volatile unsigned long *PCMCIA_Power = 
35                 ((volatile unsigned long *) ADS_p2v(_ADS_CS_PR));
36
37 static struct pcmcia_irqs irqs[] = {
38         { 0, S0_CD_IRQ, "PCMCIA 0 CD" },
39 };
40
41 static int gcplus_pcmcia_init(struct soc_pcmcia_socket *skt)
42 {
43         // Reset PCMCIA
44         // Reset Timing for CPLD(U2) version 8001E or later
45         *PCMCIA_Power &= ~ ADS_CS_PR_A_RESET;
46         udelay(12);                     // 12 uSec
47
48         *PCMCIA_Power |= ADS_CS_PR_A_RESET;
49         mdelay(30);                     // 30 mSec
50
51         // Turn off 5V
52         *PCMCIA_Power &= ~0x03;
53
54         skt->irq = S0_STS_IRQ;
55
56         /* Register interrupts */
57         return soc_pcmcia_request_irqs(skt, irqs, ARRAY_SIZE(irqs));
58 }
59
60 static void gcplus_pcmcia_hw_shutdown(struct soc_pcmcia_socket *skt)
61 {
62         /* disable IRQs */
63         free_irq(S0_CD_IRQ, skt);
64   
65         /* Shutdown PCMCIA power */
66         mdelay(2);                      // 2msec
67         *PCMCIA_Power &= ~0x03;
68 }
69
70 static void
71 gcplus_pcmcia_socket_state(struct soc_pcmcia_socket *skt, struct pcmcia_state *state)
72 {
73         unsigned long levels = *PCMCIA_Status;
74
75         state->detect=(levels & ADS_CS_ST_A_CD)?1:0;
76         state->ready=(levels & ADS_CS_ST_A_READY)?1:0;
77         state->bvd1= 0;
78         state->bvd2= 0;
79         state->wrprot=0;
80         state->vs_3v=0;
81         state->vs_Xv=0;
82 }
83
84 static int
85 gcplus_pcmcia_configure_socket(struct soc_pcmcia_socket *skt,
86                                const socket_state_t *state)
87 {
88         unsigned long flags;
89
90         local_irq_save(flags);
91
92         switch (state->Vcc) {
93         case 0:
94                 *PCMCIA_Power &= ~(ADS_CS_PR_A_3V_POWER | ADS_CS_PR_A_5V_POWER);
95                 break;
96
97         case 50:
98                 *PCMCIA_Power &= ~(ADS_CS_PR_A_3V_POWER | ADS_CS_PR_A_5V_POWER);
99                 *PCMCIA_Power |= ADS_CS_PR_A_5V_POWER;
100                 break;
101
102         case 33:
103                 *PCMCIA_Power &= ~(ADS_CS_PR_A_3V_POWER | ADS_CS_PR_A_5V_POWER);
104                 *PCMCIA_Power |= ADS_CS_PR_A_3V_POWER;
105                 break;
106
107         default:
108                 printk(KERN_ERR "%s(): unrecognized Vcc %u\n",
109                         __FUNCTION__, state->Vcc);
110                 local_irq_restore(flags);
111                 return -1;
112         }
113
114         /* Silently ignore Vpp, output enable, speaker enable. */
115
116         // Reset PCMCIA
117         *PCMCIA_Power &= ~ ADS_CS_PR_A_RESET;
118         udelay(12);
119
120         *PCMCIA_Power |= ADS_CS_PR_A_RESET;
121         mdelay(30);
122
123         local_irq_restore(flags);
124
125         return 0;
126 }
127
128 static void gcplus_pcmcia_socket_init(struct soc_pcmcia_socket *skt)
129 {
130 }
131
132 static void gcplus_pcmcia_socket_suspend(struct soc_pcmcia_socket *skt)
133 {
134 }
135
136 static struct pcmcia_low_level gcplus_pcmcia_ops = { 
137         .owner                  = THIS_MODULE,
138         .hw_init                = gcplus_pcmcia_hw_init,
139         .hw_shutdown            = gcplus_pcmcia_hw_shutdown,
140         .socket_state           = gcplus_pcmcia_socket_state,
141         .configure_socket       = gcplus_pcmcia_configure_socket,
142         .socket_init            = gcplus_pcmcia_socket_init,
143         .socket_suspend         = gcplus_pcmcia_socket_suspend,
144 };
145
146 int __init pcmcia_gcplus_init(struct device *dev)
147 {
148         int ret = -ENODEV;
149
150         if (machine_is_gcplus())
151                 ret = sa11xx_drv_pcmcia_probe(dev, &gcplus_pcmcia_ops, 0, 1);
152
153         return ret;
154 }