xref: /netbsd-src/sys/arch/hpcarm/dev/ipaq_pcic.c (revision 267197ec1eebfcb9810ea27a89625b6ddf68e3e7)
1 /*      $NetBSD: ipaq_pcic.c,v 1.17 2007/10/17 19:54:28 garbled 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@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.17 2007/10/17 19:54:28 garbled 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(struct device *parent, struct cfdata *cf, void *aux)
101 {
102 	return (1);
103 }
104 
105 static void
106 ipaqpcic_attach(struct device *parent, struct device *self, void *aux)
107 {
108 	int i;
109 	struct pcmciabus_attach_args paa;
110 	struct ipaqpcic_softc *sc = (struct ipaqpcic_softc *)self;
111 	struct ipaq_softc *psc = (struct ipaq_softc *)parent;
112 
113 	printf("\n");
114 
115 	sc->sc_pc.sc_iot = psc->sc_iot;
116 	sc->sc_ioh = psc->sc_ioh;
117 	sc->sc_parent = (struct ipaq_softc *)parent;
118 
119 	ipaqpcic_init(sc);
120 
121 	for(i = 0; i < 2; i++) {
122 		sc->sc_socket[i].sc = (struct sapcic_softc *)sc;
123 		sc->sc_socket[i].socket = i;
124 		sc->sc_socket[i].pcictag_cookie = psc;
125 		sc->sc_socket[i].pcictag = &ipaqpcic_functions;
126 		sc->sc_socket[i].event_thread = NULL;
127 		sc->sc_socket[i].event = 0;
128 		sc->sc_socket[i].laststatus = SAPCIC_CARD_INVALID;
129 		sc->sc_socket[i].shutdown = 0;
130 
131 		paa.paa_busname = "pcmcia";
132 		paa.pct = (pcmcia_chipset_tag_t)&sa11x0_pcmcia_functions;
133 		paa.pch = (pcmcia_chipset_handle_t)&sc->sc_socket[i];
134 		paa.iobase = 0;
135 		paa.iosize = 0x4000000;
136 
137 		sc->sc_socket[i].pcmcia =
138 		    config_found_ia(&sc->sc_pc.sc_dev, "pcmciabus",
139 		    &paa, ipaqpcic_print);
140 
141 		sa11x0_intr_establish((sa11x0_chipset_tag_t)psc,
142 			    i ? IRQ_CD1 : IRQ_CD0,
143 			    1, IPL_BIO, sapcic_intr,
144 			    &sc->sc_socket[i]);
145 
146 		/* schedule kthread creation */
147 		sapcic_kthread_create(&sc->sc_socket[i]);
148 
149 #if 0 /* XXX */
150 		/* establish_intr should be after creating the kthread */
151 		config_interrupt(&sc->sc_socket[i], ipaqpcic_config_intr);
152 #endif
153 	}
154 }
155 
156 static int
157 ipaqpcic_print(void *aux, const char *name)
158 {
159 	return (UNCONF);
160 }
161 
162 static void
163 ipaqpcic_init(struct ipaqpcic_softc *sc)
164 {
165 	int cr;
166 
167 	/* All those are inputs */
168 	cr = bus_space_read_4(sc->sc_pc.sc_iot, sc->sc_parent->sc_gpioh, SAGPIO_PDR);
169 	cr &= ~(GPIO_H3600_PCMCIA_CD0 | GPIO_H3600_PCMCIA_CD1 | GPIO_H3600_PCMCIA_IRQ0 |
170 		GPIO_H3600_PCMCIA_IRQ1);
171 	bus_space_write_4(sc->sc_pc.sc_iot, sc->sc_parent->sc_gpioh, SAGPIO_PDR, cr);
172 
173 	sc->sc_parent->ipaq_egpio |=
174 		EGPIO_H3600_OPT_NVRAM_ON | EGPIO_H3600_OPT_ON ;
175 	sc->sc_parent->ipaq_egpio &=
176 		~(EGPIO_H3600_CARD_RESET | EGPIO_H3600_OPT_RESET);
177 	bus_space_write_2(sc->sc_pc.sc_iot, sc->sc_parent->sc_egpioh,
178 			  0, sc->sc_parent->ipaq_egpio);
179 }
180 
181 static int
182 ipaqpcic_read(struct sapcic_socket *so, int reg)
183 {
184 	int cr, bit;
185 	struct ipaqpcic_softc *sc = (struct ipaqpcic_softc *)so->sc;
186 
187 	cr = bus_space_read_4(sc->sc_pc.sc_iot, sc->sc_parent->sc_gpioh, SAGPIO_PLR);
188 
189 	switch (reg) {
190 	case SAPCIC_STATUS_CARD:
191 		bit = (so->socket ? GPIO_H3600_PCMCIA_CD0 :
192 				GPIO_H3600_PCMCIA_CD1) & cr;
193 		if (!bit)
194 			return SAPCIC_CARD_INVALID;
195 		else
196 			return SAPCIC_CARD_VALID;
197 	case SAPCIC_STATUS_VS1:
198         case SAPCIC_STATUS_VS2:
199 	case SAPCIC_STATUS_READY:
200 		bit = (so->socket ? GPIO_H3600_PCMCIA_IRQ0:
201 				GPIO_H3600_PCMCIA_IRQ1);
202 		return (bit & cr);
203 	default:
204 		panic("ipaqpcic_read: bogus register");
205 	}
206 }
207 
208 static void
209 ipaqpcic_write(struct sapcic_socket *so, int reg, int arg)
210 {
211 	int s;
212 	struct ipaqpcic_softc *sc = (struct ipaqpcic_softc *)so->sc;
213 
214 	s = splhigh();
215 	switch (reg) {
216 	case SAPCIC_CONTROL_RESET:
217 		sc->sc_parent->ipaq_egpio |= EGPIO_H3600_CARD_RESET;
218 		break;
219 	case SAPCIC_CONTROL_LINEENABLE:
220 	case SAPCIC_CONTROL_WAITENABLE:
221 	case SAPCIC_CONTROL_POWERSELECT:
222 		break;
223 
224 	default:
225 		splx(s);
226 		panic("ipaqpcic_write: bogus register");
227 	}
228 	bus_space_write_2(sc->sc_pc.sc_iot, sc->sc_parent->sc_egpioh, 0,
229 			  sc->sc_parent->ipaq_egpio);
230 	splx(s);
231 }
232 
233 static void
234 ipaqpcic_set_power(struct sapcic_socket *so, int arg)
235 {
236 	int s;
237 	struct ipaqpcic_softc *sc = (struct ipaqpcic_softc *)so->sc;
238 
239 	s = splbio();
240 	switch (arg) {
241 	case SAPCIC_POWER_OFF:
242 		sc->sc_parent->ipaq_egpio &=
243 			~(EGPIO_H3600_OPT_NVRAM_ON | EGPIO_H3600_OPT_ON);
244 		break;
245 	case SAPCIC_POWER_3V:
246 	case SAPCIC_POWER_5V:
247 		sc->sc_parent->ipaq_egpio |=
248 			EGPIO_H3600_OPT_NVRAM_ON | EGPIO_H3600_OPT_ON;
249 		break;
250 	default:
251 		panic("ipaqpcic_set_power: bogus arg");
252 	}
253 	bus_space_write_2(sc->sc_pc.sc_iot, sc->sc_parent->sc_egpioh,
254 			  0, sc->sc_parent->ipaq_egpio);
255 	splx(s);
256 }
257 
258 static void
259 ipaqpcic_clear_intr(int arg)
260 {
261 }
262 
263 static void *
264 ipaqpcic_intr_establish(struct sapcic_socket *so, int level,
265 			int (*ih_fun)(void *), void *ih_arg)
266 {
267 	int irq;
268 
269 	irq = so->socket ? IRQ_IRQ0 : IRQ_IRQ1;
270 	return (sa11x0_intr_establish((sa11x0_chipset_tag_t)so->pcictag_cookie,
271 				    irq-16, 1, level, ih_fun, ih_arg));
272 }
273 
274 static void
275 ipaqpcic_intr_disestablish(struct sapcic_socket *so, void *ih)
276 {
277 	sa11x0_intr_disestablish((sa11x0_chipset_tag_t)so->pcictag_cookie, ih);
278 }
279