more debug output
[linux-2.4.git] / drivers / pcmcia / sa1100_assabet.c
1 /*
2  * drivers/pcmcia/sa1100_assabet.c
3  *
4  * PCMCIA implementation routines for Assabet
5  *
6  */
7 #include <linux/kernel.h>
8 #include <linux/sched.h>
9
10 #include <asm/hardware.h>
11 #include <asm/irq.h>
12 #include <asm/arch/assabet.h>
13
14 #include "sa1100_generic.h"
15
16 static struct irqs {
17         int irq;
18         unsigned int gpio;
19         const char *str;
20 } irqs[] = {
21         { ASSABET_IRQ_GPIO_CF_CD,   ASSABET_GPIO_CF_CD,   "CF_CD"   },
22         { ASSABET_IRQ_GPIO_CF_BVD2, ASSABET_GPIO_CF_BVD2, "CF_BVD2" },
23         { ASSABET_IRQ_GPIO_CF_BVD1, ASSABET_GPIO_CF_BVD1, "CF_BVD1" },
24 };
25
26 static int assabet_pcmcia_init(struct pcmcia_init *init)
27 {
28         int i, res;
29
30         /* Set transition detect */
31         set_GPIO_IRQ_edge(ASSABET_GPIO_CF_IRQ, GPIO_FALLING_EDGE);
32
33         /* Register interrupts */
34         for (i = 0; i < ARRAY_SIZE(irqs); i++) {
35                 set_GPIO_IRQ_edge(irqs[i].gpio, GPIO_NO_EDGES);
36                 res = request_irq(irqs[i].irq, init->handler, SA_INTERRUPT,
37                                   irqs[i].str, NULL);
38                 if (res)
39                         goto irq_err;
40         }
41
42         /* There's only one slot, but it's "Slot 1": */
43         return 2;
44
45  irq_err:
46         printk(KERN_ERR "%s: request for IRQ%d failed\n",
47                 __FUNCTION__, irqs[i].irq);
48
49         while (i--)
50                 free_irq(irqs[i].irq, NULL);
51
52         return -1;
53 }
54
55 /*
56  * Release all resources.
57  */
58 static int assabet_pcmcia_shutdown(void)
59 {
60         int i;
61
62         for (i = 0; i < ARRAY_SIZE(irqs); i++)
63                 free_irq(irqs[i].irq, NULL);
64   
65         return 0;
66 }
67
68 static int
69 assabet_pcmcia_socket_state(struct pcmcia_state_array *state_array)
70 {
71         unsigned long levels;
72
73         if (state_array->size < 2)
74                 return -1;
75
76         levels = GPLR;
77
78         state_array->state[1].detect = (levels & ASSABET_GPIO_CF_CD) ? 0 : 1;
79         state_array->state[1].ready  = (levels & ASSABET_GPIO_CF_IRQ) ? 1 : 0;
80         state_array->state[1].bvd1   = (levels & ASSABET_GPIO_CF_BVD1) ? 1 : 0;
81         state_array->state[1].bvd2   = (levels & ASSABET_GPIO_CF_BVD2) ? 1 : 0;
82         state_array->state[1].wrprot = 0; /* Not available on Assabet. */
83         state_array->state[1].vs_3v  = 1; /* Can only apply 3.3V on Assabet. */
84         state_array->state[1].vs_Xv  = 0;
85
86         return 1;
87 }
88
89 static int assabet_pcmcia_get_irq_info(struct pcmcia_irq_info *info)
90 {
91         if (info->sock > 1)
92                 return -1;
93
94         if (info->sock == 1)
95                 info->irq = ASSABET_IRQ_GPIO_CF_IRQ;
96
97         return 0;
98 }
99
100 static int
101 assabet_pcmcia_configure_socket(const struct pcmcia_configure *configure)
102 {
103         unsigned int mask;
104
105         if (configure->sock > 1)
106                 return -1;
107
108         if (configure->sock == 0)
109                 return 0;
110
111         switch (configure->vcc) {
112         case 0:
113                 mask = 0;
114                 break;
115
116         case 50:
117                 printk(KERN_WARNING "%s(): CS asked for 5V, applying 3.3V...\n",
118                         __FUNCTION__);
119
120         case 33:  /* Can only apply 3.3V to the CF slot. */
121                 mask = ASSABET_BCR_CF_PWR;
122                 break;
123
124         default:
125                 printk(KERN_ERR "%s(): unrecognized Vcc %u\n", __FUNCTION__,
126                         configure->vcc);
127                 return -1;
128         }
129
130         /* Silently ignore Vpp, output enable, speaker enable. */
131
132         if (configure->reset)
133                 mask |= ASSABET_BCR_CF_RST;
134
135         ASSABET_BCR_frob(ASSABET_BCR_CF_RST | ASSABET_BCR_CF_PWR, mask);
136
137         /*
138          * Handle suspend mode properly.  This prevents a
139          * flood of IRQs from the CF device.
140          */
141         if (configure->irq)
142                 enable_irq(ASSABET_IRQ_GPIO_CF_IRQ);
143         else
144                 disable_irq(ASSABET_IRQ_GPIO_CF_IRQ);
145
146         return 0;
147 }
148
149 /*
150  * Enable card status IRQs on (re-)initialisation.  This can
151  * be called at initialisation, power management event, or
152  * pcmcia event.
153  */
154 static int assabet_pcmcia_socket_init(int sock)
155 {
156         int i;
157
158         if (sock == 1) {
159                 /*
160                  * Enable CF bus
161                  */
162                 ASSABET_BCR_clear(ASSABET_BCR_CF_BUS_OFF);
163
164                 for (i = 0; i < ARRAY_SIZE(irqs); i++)
165                         set_GPIO_IRQ_edge(irqs[i].gpio, GPIO_BOTH_EDGES);
166         }
167
168         return 0;
169 }
170
171 /*
172  * Disable card status IRQs on suspend.
173  */
174 static int assabet_pcmcia_socket_suspend(int sock)
175 {
176         int i;
177
178         if (sock == 1) {
179                 for (i = 0; i < ARRAY_SIZE(irqs); i++)
180                         set_GPIO_IRQ_edge(irqs[i].gpio, GPIO_NO_EDGES);
181
182                 /*
183                  * Tristate the CF bus signals.  Also assert CF
184                  * reset as per user guide page 4-11.
185                  */
186                 ASSABET_BCR_set(ASSABET_BCR_CF_BUS_OFF | ASSABET_BCR_CF_RST);
187         }
188
189         return 0;
190 }
191
192 struct pcmcia_low_level assabet_pcmcia_ops = { 
193         init:                   assabet_pcmcia_init,
194         shutdown:               assabet_pcmcia_shutdown,
195         socket_state:           assabet_pcmcia_socket_state,
196         get_irq_info:           assabet_pcmcia_get_irq_info,
197         configure_socket:       assabet_pcmcia_configure_socket,
198
199         socket_init:            assabet_pcmcia_socket_init,
200         socket_suspend:         assabet_pcmcia_socket_suspend,
201 };
202