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 
h3600_pcmcia_init(struct pcmcia_init * init)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 
h3600_pcmcia_shutdown(void)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
h3600_pcmcia_socket_state(struct pcmcia_state_array * state)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 
h3600_pcmcia_get_irq_info(struct pcmcia_irq_info * info)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
h3600_pcmcia_configure_socket(const struct pcmcia_configure * conf)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 
h3600_pcmcia_socket_init(int sock)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 
h3600_pcmcia_socket_suspend(int sock)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 
197