ipaq_pcic.c revision 1.13 1 /* $NetBSD: ipaq_pcic.c,v 1.13 2005/06/28 18:30:00 drochner Exp $ */
2
3 /*-
4 * Copyright (c) 2001 The NetBSD Foundation, Inc.
5 * All rights reserved.
6 *
7 * This code is derived from software contributed to The NetBSD Foundation
8 * by Ichiro FUKUHARA (ichiro (at) ichiro.org).
9 *
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
12 * are met:
13 * 1. Redistributions of source code must retain the above copyright
14 * notice, this list of conditions and the following disclaimer.
15 * 2. Redistributions in binary form must reproduce the above copyright
16 * notice, this list of conditions and the following disclaimer in the
17 * documentation and/or other materials provided with the distribution.
18 * 3. All advertising materials mentioning features or use of this software
19 * must display the following acknowledgement:
20 * This product includes software developed by the NetBSD
21 * Foundation, Inc. and its contributors.
22 * 4. Neither the name of The NetBSD Foundation nor the names of its
23 * contributors may be used to endorse or promote products derived
24 * from this software without specific prior written permission.
25 *
26 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
27 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
28 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
29 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
30 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
31 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
32 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
33 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
34 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
35 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
36 * POSSIBILITY OF SUCH DAMAGE.
37 */
38
39 #include <sys/cdefs.h>
40 __KERNEL_RCSID(0, "$NetBSD: ipaq_pcic.c,v 1.13 2005/06/28 18:30:00 drochner Exp $");
41
42 #include <sys/param.h>
43 #include <sys/systm.h>
44 #include <sys/types.h>
45 #include <sys/conf.h>
46 #include <sys/file.h>
47 #include <sys/device.h>
48 #include <sys/kernel.h>
49 #include <sys/kthread.h>
50 #include <sys/malloc.h>
51
52 #include <machine/bus.h>
53 #include <dev/pcmcia/pcmciachip.h>
54 #include <dev/pcmcia/pcmciavar.h>
55
56 #include <hpcarm/dev/ipaq_saipvar.h>
57 #include <hpcarm/dev/ipaq_pcicreg.h>
58 #include <hpcarm/dev/ipaq_gpioreg.h>
59
60 #include <arm/sa11x0/sa11x0_gpioreg.h>
61 #include <arm/sa11x0/sa11x0_var.h>
62 #include <arm/sa11x0/sa11xx_pcicvar.h>
63
64 #include "ipaqpcic.h"
65
66 static int ipaqpcic_match(struct device *, struct cfdata *, void *);
67 static void ipaqpcic_attach(struct device *, struct device *, void *);
68 static int ipaqpcic_print(void *, const char *);
69
70 static int ipaqpcic_read(struct sapcic_socket *, int);
71 static void ipaqpcic_write(struct sapcic_socket *, int, int);
72 static void ipaqpcic_set_power(struct sapcic_socket *, int);
73 static void ipaqpcic_clear_intr(int);
74 static void *ipaqpcic_intr_establish(struct sapcic_socket *, int,
75 int (*)(void *), void *);
76 static void ipaqpcic_intr_disestablish(struct sapcic_socket *, void *);
77
78 struct ipaqpcic_softc {
79 struct sapcic_softc sc_pc;
80 bus_space_handle_t sc_ioh;
81 struct ipaq_softc *sc_parent;
82 struct sapcic_socket sc_socket[2];
83 };
84
85 static void ipaqpcic_init(struct ipaqpcic_softc *);
86
87 static struct sapcic_tag ipaqpcic_functions = {
88 ipaqpcic_read,
89 ipaqpcic_write,
90 ipaqpcic_set_power,
91 ipaqpcic_clear_intr,
92 ipaqpcic_intr_establish,
93 ipaqpcic_intr_disestablish
94 };
95
96 CFATTACH_DECL(ipaqpcic, sizeof(struct ipaqpcic_softc),
97 ipaqpcic_match, ipaqpcic_attach, NULL, NULL);
98
99 static int
100 ipaqpcic_match(parent, cf, aux)
101 struct device *parent;
102 struct cfdata *cf;
103 void *aux;
104 {
105 return (1);
106 }
107
108 static void
109 ipaqpcic_attach(parent, self, aux)
110 struct device *parent;
111 struct device *self;
112 void *aux;
113 {
114 int i;
115 struct pcmciabus_attach_args paa;
116 struct ipaqpcic_softc *sc = (struct ipaqpcic_softc *)self;
117 struct ipaq_softc *psc = (struct ipaq_softc *)parent;
118
119 printf("\n");
120
121 sc->sc_pc.sc_iot = psc->sc_iot;
122 sc->sc_ioh = psc->sc_ioh;
123 sc->sc_parent = (struct ipaq_softc *)parent;
124
125 ipaqpcic_init(sc);
126
127 for(i = 0; i < 2; i++) {
128 sc->sc_socket[i].sc = (struct sapcic_softc *)sc;
129 sc->sc_socket[i].socket = i;
130 sc->sc_socket[i].pcictag_cookie = psc;
131 sc->sc_socket[i].pcictag = &ipaqpcic_functions;
132 sc->sc_socket[i].event_thread = NULL;
133 sc->sc_socket[i].event = 0;
134 sc->sc_socket[i].laststatus = SAPCIC_CARD_INVALID;
135 sc->sc_socket[i].shutdown = 0;
136
137 paa.paa_busname = "pcmcia";
138 paa.pct = (pcmcia_chipset_tag_t)&sa11x0_pcmcia_functions;
139 paa.pch = (pcmcia_chipset_handle_t)&sc->sc_socket[i];
140 paa.iobase = 0;
141 paa.iosize = 0x4000000;
142
143 sc->sc_socket[i].pcmcia =
144 config_found_ia(&sc->sc_pc.sc_dev, "pcmciabus",
145 &paa, ipaqpcic_print);
146
147 sa11x0_intr_establish((sa11x0_chipset_tag_t)psc,
148 i ? IRQ_CD1 : IRQ_CD0,
149 1, IPL_BIO, sapcic_intr,
150 &sc->sc_socket[i]);
151
152 /* schedule kthread creation */
153 kthread_create(sapcic_kthread_create, &sc->sc_socket[i]);
154
155 #if 0 /* XXX */
156 /* establish_intr should be after creating the kthread */
157 config_interrupt(&sc->sc_socket[i], ipaqpcic_config_intr);
158 #endif
159 }
160 }
161
162 static int
163 ipaqpcic_print(aux, name)
164 void *aux;
165 const char *name;
166 {
167 return (UNCONF);
168 }
169
170 static void
171 ipaqpcic_init(sc)
172 struct ipaqpcic_softc *sc;
173 {
174 int cr;
175
176 /* All those are inputs */
177 cr = bus_space_read_4(sc->sc_pc.sc_iot, sc->sc_parent->sc_gpioh, SAGPIO_PDR);
178 cr &= ~(GPIO_H3600_PCMCIA_CD0 | GPIO_H3600_PCMCIA_CD1 | GPIO_H3600_PCMCIA_IRQ0 |
179 GPIO_H3600_PCMCIA_IRQ1);
180 bus_space_write_4(sc->sc_pc.sc_iot, sc->sc_parent->sc_gpioh, SAGPIO_PDR, cr);
181
182 sc->sc_parent->ipaq_egpio |=
183 EGPIO_H3600_OPT_NVRAM_ON | EGPIO_H3600_OPT_ON ;
184 sc->sc_parent->ipaq_egpio &=
185 ~(EGPIO_H3600_CARD_RESET | EGPIO_H3600_OPT_RESET);
186 bus_space_write_2(sc->sc_pc.sc_iot, sc->sc_parent->sc_egpioh,
187 0, sc->sc_parent->ipaq_egpio);
188 }
189
190 static int
191 ipaqpcic_read(so, reg)
192 struct sapcic_socket *so;
193 int reg;
194 {
195 int cr, bit;
196 struct ipaqpcic_softc *sc = (struct ipaqpcic_softc *)so->sc;
197
198 cr = bus_space_read_4(sc->sc_pc.sc_iot, sc->sc_parent->sc_gpioh, SAGPIO_PLR);
199
200 switch (reg) {
201 case SAPCIC_STATUS_CARD:
202 bit = (so->socket ? GPIO_H3600_PCMCIA_CD0 :
203 GPIO_H3600_PCMCIA_CD1) & cr;
204 if (!bit)
205 return SAPCIC_CARD_INVALID;
206 else
207 return SAPCIC_CARD_VALID;
208 case SAPCIC_STATUS_VS1:
209 case SAPCIC_STATUS_VS2:
210 case SAPCIC_STATUS_READY:
211 bit = (so->socket ? GPIO_H3600_PCMCIA_IRQ0:
212 GPIO_H3600_PCMCIA_IRQ1);
213 return (bit & cr);
214 default:
215 panic("ipaqpcic_read: bogus register");
216 }
217 }
218
219 static void
220 ipaqpcic_write(so, reg, arg)
221 struct sapcic_socket *so;
222 int reg;
223 int arg;
224 {
225 int s;
226 struct ipaqpcic_softc *sc = (struct ipaqpcic_softc *)so->sc;
227
228 s = splhigh();
229 switch (reg) {
230 case SAPCIC_CONTROL_RESET:
231 sc->sc_parent->ipaq_egpio |= EGPIO_H3600_CARD_RESET;
232 break;
233 case SAPCIC_CONTROL_LINEENABLE:
234 case SAPCIC_CONTROL_WAITENABLE:
235 case SAPCIC_CONTROL_POWERSELECT:
236 break;
237
238 default:
239 splx(s);
240 panic("ipaqpcic_write: bogus register");
241 }
242 bus_space_write_2(sc->sc_pc.sc_iot, sc->sc_parent->sc_egpioh, 0,
243 sc->sc_parent->ipaq_egpio);
244 splx(s);
245 }
246
247 static void
248 ipaqpcic_set_power(so, arg)
249 struct sapcic_socket *so;
250 int arg;
251 {
252 int s;
253 struct ipaqpcic_softc *sc = (struct ipaqpcic_softc *)so->sc;
254
255 s = splbio();
256 switch (arg) {
257 case SAPCIC_POWER_OFF:
258 sc->sc_parent->ipaq_egpio &=
259 ~(EGPIO_H3600_OPT_NVRAM_ON | EGPIO_H3600_OPT_ON);
260 break;
261 case SAPCIC_POWER_3V:
262 case SAPCIC_POWER_5V:
263 sc->sc_parent->ipaq_egpio |=
264 EGPIO_H3600_OPT_NVRAM_ON | EGPIO_H3600_OPT_ON;
265 break;
266 default:
267 panic("ipaqpcic_set_power: bogus arg");
268 }
269 bus_space_write_2(sc->sc_pc.sc_iot, sc->sc_parent->sc_egpioh,
270 0, sc->sc_parent->ipaq_egpio);
271 splx(s);
272 }
273
274 static void
275 ipaqpcic_clear_intr(arg)
276 {
277 }
278
279 static void *
280 ipaqpcic_intr_establish(so, level, ih_fun, ih_arg)
281 struct sapcic_socket *so;
282 int level;
283 int (*ih_fun)(void *);
284 void *ih_arg;
285 {
286 int irq;
287
288 irq = so->socket ? IRQ_IRQ0 : IRQ_IRQ1;
289 return (sa11x0_intr_establish((sa11x0_chipset_tag_t)so->pcictag_cookie,
290 irq-16, 1, level, ih_fun, ih_arg));
291 }
292
293 static void
294 ipaqpcic_intr_disestablish(so, ih)
295 struct sapcic_socket *so;
296 void *ih;
297 {
298 sa11x0_intr_disestablish((sa11x0_chipset_tag_t)so->pcictag_cookie, ih);
299 }
300