1 /*
2 * drivers/pcmcia/sa1100_flexanet.c
3 *
4 * PCMCIA implementation routines for Flexanet.
5 * by Jordi Colomer, 09/05/2001
6 *
7 */
8
9 #include <linux/kernel.h>
10 #include <linux/sched.h>
11
12 #include <asm/hardware.h>
13 #include <asm/irq.h>
14 #include "sa1100_generic.h"
15
16 static struct {
17 int irq;
18 unsigned int gpio;
19 const char *name;
20 } irqs[] = {
21 { IRQ_GPIO_CF1_CD, GPIO_CF1_NCD, "CF1_CD" },
22 { IRQ_GPIO_CF1_BVD1, GPIO_CF1_BVD1, "CF1_BVD1" },
23 { IRQ_GPIO_CF2_CD, GPIO_CF2_NCD, "CF2_CD" },
24 { IRQ_GPIO_CF2_BVD1, GPIO_CF2_BVD1, "CF2_BVD1" }
25 };
26
27 /*
28 * Socket initialization.
29 *
30 * Called by sa1100_pcmcia_driver_init on startup.
31 * Must return the number of slots.
32 *
33 */
flexanet_pcmcia_init(struct pcmcia_init * init)34 static int flexanet_pcmcia_init(struct pcmcia_init *init)
35 {
36 int i, res;
37
38 /* Configure the GPIOs as inputs (BVD2 is not implemented) */
39 GPDR &= ~(GPIO_CF1_NCD | GPIO_CF1_BVD1 | GPIO_CF1_IRQ |
40 GPIO_CF2_NCD | GPIO_CF2_BVD1 | GPIO_CF2_IRQ );
41
42 /* Set IRQ edge */
43 set_GPIO_IRQ_edge( GPIO_CF1_IRQ | GPIO_CF2_IRQ, GPIO_FALLING_EDGE );
44
45 /* Register the socket interrupts (not the card interrupts) */
46 for (i = 0; i < ARRAY_SIZE(irqs); i++) {
47 set_GPIO_IRQ_edge(irqs[i].gpio, GPIO_NO_EDGES);
48 res = request_irq(irqs[i].irq, init->handler, SA_INTERRUPT,
49 irqs[i].name, NULL);
50 if (res < 0)
51 break;
52 }
53
54 /* If we failed, then free all interrupts requested thus far. */
55 if (res < 0) {
56 printk(KERN_ERR "%s: Request for IRQ%u failed: %d\n", __FUNCTION__,
57 irqs[i].irq, res);
58 while (i--)
59 free_irq(irqs[i].irq, NULL);
60 return -1;
61 }
62
63 return 2;
64 }
65
66
67 /*
68 * Socket shutdown
69 *
70 */
flexanet_pcmcia_shutdown(void)71 static int flexanet_pcmcia_shutdown(void)
72 {
73 int i;
74
75 /* disable IRQs */
76 for (i = 0; i < ARRAY_SIZE(irqs); i++)
77 free_irq(irqs[i].irq, NULL);
78
79 return 0;
80 }
81
82
83 /*
84 * Get the state of the sockets.
85 *
86 * Sockets in Flexanet are 3.3V only, without BVD2.
87 *
88 */
flexanet_pcmcia_socket_state(struct pcmcia_state_array * state_array)89 static int flexanet_pcmcia_socket_state(struct pcmcia_state_array
90 *state_array){
91 unsigned long levels;
92
93 if (state_array->size < 2)
94 return -1;
95
96 /* Sense the GPIOs, asynchronously */
97 levels = GPLR;
98
99 /* Socket 0 */
100 state_array->state[0].detect = ((levels & GPIO_CF1_NCD)==0)?1:0;
101 state_array->state[0].ready = (levels & GPIO_CF1_IRQ)?1:0;
102 state_array->state[0].bvd1 = (levels & GPIO_CF1_BVD1)?1:0;
103 state_array->state[0].bvd2 = 1;
104 state_array->state[0].wrprot = 0;
105 state_array->state[0].vs_3v = 1;
106 state_array->state[0].vs_Xv = 0;
107
108 /* Socket 1 */
109 state_array->state[1].detect = ((levels & GPIO_CF2_NCD)==0)?1:0;
110 state_array->state[1].ready = (levels & GPIO_CF2_IRQ)?1:0;
111 state_array->state[1].bvd1 = (levels & GPIO_CF2_BVD1)?1:0;
112 state_array->state[1].bvd2 = 1;
113 state_array->state[1].wrprot = 0;
114 state_array->state[1].vs_3v = 1;
115 state_array->state[1].vs_Xv = 0;
116
117 return 1;
118 }
119
120
121 /*
122 * Return the IRQ information for a given socket number (the IRQ number)
123 *
124 */
flexanet_pcmcia_get_irq_info(struct pcmcia_irq_info * info)125 static int flexanet_pcmcia_get_irq_info(struct pcmcia_irq_info *info){
126
127 /* check the socket index */
128 if (info->sock > 1)
129 return -1;
130
131 if (info->sock == 0)
132 info->irq = IRQ_GPIO_CF1_IRQ;
133 else if (info->sock == 1)
134 info->irq = IRQ_GPIO_CF2_IRQ;
135
136 return 0;
137 }
138
139
140 /*
141 *
142 */
flexanet_pcmcia_configure_socket(const struct pcmcia_configure * configure)143 static int flexanet_pcmcia_configure_socket(const struct pcmcia_configure
144 *configure)
145 {
146 unsigned long value, flags, mask;
147
148
149 if (configure->sock > 1)
150 return -1;
151
152 /* Ignore the VCC level since it is 3.3V and always on */
153 switch (configure->vcc)
154 {
155 case 0:
156 printk(KERN_WARNING "%s(): CS asked to power off.\n", __FUNCTION__);
157 break;
158
159 case 50:
160 printk(KERN_WARNING "%s(): CS asked for 5V, applying 3.3V...\n",
161 __FUNCTION__);
162
163 case 33:
164 break;
165
166 default:
167 printk(KERN_ERR "%s(): unrecognized Vcc %u\n", __FUNCTION__,
168 configure->vcc);
169 return -1;
170 }
171
172 /* Reset the slot(s) using the controls in the BCR */
173 mask = 0;
174
175 switch (configure->sock)
176 {
177 case 0 : mask = FHH_BCR_CF1_RST; break;
178 case 1 : mask = FHH_BCR_CF2_RST; break;
179 }
180
181 save_flags_cli(flags);
182
183 value = flexanet_BCR;
184 value = (configure->reset) ? (value | mask) : (value & ~mask);
185 FHH_BCR = flexanet_BCR = value;
186
187 restore_flags(flags);
188
189 return 0;
190 }
191
flexanet_pcmcia_socket_init(int sock)192 static int flexanet_pcmcia_socket_init(int sock)
193 {
194 if (sock == 0)
195 set_GPIO_IRQ_edge(GPIO_CF1_NCD | GPIO_CF1_BVD1, GPIO_BOTH_EDGES);
196 else if (sock == 1)
197 set_GPIO_IRQ_edge(GPIO_CF2_NCD | GPIO_CF2_BVD1, GPIO_BOTH_EDGES);
198
199 return 0;
200 }
201
flexanet_pcmcia_socket_suspend(int sock)202 static int flexanet_pcmcia_socket_suspend(int sock)
203 {
204 if (sock == 0)
205 set_GPIO_IRQ_edge(GPIO_CF1_NCD | GPIO_CF1_BVD1, GPIO_NO_EDGES);
206 else if (sock == 1)
207 set_GPIO_IRQ_edge(GPIO_CF2_NCD | GPIO_CF2_BVD1, GPIO_NO_EDGES);
208
209 return 0;
210 }
211
212 /*
213 * The set of socket operations
214 *
215 */
216 struct pcmcia_low_level flexanet_pcmcia_ops = {
217 init: flexanet_pcmcia_init,
218 shutdown: flexanet_pcmcia_shutdown,
219 socket_state: flexanet_pcmcia_socket_state,
220 get_irq_info: flexanet_pcmcia_get_irq_info,
221 configure_socket: flexanet_pcmcia_configure_socket,
222
223 socket_init: flexanet_pcmcia_socket_init,
224 socket_suspend: flexanet_pcmcia_socket_suspend,
225 };
226
227