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