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