1/* $NetBSD: ipaq_pcic.c,v 1.24 2023/12/20 14:50:02 thorpej 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.24 2023/12/20 14:50:02 thorpej 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/bus.h> 44 45#include <dev/pcmcia/pcmciachip.h> 46#include <dev/pcmcia/pcmciavar.h> 47 48#include <hpcarm/dev/ipaq_saipvar.h> 49#include <hpcarm/dev/ipaq_pcicreg.h> 50#include <hpcarm/dev/ipaq_gpioreg.h> 51 52#include <arm/sa11x0/sa11x0_gpioreg.h> 53#include <arm/sa11x0/sa11x0_var.h> 54#include <arm/sa11x0/sa11xx_pcicvar.h> 55 56#include "ipaqpcic.h" 57 58static int ipaqpcic_match(device_t, cfdata_t, void *); 59static void ipaqpcic_attach(device_t, device_t, void *); 60static int ipaqpcic_print(void *, const char *); 61 62static int ipaqpcic_read(struct sapcic_socket *, int); 63static void ipaqpcic_write(struct sapcic_socket *, int, int); 64static void ipaqpcic_set_power(struct sapcic_socket *, int); 65static void ipaqpcic_clear_intr(int); 66static void *ipaqpcic_intr_establish(struct sapcic_socket *, int, 67 int (*)(void *), void *); 68static void ipaqpcic_intr_disestablish(struct sapcic_socket *, void *); 69 70struct ipaqpcic_softc { 71 struct sapcic_softc sc_pc; 72 bus_space_handle_t sc_ioh; 73 struct ipaq_softc *sc_parent; 74 struct sapcic_socket sc_socket[2]; 75}; 76 77static void ipaqpcic_init(struct ipaqpcic_softc *); 78 79static struct sapcic_tag ipaqpcic_functions = { 80 ipaqpcic_read, 81 ipaqpcic_write, 82 ipaqpcic_set_power, 83 ipaqpcic_clear_intr, 84 ipaqpcic_intr_establish, 85 ipaqpcic_intr_disestablish 86}; 87 88CFATTACH_DECL_NEW(ipaqpcic, sizeof(struct ipaqpcic_softc), 89 ipaqpcic_match, ipaqpcic_attach, NULL, NULL); 90 91static int 92ipaqpcic_match(device_t parent, cfdata_t cf, void *aux) 93{ 94 return (1); 95} 96 97static void 98ipaqpcic_attach(device_t parent, device_t self, void *aux) 99{ 100 int i; 101 struct pcmciabus_attach_args paa; 102 struct ipaqpcic_softc *sc = device_private(self); 103 struct ipaq_softc *psc = device_private(parent); 104 105 aprint_normal("\n"); 106 107 sc->sc_pc.sc_dev = self; 108 sc->sc_pc.sc_iot = psc->sc_iot; 109 sc->sc_ioh = psc->sc_ioh; 110 sc->sc_parent = psc; 111 112 ipaqpcic_init(sc); 113 114 for(i = 0; i < 2; i++) { 115 sc->sc_socket[i].sc = (struct sapcic_softc *)sc; 116 sc->sc_socket[i].socket = i; 117 sc->sc_socket[i].pcictag_cookie = psc; 118 sc->sc_socket[i].pcictag = &ipaqpcic_functions; 119 sc->sc_socket[i].event_thread = NULL; 120 sc->sc_socket[i].event = 0; 121 sc->sc_socket[i].laststatus = SAPCIC_CARD_INVALID; 122 sc->sc_socket[i].shutdown = 0; 123 124 paa.paa_busname = "pcmcia"; 125 paa.pct = (pcmcia_chipset_tag_t)&sa11x0_pcmcia_functions; 126 paa.pch = (pcmcia_chipset_handle_t)&sc->sc_socket[i]; 127 128 sc->sc_socket[i].pcmcia = 129 config_found(sc->sc_pc.sc_dev, &paa, ipaqpcic_print, 130 CFARGS_NONE); 131 132 sa11x0_intr_establish((sa11x0_chipset_tag_t)psc, 133 i ? IRQ_CD1 : IRQ_CD0, 134 1, IPL_BIO, sapcic_intr, 135 &sc->sc_socket[i]); 136 137 /* schedule kthread creation */ 138 sapcic_kthread_create(&sc->sc_socket[i]); 139 140#if 0 /* XXX */ 141 /* establish_intr should be after creating the kthread */ 142 config_interrupt(&sc->sc_socket[i], ipaqpcic_config_intr); 143#endif 144 } 145} 146 147static int 148ipaqpcic_print(void *aux, const char *name) 149{ 150 return (UNCONF); 151} 152 153static void 154ipaqpcic_init(struct ipaqpcic_softc *sc) 155{ 156 int cr; 157 158 /* All those are inputs */ 159 cr = bus_space_read_4(sc->sc_pc.sc_iot, sc->sc_parent->sc_gpioh, SAGPIO_PDR); 160 cr &= ~(GPIO_H3600_PCMCIA_CD0 | GPIO_H3600_PCMCIA_CD1 | GPIO_H3600_PCMCIA_IRQ0 | 161 GPIO_H3600_PCMCIA_IRQ1); 162 bus_space_write_4(sc->sc_pc.sc_iot, sc->sc_parent->sc_gpioh, SAGPIO_PDR, cr); 163 164 sc->sc_parent->ipaq_egpio |= 165 EGPIO_H3600_OPT_NVRAM_ON | EGPIO_H3600_OPT_ON ; 166 sc->sc_parent->ipaq_egpio &= 167 ~(EGPIO_H3600_CARD_RESET | EGPIO_H3600_OPT_RESET); 168 bus_space_write_2(sc->sc_pc.sc_iot, sc->sc_parent->sc_egpioh, 169 0, sc->sc_parent->ipaq_egpio); 170} 171 172static int 173ipaqpcic_read(struct sapcic_socket *so, int reg) 174{ 175 int cr, bit; 176 struct ipaqpcic_softc *sc = (struct ipaqpcic_softc *)so->sc; 177 178 cr = bus_space_read_4(sc->sc_pc.sc_iot, sc->sc_parent->sc_gpioh, SAGPIO_PLR); 179 180 switch (reg) { 181 case SAPCIC_STATUS_CARD: 182 bit = (so->socket ? GPIO_H3600_PCMCIA_CD0 : 183 GPIO_H3600_PCMCIA_CD1) & cr; 184 if (!bit) 185 return SAPCIC_CARD_INVALID; 186 else 187 return SAPCIC_CARD_VALID; 188 case SAPCIC_STATUS_VS1: 189 case SAPCIC_STATUS_VS2: 190 case SAPCIC_STATUS_READY: 191 bit = (so->socket ? GPIO_H3600_PCMCIA_IRQ0: 192 GPIO_H3600_PCMCIA_IRQ1); 193 return (bit & cr); 194 default: 195 panic("ipaqpcic_read: bogus register"); 196 } 197} 198 199static void 200ipaqpcic_write(struct sapcic_socket *so, int reg, int arg) 201{ 202 int s; 203 struct ipaqpcic_softc *sc = (struct ipaqpcic_softc *)so->sc; 204 205 s = splhigh(); 206 switch (reg) { 207 case SAPCIC_CONTROL_RESET: 208 sc->sc_parent->ipaq_egpio |= EGPIO_H3600_CARD_RESET; 209 break; 210 case SAPCIC_CONTROL_LINEENABLE: 211 case SAPCIC_CONTROL_WAITENABLE: 212 case SAPCIC_CONTROL_POWERSELECT: 213 break; 214 215 default: 216 splx(s); 217 panic("ipaqpcic_write: bogus register"); 218 } 219 bus_space_write_2(sc->sc_pc.sc_iot, sc->sc_parent->sc_egpioh, 0, 220 sc->sc_parent->ipaq_egpio); 221 splx(s); 222} 223 224static void 225ipaqpcic_set_power(struct sapcic_socket *so, int arg) 226{ 227 int s; 228 struct ipaqpcic_softc *sc = (struct ipaqpcic_softc *)so->sc; 229 230 s = splbio(); 231 switch (arg) { 232 case SAPCIC_POWER_OFF: 233 sc->sc_parent->ipaq_egpio &= 234 ~(EGPIO_H3600_OPT_NVRAM_ON | EGPIO_H3600_OPT_ON); 235 break; 236 case SAPCIC_POWER_3V: 237 case SAPCIC_POWER_5V: 238 sc->sc_parent->ipaq_egpio |= 239 EGPIO_H3600_OPT_NVRAM_ON | EGPIO_H3600_OPT_ON; 240 break; 241 default: 242 panic("ipaqpcic_set_power: bogus arg"); 243 } 244 bus_space_write_2(sc->sc_pc.sc_iot, sc->sc_parent->sc_egpioh, 245 0, sc->sc_parent->ipaq_egpio); 246 splx(s); 247} 248 249static void 250ipaqpcic_clear_intr(int arg) 251{ 252} 253 254static void * 255ipaqpcic_intr_establish(struct sapcic_socket *so, int level, 256 int (*ih_fun)(void *), void *ih_arg) 257{ 258 int irq; 259 260 irq = so->socket ? IRQ_IRQ0 : IRQ_IRQ1; 261 return (sa11x0_intr_establish((sa11x0_chipset_tag_t)so->pcictag_cookie, 262 irq-16, 1, level, ih_fun, ih_arg)); 263} 264 265static void 266ipaqpcic_intr_disestablish(struct sapcic_socket *so, void *ih) 267{ 268 sa11x0_intr_disestablish((sa11x0_chipset_tag_t)so->pcictag_cookie, ih); 269} 270