1 /* $NetBSD: ipaq_pcic.c,v 1.19 2009/05/29 14:15:45 rjs 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 * 19 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 20 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 21 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 22 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 23 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 24 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 25 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 26 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 27 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 28 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 29 * POSSIBILITY OF SUCH DAMAGE. 30 */ 31 32 #include <sys/cdefs.h> 33 __KERNEL_RCSID(0, "$NetBSD: ipaq_pcic.c,v 1.19 2009/05/29 14:15:45 rjs Exp $"); 34 35 #include <sys/param.h> 36 #include <sys/systm.h> 37 #include <sys/types.h> 38 #include <sys/conf.h> 39 #include <sys/file.h> 40 #include <sys/device.h> 41 #include <sys/kernel.h> 42 #include <sys/kthread.h> 43 #include <sys/malloc.h> 44 45 #include <machine/bus.h> 46 #include <dev/pcmcia/pcmciachip.h> 47 #include <dev/pcmcia/pcmciavar.h> 48 49 #include <hpcarm/dev/ipaq_saipvar.h> 50 #include <hpcarm/dev/ipaq_pcicreg.h> 51 #include <hpcarm/dev/ipaq_gpioreg.h> 52 53 #include <arm/sa11x0/sa11x0_gpioreg.h> 54 #include <arm/sa11x0/sa11x0_var.h> 55 #include <arm/sa11x0/sa11xx_pcicvar.h> 56 57 #include "ipaqpcic.h" 58 59 static int ipaqpcic_match(device_t, cfdata_t, void *); 60 static void ipaqpcic_attach(device_t, device_t, void *); 61 static int ipaqpcic_print(void *, const char *); 62 63 static int ipaqpcic_read(struct sapcic_socket *, int); 64 static void ipaqpcic_write(struct sapcic_socket *, int, int); 65 static void ipaqpcic_set_power(struct sapcic_socket *, int); 66 static void ipaqpcic_clear_intr(int); 67 static void *ipaqpcic_intr_establish(struct sapcic_socket *, int, 68 int (*)(void *), void *); 69 static void ipaqpcic_intr_disestablish(struct sapcic_socket *, void *); 70 71 struct ipaqpcic_softc { 72 struct sapcic_softc sc_pc; 73 bus_space_handle_t sc_ioh; 74 struct ipaq_softc *sc_parent; 75 struct sapcic_socket sc_socket[2]; 76 }; 77 78 static void ipaqpcic_init(struct ipaqpcic_softc *); 79 80 static struct sapcic_tag ipaqpcic_functions = { 81 ipaqpcic_read, 82 ipaqpcic_write, 83 ipaqpcic_set_power, 84 ipaqpcic_clear_intr, 85 ipaqpcic_intr_establish, 86 ipaqpcic_intr_disestablish 87 }; 88 89 CFATTACH_DECL_NEW(ipaqpcic, sizeof(struct ipaqpcic_softc), 90 ipaqpcic_match, ipaqpcic_attach, NULL, NULL); 91 92 static int 93 ipaqpcic_match(device_t parent, cfdata_t cf, void *aux) 94 { 95 return (1); 96 } 97 98 static void 99 ipaqpcic_attach(device_t parent, device_t self, void *aux) 100 { 101 int i; 102 struct pcmciabus_attach_args paa; 103 struct ipaqpcic_softc *sc = device_private(self); 104 struct ipaq_softc *psc = device_private(parent); 105 106 aprint_normal("\n"); 107 108 sc->sc_pc.sc_dev = self; 109 sc->sc_pc.sc_iot = psc->sc_iot; 110 sc->sc_ioh = psc->sc_ioh; 111 sc->sc_parent = psc; 112 113 ipaqpcic_init(sc); 114 115 for(i = 0; i < 2; i++) { 116 sc->sc_socket[i].sc = (struct sapcic_softc *)sc; 117 sc->sc_socket[i].socket = i; 118 sc->sc_socket[i].pcictag_cookie = psc; 119 sc->sc_socket[i].pcictag = &ipaqpcic_functions; 120 sc->sc_socket[i].event_thread = NULL; 121 sc->sc_socket[i].event = 0; 122 sc->sc_socket[i].laststatus = SAPCIC_CARD_INVALID; 123 sc->sc_socket[i].shutdown = 0; 124 125 paa.paa_busname = "pcmcia"; 126 paa.pct = (pcmcia_chipset_tag_t)&sa11x0_pcmcia_functions; 127 paa.pch = (pcmcia_chipset_handle_t)&sc->sc_socket[i]; 128 paa.iobase = 0; 129 paa.iosize = 0x4000000; 130 131 sc->sc_socket[i].pcmcia = 132 config_found_ia(sc->sc_pc.sc_dev, "pcmciabus", 133 &paa, ipaqpcic_print); 134 135 sa11x0_intr_establish((sa11x0_chipset_tag_t)psc, 136 i ? IRQ_CD1 : IRQ_CD0, 137 1, IPL_BIO, sapcic_intr, 138 &sc->sc_socket[i]); 139 140 /* schedule kthread creation */ 141 sapcic_kthread_create(&sc->sc_socket[i]); 142 143 #if 0 /* XXX */ 144 /* establish_intr should be after creating the kthread */ 145 config_interrupt(&sc->sc_socket[i], ipaqpcic_config_intr); 146 #endif 147 } 148 } 149 150 static int 151 ipaqpcic_print(void *aux, const char *name) 152 { 153 return (UNCONF); 154 } 155 156 static void 157 ipaqpcic_init(struct ipaqpcic_softc *sc) 158 { 159 int cr; 160 161 /* All those are inputs */ 162 cr = bus_space_read_4(sc->sc_pc.sc_iot, sc->sc_parent->sc_gpioh, SAGPIO_PDR); 163 cr &= ~(GPIO_H3600_PCMCIA_CD0 | GPIO_H3600_PCMCIA_CD1 | GPIO_H3600_PCMCIA_IRQ0 | 164 GPIO_H3600_PCMCIA_IRQ1); 165 bus_space_write_4(sc->sc_pc.sc_iot, sc->sc_parent->sc_gpioh, SAGPIO_PDR, cr); 166 167 sc->sc_parent->ipaq_egpio |= 168 EGPIO_H3600_OPT_NVRAM_ON | EGPIO_H3600_OPT_ON ; 169 sc->sc_parent->ipaq_egpio &= 170 ~(EGPIO_H3600_CARD_RESET | EGPIO_H3600_OPT_RESET); 171 bus_space_write_2(sc->sc_pc.sc_iot, sc->sc_parent->sc_egpioh, 172 0, sc->sc_parent->ipaq_egpio); 173 } 174 175 static int 176 ipaqpcic_read(struct sapcic_socket *so, int reg) 177 { 178 int cr, bit; 179 struct ipaqpcic_softc *sc = (struct ipaqpcic_softc *)so->sc; 180 181 cr = bus_space_read_4(sc->sc_pc.sc_iot, sc->sc_parent->sc_gpioh, SAGPIO_PLR); 182 183 switch (reg) { 184 case SAPCIC_STATUS_CARD: 185 bit = (so->socket ? GPIO_H3600_PCMCIA_CD0 : 186 GPIO_H3600_PCMCIA_CD1) & cr; 187 if (!bit) 188 return SAPCIC_CARD_INVALID; 189 else 190 return SAPCIC_CARD_VALID; 191 case SAPCIC_STATUS_VS1: 192 case SAPCIC_STATUS_VS2: 193 case SAPCIC_STATUS_READY: 194 bit = (so->socket ? GPIO_H3600_PCMCIA_IRQ0: 195 GPIO_H3600_PCMCIA_IRQ1); 196 return (bit & cr); 197 default: 198 panic("ipaqpcic_read: bogus register"); 199 } 200 } 201 202 static void 203 ipaqpcic_write(struct sapcic_socket *so, int reg, int arg) 204 { 205 int s; 206 struct ipaqpcic_softc *sc = (struct ipaqpcic_softc *)so->sc; 207 208 s = splhigh(); 209 switch (reg) { 210 case SAPCIC_CONTROL_RESET: 211 sc->sc_parent->ipaq_egpio |= EGPIO_H3600_CARD_RESET; 212 break; 213 case SAPCIC_CONTROL_LINEENABLE: 214 case SAPCIC_CONTROL_WAITENABLE: 215 case SAPCIC_CONTROL_POWERSELECT: 216 break; 217 218 default: 219 splx(s); 220 panic("ipaqpcic_write: bogus register"); 221 } 222 bus_space_write_2(sc->sc_pc.sc_iot, sc->sc_parent->sc_egpioh, 0, 223 sc->sc_parent->ipaq_egpio); 224 splx(s); 225 } 226 227 static void 228 ipaqpcic_set_power(struct sapcic_socket *so, int arg) 229 { 230 int s; 231 struct ipaqpcic_softc *sc = (struct ipaqpcic_softc *)so->sc; 232 233 s = splbio(); 234 switch (arg) { 235 case SAPCIC_POWER_OFF: 236 sc->sc_parent->ipaq_egpio &= 237 ~(EGPIO_H3600_OPT_NVRAM_ON | EGPIO_H3600_OPT_ON); 238 break; 239 case SAPCIC_POWER_3V: 240 case SAPCIC_POWER_5V: 241 sc->sc_parent->ipaq_egpio |= 242 EGPIO_H3600_OPT_NVRAM_ON | EGPIO_H3600_OPT_ON; 243 break; 244 default: 245 panic("ipaqpcic_set_power: bogus arg"); 246 } 247 bus_space_write_2(sc->sc_pc.sc_iot, sc->sc_parent->sc_egpioh, 248 0, sc->sc_parent->ipaq_egpio); 249 splx(s); 250 } 251 252 static void 253 ipaqpcic_clear_intr(int arg) 254 { 255 } 256 257 static void * 258 ipaqpcic_intr_establish(struct sapcic_socket *so, int level, 259 int (*ih_fun)(void *), void *ih_arg) 260 { 261 int irq; 262 263 irq = so->socket ? IRQ_IRQ0 : IRQ_IRQ1; 264 return (sa11x0_intr_establish((sa11x0_chipset_tag_t)so->pcictag_cookie, 265 irq-16, 1, level, ih_fun, ih_arg)); 266 } 267 268 static void 269 ipaqpcic_intr_disestablish(struct sapcic_socket *so, void *ih) 270 { 271 sa11x0_intr_disestablish((sa11x0_chipset_tag_t)so->pcictag_cookie, ih); 272 } 273