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
assabet_pcmcia_init(struct pcmcia_init * init)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 */
assabet_pcmcia_shutdown(void)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
assabet_pcmcia_socket_state(struct pcmcia_state_array * state_array)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
assabet_pcmcia_get_irq_info(struct pcmcia_irq_info * info)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
assabet_pcmcia_configure_socket(const struct pcmcia_configure * configure)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 */
assabet_pcmcia_socket_init(int sock)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 */
assabet_pcmcia_socket_suspend(int sock)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
203