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