more debug output
[linux-2.4.git] / drivers / pcmcia / sa1100_h3600.c
1 /*
2  * drivers/pcmcia/sa1100_h3600.c
3  *
4  * PCMCIA implementation routines for H3600
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 "sa1100_generic.h"
13
14 static struct irqs {
15         int irq;
16         const char *str;
17 } irqs[] = {
18         { IRQ_GPIO_H3600_PCMCIA_CD0, "PCMCIA CD0" },
19         { IRQ_GPIO_H3600_PCMCIA_CD1, "PCMCIA CD1" }
20 };
21
22 static int h3600_pcmcia_init(struct pcmcia_init *init)
23 {
24         int i, res;
25
26         /*
27          * Set transition detect
28          */
29         set_GPIO_IRQ_edge(GPIO_H3600_PCMCIA_IRQ0 | GPIO_H3600_PCMCIA_IRQ1,
30                           GPIO_FALLING_EDGE);
31
32         /*
33          * Register interrupts
34          */
35         for (i = res = 0; i < ARRAY_SIZE(irqs); i++) {
36                 res = request_irq(irqs[i].irq, init->handler, SA_INTERRUPT,
37                                   irqs[i].str, NULL);
38                 if (res)
39                         break;
40         }
41
42         if (res) {
43                 printk(KERN_ERR "h3600_pcmcia: request for IRQ%d failed: %d\n",
44                        irqs[i].irq, res);
45
46                 while (i--)
47                         free_irq(irqs[i].irq, NULL);
48         }
49
50         return res ? -1 : 2;
51 }
52
53 static int h3600_pcmcia_shutdown(void)
54 {
55         int i;
56
57         /*
58          * disable IRQs
59          */
60         for (i = 0; i < ARRAY_SIZE(irqs); i++)
61                 free_irq(irqs[i].irq, NULL);
62   
63         /* Disable CF bus: */
64         clr_h3600_egpio(IPAQ_EGPIO_OPT_NVRAM_ON);
65         clr_h3600_egpio(IPAQ_EGPIO_OPT_ON);
66         set_h3600_egpio(IPAQ_EGPIO_OPT_RESET);
67
68         return 0;
69 }
70
71 static int
72 h3600_pcmcia_socket_state(struct pcmcia_state_array *state)
73 {
74         unsigned long levels;
75
76         if (state->size < 2)
77                 return -1;
78
79         levels = GPLR;
80
81         state->state[0].detect = levels & GPIO_H3600_PCMCIA_CD0 ? 0 : 1;
82         state->state[0].ready = levels & GPIO_H3600_PCMCIA_IRQ0 ? 1 : 0;
83         state->state[0].bvd1 = 0;
84         state->state[0].bvd2 = 0;
85         state->state[0].wrprot = 0; /* Not available on H3600. */
86         state->state[0].vs_3v = 0;
87         state->state[0].vs_Xv = 0;
88
89         state->state[1].detect = levels & GPIO_H3600_PCMCIA_CD1 ? 0 : 1;
90         state->state[1].ready = levels & GPIO_H3600_PCMCIA_IRQ1 ? 1 : 0;
91         state->state[1].bvd1 = 0;
92         state->state[1].bvd2 = 0;
93         state->state[1].wrprot = 0; /* Not available on H3600. */
94         state->state[1].vs_3v = 0;
95         state->state[1].vs_Xv = 0;
96
97         return 1;
98 }
99
100 static int h3600_pcmcia_get_irq_info(struct pcmcia_irq_info *info)
101 {
102         switch (info->sock) {
103         case 0:
104                 info->irq = IRQ_GPIO_H3600_PCMCIA_IRQ0;
105                 break;
106         case 1:
107                 info->irq = IRQ_GPIO_H3600_PCMCIA_IRQ1;
108                 break;
109         default:
110                 return -1;
111         }
112         return 0;
113 }
114
115 static int
116 h3600_pcmcia_configure_socket(const struct pcmcia_configure *conf)
117 {
118         if (conf->sock > 1)
119                 return -1;
120
121         if (conf->vcc != 0 && conf->vcc != 33 && conf->vcc != 50) {
122                 printk(KERN_ERR "h3600_pcmcia: unrecognized Vcc %u.%uV\n",
123                        conf->vcc / 10, conf->vcc % 10);
124                 return -1;
125         }
126
127         if (conf->reset)
128                 set_h3600_egpio(IPAQ_EGPIO_CARD_RESET);
129         else
130                 clr_h3600_egpio(IPAQ_EGPIO_CARD_RESET);
131
132         /* Silently ignore Vpp, output enable, speaker enable. */
133
134         return 0;
135 }
136
137 static int h3600_pcmcia_socket_init(int sock)
138 {
139         /* Enable CF bus: */
140         set_h3600_egpio(IPAQ_EGPIO_OPT_NVRAM_ON);
141         set_h3600_egpio(IPAQ_EGPIO_OPT_ON);
142         clr_h3600_egpio(IPAQ_EGPIO_OPT_RESET);
143
144         set_current_state(TASK_UNINTERRUPTIBLE);
145         schedule_timeout(10*HZ / 1000);
146
147         switch (sock) {
148         case 0:
149                 set_GPIO_IRQ_edge(GPIO_H3600_PCMCIA_CD0, GPIO_BOTH_EDGES);
150                 break;
151         case 1:
152                 set_GPIO_IRQ_edge(GPIO_H3600_PCMCIA_CD1, GPIO_BOTH_EDGES);
153                 break;
154         }
155
156         return 0;
157 }
158
159 static int h3600_pcmcia_socket_suspend(int sock)
160 {
161         switch (sock) {
162         case 0:
163                 set_GPIO_IRQ_edge(GPIO_H3600_PCMCIA_CD0, GPIO_NO_EDGES);
164                 break;
165         case 1:
166                 set_GPIO_IRQ_edge(GPIO_H3600_PCMCIA_CD1, GPIO_NO_EDGES);
167                 break;
168         }
169
170         /*
171          * FIXME:  This doesn't fit well.  We don't have the mechanism in
172          * the generic PCMCIA layer to deal with the idea of two sockets
173          * on one bus.  We rely on the cs.c behaviour shutting down
174          * socket 0 then socket 1.
175          */
176         if (sock == 1) {
177                 clr_h3600_egpio(IPAQ_EGPIO_OPT_ON);
178                 clr_h3600_egpio(IPAQ_EGPIO_OPT_NVRAM_ON);
179                 /* hmm, does this suck power? */
180                 set_h3600_egpio(IPAQ_EGPIO_OPT_RESET);
181         }
182
183         return 0;
184 }
185
186 struct pcmcia_low_level h3600_pcmcia_ops = { 
187         init:                   h3600_pcmcia_init,
188         shutdown:               h3600_pcmcia_shutdown,
189         socket_state:           h3600_pcmcia_socket_state,
190         get_irq_info:           h3600_pcmcia_get_irq_info,
191         configure_socket:       h3600_pcmcia_configure_socket,
192
193         socket_init:            h3600_pcmcia_socket_init,
194         socket_suspend:         h3600_pcmcia_socket_suspend,
195 };
196