1 1.34 thorpej /* $NetBSD: nsclpcsio_isa.c,v 1.34 2021/08/07 16:19:12 thorpej Exp $ */ 2 1.1 drochner 3 1.1 drochner /* 4 1.1 drochner * Copyright (c) 2002 5 1.1 drochner * Matthias Drochner. All rights reserved. 6 1.1 drochner * 7 1.1 drochner * Redistribution and use in source and binary forms, with or without 8 1.1 drochner * modification, are permitted provided that the following conditions 9 1.1 drochner * are met: 10 1.1 drochner * 1. Redistributions of source code must retain the above copyright 11 1.1 drochner * notice, this list of conditions, and the following disclaimer. 12 1.1 drochner * 2. Redistributions in binary form must reproduce the above copyright 13 1.1 drochner * notice, this list of conditions and the following disclaimer in the 14 1.1 drochner * documentation and/or other materials provided with the distribution. 15 1.1 drochner * 16 1.1 drochner * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 17 1.1 drochner * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 18 1.1 drochner * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 19 1.1 drochner * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 20 1.1 drochner * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 21 1.1 drochner * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 22 1.1 drochner * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 23 1.1 drochner * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 24 1.1 drochner * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 25 1.1 drochner * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 26 1.1 drochner * SUCH DAMAGE. 27 1.1 drochner */ 28 1.1 drochner 29 1.21 xtraeme /* 30 1.21 xtraeme * National Semiconductor PC87366 LPC Super I/O driver. 31 1.21 xtraeme * Supported logical devices: GPIO, TMS, VLM. 32 1.21 xtraeme */ 33 1.21 xtraeme 34 1.1 drochner #include <sys/cdefs.h> 35 1.34 thorpej __KERNEL_RCSID(0, "$NetBSD: nsclpcsio_isa.c,v 1.34 2021/08/07 16:19:12 thorpej Exp $"); 36 1.1 drochner 37 1.1 drochner #include <sys/param.h> 38 1.1 drochner #include <sys/systm.h> 39 1.1 drochner #include <sys/device.h> 40 1.16 xtraeme #include <sys/mutex.h> 41 1.11 jmcneill #include <sys/gpio.h> 42 1.20 ad #include <sys/bus.h> 43 1.30 jmcneill #include <sys/module.h> 44 1.1 drochner 45 1.28 ad /* Don't use gpio for now in the module */ 46 1.28 ad #ifdef _MODULE 47 1.19 xtraeme #undef NGPIO 48 1.19 xtraeme #endif 49 1.19 xtraeme 50 1.1 drochner #include <dev/isa/isareg.h> 51 1.1 drochner #include <dev/isa/isavar.h> 52 1.19 xtraeme 53 1.28 ad #ifndef _MODULE 54 1.12 drochner #include "gpio.h" 55 1.19 xtraeme #endif 56 1.12 drochner #if NGPIO > 0 57 1.11 jmcneill #include <dev/gpio/gpiovar.h> 58 1.12 drochner #endif 59 1.1 drochner #include <dev/sysmon/sysmonvar.h> 60 1.1 drochner 61 1.21 xtraeme #define SIO_REG_SID 0x20 /* Super I/O ID */ 62 1.21 xtraeme #define SIO_SID_PC87366 0xE9 /* PC87366 is identified by 0xE9.*/ 63 1.21 xtraeme 64 1.21 xtraeme #define SIO_REG_SRID 0x27 /* Super I/O Revision */ 65 1.21 xtraeme 66 1.21 xtraeme #define SIO_REG_LDN 0x07 /* Logical Device Number */ 67 1.21 xtraeme #define SIO_LDN_FDC 0x00 /* Floppy Disk Controller (FDC) */ 68 1.21 xtraeme #define SIO_LDN_PP 0x01 /* Parallel Port (PP) */ 69 1.21 xtraeme #define SIO_LDN_SP2 0x02 /* Serial Port 2 with IR (SP2) */ 70 1.21 xtraeme #define SIO_LDN_SP1 0x03 /* Serial Port 1 (SP1) */ 71 1.21 xtraeme #define SIO_LDN_SWC 0x04 /* System Wake-Up Control (SWC) */ 72 1.21 xtraeme #define SIO_LDN_KBCM 0x05 /* Mouse Controller (KBC) */ 73 1.21 xtraeme #define SIO_LDN_KBCK 0x06 /* Keyboard Controller (KBC) */ 74 1.21 xtraeme #define SIO_LDN_GPIO 0x07 /* General-Purpose I/O (GPIO) Ports */ 75 1.21 xtraeme #define SIO_LDN_ACB 0x08 /* ACCESS.bus Interface (ACB) */ 76 1.21 xtraeme #define SIO_LDN_FSCM 0x09 /* Fan Speed Control and Monitor (FSCM) */ 77 1.21 xtraeme #define SIO_LDN_WDT 0x0A /* WATCHDOG Timer (WDT) */ 78 1.21 xtraeme #define SIO_LDN_GMP 0x0B /* Game Port (GMP) */ 79 1.21 xtraeme #define SIO_LDN_MIDI 0x0C /* Musical Instrument Digital Interface */ 80 1.21 xtraeme #define SIO_LDN_VLM 0x0D /* Voltage Level Monitor (VLM) */ 81 1.21 xtraeme #define SIO_LDN_TMS 0x0E /* Temperature Sensor (TMS) */ 82 1.21 xtraeme 83 1.21 xtraeme #define SIO_REG_ACTIVE 0x30 /* Logical Device Activate Register */ 84 1.21 xtraeme #define SIO_ACTIVE_EN 0x01 /* enabled */ 85 1.21 xtraeme 86 1.21 xtraeme #define SIO_REG_IO_MSB 0x60 /* I/O Port Base, bits 15-8 */ 87 1.21 xtraeme #define SIO_REG_IO_LSB 0x61 /* I/O Port Base, bits 7-0 */ 88 1.21 xtraeme 89 1.21 xtraeme #define SIO_LDNUM 15 /* total number of logical devices */ 90 1.21 xtraeme 91 1.21 xtraeme /* Supported logical devices description */ 92 1.21 xtraeme static const struct { 93 1.21 xtraeme const char *ld_name; 94 1.21 xtraeme int ld_num; 95 1.21 xtraeme int ld_iosize; 96 1.21 xtraeme } sio_ld[] = { 97 1.21 xtraeme { "GPIO", SIO_LDN_GPIO, 16 }, 98 1.21 xtraeme { "VLM", SIO_LDN_VLM, 16 }, 99 1.21 xtraeme { "TMS", SIO_LDN_TMS, 16 } 100 1.21 xtraeme }; 101 1.21 xtraeme 102 1.21 xtraeme /* GPIO */ 103 1.21 xtraeme #define SIO_GPIO_PINSEL 0xf0 104 1.21 xtraeme #define SIO_GPIO_PINCFG 0xf1 105 1.21 xtraeme #define SIO_GPIO_PINEV 0xf2 106 1.1 drochner 107 1.11 jmcneill #define SIO_GPIO_CONF_OUTPUTEN (1 << 0) 108 1.11 jmcneill #define SIO_GPIO_CONF_PUSHPULL (1 << 1) 109 1.11 jmcneill #define SIO_GPIO_CONF_PULLUP (1 << 2) 110 1.11 jmcneill 111 1.21 xtraeme #define SIO_GPDO0 0x00 112 1.21 xtraeme #define SIO_GPDI0 0x01 113 1.21 xtraeme #define SIO_GPEVEN0 0x02 114 1.21 xtraeme #define SIO_GPEVST0 0x03 115 1.21 xtraeme #define SIO_GPDO1 0x04 116 1.21 xtraeme #define SIO_GPDI1 0x05 117 1.21 xtraeme #define SIO_GPEVEN1 0x06 118 1.21 xtraeme #define SIO_GPEVST1 0x07 119 1.21 xtraeme #define SIO_GPDO2 0x08 120 1.21 xtraeme #define SIO_GPDI2 0x09 121 1.21 xtraeme #define SIO_GPDO3 0x0a 122 1.21 xtraeme #define SIO_GPDI3 0x0b 123 1.21 xtraeme 124 1.21 xtraeme #define SIO_GPIO_NPINS 29 125 1.21 xtraeme 126 1.21 xtraeme /* TMS */ 127 1.21 xtraeme #define SIO_TEVSTS 0x00 /* Temperature Event Status */ 128 1.21 xtraeme #define SIO_TEVSMI 0x02 /* Temperature Event to SMI */ 129 1.21 xtraeme #define SIO_TEVIRQ 0x04 /* Temperature Event to IRQ */ 130 1.21 xtraeme #define SIO_TMSCFG 0x08 /* TMS Configuration */ 131 1.21 xtraeme #define SIO_TMSBS 0x09 /* TMS Bank Select */ 132 1.21 xtraeme #define SIO_TCHCFST 0x0a /* Temperature Channel Config and Status */ 133 1.21 xtraeme #define SIO_RDCHT 0x0b /* Read Channel Temperature */ 134 1.21 xtraeme #define SIO_CHTH 0x0c /* Channel Temperature High Limit */ 135 1.21 xtraeme #define SIO_CHTL 0x0d /* Channel Temperature Low Limit */ 136 1.21 xtraeme #define SIO_CHOTL 0x0e /* Channel Overtemperature Limit */ 137 1.21 xtraeme 138 1.21 xtraeme /* VLM */ 139 1.21 xtraeme #define SIO_VEVSTS0 0x00 /* Voltage Event Status 0 */ 140 1.21 xtraeme #define SIO_VEVSTS1 0x01 /* Voltage Event Status 1 */ 141 1.21 xtraeme #define SIO_VEVSMI0 0x02 /* Voltage Event to SMI 0 */ 142 1.21 xtraeme #define SIO_VEVSMI1 0x03 /* Voltage Event to SMI 1 */ 143 1.21 xtraeme #define SIO_VEVIRQ0 0x04 /* Voltage Event to IRQ 0 */ 144 1.21 xtraeme #define SIO_VEVIRQ1 0x05 /* Voltage Event to IRQ 1 */ 145 1.21 xtraeme #define SIO_VID 0x06 /* Voltage ID */ 146 1.21 xtraeme #define SIO_VCNVR 0x07 /* Voltage Conversion Rate */ 147 1.21 xtraeme #define SIO_VLMCFG 0x08 /* VLM Configuration */ 148 1.21 xtraeme #define SIO_VLMBS 0x09 /* VLM Bank Select */ 149 1.21 xtraeme #define SIO_VCHCFST 0x0a /* Voltage Channel Config and Status */ 150 1.21 xtraeme #define SIO_RDCHV 0x0b /* Read Channel Voltage */ 151 1.21 xtraeme #define SIO_CHVH 0x0c /* Channel Voltage High Limit */ 152 1.21 xtraeme #define SIO_CHVL 0x0d /* Channel Voltage Low Limit */ 153 1.21 xtraeme #define SIO_OTSL 0x0e /* Overtemperature Shutdown Limit */ 154 1.21 xtraeme 155 1.21 xtraeme #define SIO_REG_SIOCF1 0x21 156 1.21 xtraeme #define SIO_REG_SIOCF2 0x22 157 1.21 xtraeme #define SIO_REG_SIOCF3 0x23 158 1.21 xtraeme #define SIO_REG_SIOCF4 0x24 159 1.21 xtraeme #define SIO_REG_SIOCF5 0x25 160 1.21 xtraeme #define SIO_REG_SIOCF8 0x28 161 1.21 xtraeme #define SIO_REG_SIOCFA 0x2a 162 1.21 xtraeme #define SIO_REG_SIOCFB 0x2b 163 1.21 xtraeme #define SIO_REG_SIOCFC 0x2c 164 1.21 xtraeme #define SIO_REG_SIOCFD 0x2d 165 1.21 xtraeme 166 1.21 xtraeme #define SIO_VLM_OFF 3 167 1.21 xtraeme #define SIO_NUM_SENSORS (SIO_VLM_OFF + 14) 168 1.21 xtraeme #define SIO_VREF 1235 /* 1000.0 * VREF */ 169 1.21 xtraeme 170 1.1 drochner struct nsclpcsio_softc { 171 1.26 xtraeme device_t sc_dev; 172 1.26 xtraeme 173 1.21 xtraeme bus_space_tag_t sc_iot; 174 1.21 xtraeme bus_space_handle_t sc_ioh; 175 1.21 xtraeme 176 1.21 xtraeme bus_space_handle_t sc_ld_ioh[SIO_LDNUM]; 177 1.21 xtraeme int sc_ld_en[SIO_LDNUM]; 178 1.1 drochner 179 1.21 xtraeme /* TMS and VLM */ 180 1.22 xtraeme struct sysmon_envsys *sc_sme; 181 1.21 xtraeme envsys_data_t sc_sensor[SIO_NUM_SENSORS]; 182 1.21 xtraeme 183 1.16 xtraeme kmutex_t sc_lock; 184 1.12 drochner #if NGPIO > 0 185 1.11 jmcneill /* GPIO */ 186 1.11 jmcneill struct gpio_chipset_tag sc_gpio_gc; 187 1.21 xtraeme struct gpio_pin sc_gpio_pins[SIO_GPIO_NPINS]; 188 1.12 drochner #endif 189 1.1 drochner }; 190 1.1 drochner 191 1.11 jmcneill #define GPIO_READ(sc, reg) \ 192 1.21 xtraeme bus_space_read_1((sc)->sc_iot, \ 193 1.21 xtraeme (sc)->sc_ld_ioh[SIO_LDN_GPIO], (reg)) 194 1.11 jmcneill #define GPIO_WRITE(sc, reg, val) \ 195 1.21 xtraeme bus_space_write_1((sc)->sc_iot, \ 196 1.21 xtraeme (sc)->sc_ld_ioh[SIO_LDN_GPIO], (reg), (val)) 197 1.21 xtraeme #define TMS_WRITE(sc, reg, val) \ 198 1.21 xtraeme bus_space_write_1((sc)->sc_iot, \ 199 1.21 xtraeme (sc)->sc_ld_ioh[SIO_LDN_TMS], (reg), (val)) 200 1.21 xtraeme #define TMS_READ(sc, reg) \ 201 1.21 xtraeme bus_space_read_1((sc)->sc_iot, \ 202 1.21 xtraeme (sc)->sc_ld_ioh[SIO_LDN_TMS], (reg)) 203 1.21 xtraeme #define VLM_WRITE(sc, reg, val) \ 204 1.21 xtraeme bus_space_write_1((sc)->sc_iot, \ 205 1.21 xtraeme (sc)->sc_ld_ioh[SIO_LDN_VLM], (reg), (val)) 206 1.21 xtraeme #define VLM_READ(sc, reg) \ 207 1.21 xtraeme bus_space_read_1((sc)->sc_iot, \ 208 1.21 xtraeme (sc)->sc_ld_ioh[SIO_LDN_VLM], (reg)) 209 1.21 xtraeme 210 1.26 xtraeme static int nsclpcsio_isa_match(device_t, cfdata_t, void *); 211 1.26 xtraeme static void nsclpcsio_isa_attach(device_t, device_t, void *); 212 1.26 xtraeme static int nsclpcsio_isa_detach(device_t, int); 213 1.11 jmcneill 214 1.26 xtraeme CFATTACH_DECL_NEW(nsclpcsio_isa, sizeof(struct nsclpcsio_softc), 215 1.19 xtraeme nsclpcsio_isa_match, nsclpcsio_isa_attach, nsclpcsio_isa_detach, NULL); 216 1.1 drochner 217 1.21 xtraeme static uint8_t nsread(bus_space_tag_t, bus_space_handle_t, int); 218 1.21 xtraeme static void nswrite(bus_space_tag_t, bus_space_handle_t, int, uint8_t); 219 1.26 xtraeme static int nscheck(bus_space_tag_t, int); 220 1.1 drochner 221 1.21 xtraeme static void nsclpcsio_tms_init(struct nsclpcsio_softc *); 222 1.21 xtraeme static void nsclpcsio_vlm_init(struct nsclpcsio_softc *); 223 1.22 xtraeme static void nsclpcsio_refresh(struct sysmon_envsys *, envsys_data_t *); 224 1.1 drochner 225 1.12 drochner #if NGPIO > 0 226 1.11 jmcneill static void nsclpcsio_gpio_init(struct nsclpcsio_softc *); 227 1.11 jmcneill static void nsclpcsio_gpio_pin_select(struct nsclpcsio_softc *, int); 228 1.11 jmcneill static void nsclpcsio_gpio_pin_write(void *, int, int); 229 1.11 jmcneill static int nsclpcsio_gpio_pin_read(void *, int); 230 1.11 jmcneill static void nsclpcsio_gpio_pin_ctl(void *, int, int); 231 1.12 drochner #endif 232 1.11 jmcneill 233 1.21 xtraeme static uint8_t 234 1.21 xtraeme nsread(bus_space_tag_t iot, bus_space_handle_t ioh, int idx) 235 1.1 drochner { 236 1.1 drochner bus_space_write_1(iot, ioh, 0, idx); 237 1.21 xtraeme return bus_space_read_1(iot, ioh, 1); 238 1.1 drochner } 239 1.1 drochner 240 1.1 drochner static void 241 1.21 xtraeme nswrite(bus_space_tag_t iot, bus_space_handle_t ioh, int idx, uint8_t data) 242 1.1 drochner { 243 1.1 drochner bus_space_write_1(iot, ioh, 0, idx); 244 1.1 drochner bus_space_write_1(iot, ioh, 1, data); 245 1.1 drochner } 246 1.1 drochner 247 1.1 drochner static int 248 1.21 xtraeme nscheck(bus_space_tag_t iot, int base) 249 1.1 drochner { 250 1.1 drochner bus_space_handle_t ioh; 251 1.1 drochner int rv = 0; 252 1.1 drochner 253 1.1 drochner if (bus_space_map(iot, base, 2, 0, &ioh)) 254 1.21 xtraeme return 0; 255 1.1 drochner 256 1.1 drochner /* XXX this is for PC87366 only for now */ 257 1.21 xtraeme if (nsread(iot, ioh, SIO_REG_SID) == SIO_SID_PC87366) 258 1.1 drochner rv = 1; 259 1.1 drochner 260 1.1 drochner bus_space_unmap(iot, ioh, 2); 261 1.21 xtraeme return rv; 262 1.1 drochner } 263 1.1 drochner 264 1.1 drochner static int 265 1.26 xtraeme nsclpcsio_isa_match(device_t parent, cfdata_t match, void *aux) 266 1.1 drochner { 267 1.1 drochner struct isa_attach_args *ia = aux; 268 1.1 drochner int iobase; 269 1.1 drochner 270 1.1 drochner if (ISA_DIRECT_CONFIG(ia)) 271 1.21 xtraeme return 0; 272 1.1 drochner 273 1.6 drochner if (ia->ia_nio > 0 && ia->ia_io[0].ir_addr != ISA_UNKNOWN_PORT) { 274 1.1 drochner /* XXX check for legal iobase ??? */ 275 1.1 drochner if (nscheck(ia->ia_iot, ia->ia_io[0].ir_addr)) { 276 1.1 drochner iobase = ia->ia_io[0].ir_addr; 277 1.1 drochner goto found; 278 1.1 drochner } 279 1.21 xtraeme return 0; 280 1.1 drochner } 281 1.1 drochner 282 1.1 drochner /* PC87366 has two possible locations depending on wiring */ 283 1.1 drochner if (nscheck(ia->ia_iot, 0x2e)) { 284 1.1 drochner iobase = 0x2e; 285 1.1 drochner goto found; 286 1.1 drochner } 287 1.1 drochner if (nscheck(ia->ia_iot, 0x4e)) { 288 1.1 drochner iobase = 0x4e; 289 1.1 drochner goto found; 290 1.1 drochner } 291 1.21 xtraeme 292 1.21 xtraeme return 0; 293 1.1 drochner 294 1.1 drochner found: 295 1.1 drochner ia->ia_nio = 1; 296 1.1 drochner ia->ia_io[0].ir_addr = iobase; 297 1.1 drochner ia->ia_io[0].ir_size = 2; 298 1.1 drochner ia->ia_niomem = 0; 299 1.1 drochner ia->ia_nirq = 0; 300 1.1 drochner ia->ia_ndrq = 0; 301 1.21 xtraeme 302 1.21 xtraeme return 1; 303 1.1 drochner } 304 1.1 drochner 305 1.25 dyoung static struct sysmon_envsys * 306 1.25 dyoung nsclpcsio_envsys_init(struct nsclpcsio_softc *sc) 307 1.25 dyoung { 308 1.25 dyoung int i; 309 1.25 dyoung struct sysmon_envsys *sme; 310 1.25 dyoung 311 1.25 dyoung sme = sysmon_envsys_create(); 312 1.25 dyoung for (i = 0; i < SIO_NUM_SENSORS; i++) { 313 1.29 pgoyette sc->sc_sensor[i].state = ENVSYS_SINVALID; 314 1.25 dyoung if (sysmon_envsys_sensor_attach(sme, &sc->sc_sensor[i]) != 0) { 315 1.26 xtraeme aprint_error_dev(sc->sc_dev, 316 1.25 dyoung "could not attach sensor %d", i); 317 1.25 dyoung goto err; 318 1.25 dyoung } 319 1.25 dyoung } 320 1.25 dyoung 321 1.25 dyoung /* 322 1.25 dyoung * Hook into the System Monitor. 323 1.25 dyoung */ 324 1.26 xtraeme sme->sme_name = device_xname(sc->sc_dev); 325 1.25 dyoung sme->sme_cookie = sc; 326 1.25 dyoung sme->sme_refresh = nsclpcsio_refresh; 327 1.25 dyoung 328 1.26 xtraeme if ((i = sysmon_envsys_register(sme)) != 0) { 329 1.26 xtraeme aprint_error_dev(sc->sc_dev, 330 1.26 xtraeme "unable to register with sysmon (%d)\n", i); 331 1.25 dyoung goto err; 332 1.25 dyoung } 333 1.25 dyoung return sme; 334 1.25 dyoung err: 335 1.25 dyoung sysmon_envsys_destroy(sme); 336 1.25 dyoung return NULL; 337 1.25 dyoung } 338 1.25 dyoung 339 1.1 drochner static void 340 1.26 xtraeme nsclpcsio_isa_attach(device_t parent, device_t self, void *aux) 341 1.1 drochner { 342 1.21 xtraeme struct nsclpcsio_softc *sc = device_private(self); 343 1.1 drochner struct isa_attach_args *ia = aux; 344 1.12 drochner #if NGPIO > 0 345 1.11 jmcneill struct gpiobus_attach_args gba; 346 1.12 drochner #endif 347 1.21 xtraeme int i, iobase; 348 1.1 drochner 349 1.23 ad mutex_init(&sc->sc_lock, MUTEX_DEFAULT, IPL_NONE); 350 1.11 jmcneill 351 1.26 xtraeme sc->sc_dev = self; 352 1.21 xtraeme sc->sc_iot = ia->ia_iot; 353 1.21 xtraeme iobase = ia->ia_io[0].ir_addr; 354 1.11 jmcneill 355 1.21 xtraeme if (bus_space_map(ia->ia_iot, iobase, 2, 0, &sc->sc_ioh)) { 356 1.21 xtraeme aprint_error(": can't map i/o space\n"); 357 1.24 dyoung return; 358 1.24 dyoung } 359 1.11 jmcneill 360 1.32 msaitoh aprint_normal(": NSC PC87366 rev. %d ", 361 1.21 xtraeme nsread(sc->sc_iot, sc->sc_ioh, SIO_REG_SRID)); 362 1.11 jmcneill 363 1.21 xtraeme /* Configure all supported logical devices */ 364 1.21 xtraeme for (i = 0; i < __arraycount(sio_ld); i++) { 365 1.21 xtraeme sc->sc_ld_en[sio_ld[i].ld_num] = 0; 366 1.21 xtraeme 367 1.21 xtraeme /* Select the device and check if it's activated */ 368 1.21 xtraeme nswrite(sc->sc_iot, sc->sc_ioh, SIO_REG_LDN, sio_ld[i].ld_num); 369 1.21 xtraeme if ((nsread(sc->sc_iot, sc->sc_ioh, 370 1.21 xtraeme SIO_REG_ACTIVE) & SIO_ACTIVE_EN) == 0) 371 1.21 xtraeme continue; 372 1.21 xtraeme 373 1.21 xtraeme /* Map I/O space if necessary */ 374 1.21 xtraeme if (sio_ld[i].ld_iosize != 0) { 375 1.21 xtraeme iobase = (nsread(sc->sc_iot, sc->sc_ioh, 376 1.21 xtraeme SIO_REG_IO_MSB) << 8); 377 1.21 xtraeme iobase |= nsread(sc->sc_iot, sc->sc_ioh, 378 1.21 xtraeme SIO_REG_IO_LSB); 379 1.21 xtraeme if (bus_space_map(sc->sc_iot, iobase, 380 1.21 xtraeme sio_ld[i].ld_iosize, 0, 381 1.21 xtraeme &sc->sc_ld_ioh[sio_ld[i].ld_num])) 382 1.21 xtraeme continue; 383 1.22 xtraeme } 384 1.21 xtraeme 385 1.21 xtraeme sc->sc_ld_en[sio_ld[i].ld_num] = 1; 386 1.21 xtraeme aprint_normal("%s ", sio_ld[i].ld_name); 387 1.21 xtraeme } 388 1.21 xtraeme 389 1.21 xtraeme aprint_normal("\n"); 390 1.21 xtraeme 391 1.21 xtraeme #if NGPIO > 0 392 1.21 xtraeme nsclpcsio_gpio_init(sc); 393 1.21 xtraeme #endif 394 1.21 xtraeme nsclpcsio_tms_init(sc); 395 1.21 xtraeme nsclpcsio_vlm_init(sc); 396 1.25 dyoung sc->sc_sme = nsclpcsio_envsys_init(sc); 397 1.11 jmcneill 398 1.12 drochner #if NGPIO > 0 399 1.11 jmcneill /* attach GPIO framework */ 400 1.21 xtraeme if (sc->sc_ld_en[SIO_LDN_GPIO]) { 401 1.11 jmcneill gba.gba_gc = &sc->sc_gpio_gc; 402 1.11 jmcneill gba.gba_pins = sc->sc_gpio_pins; 403 1.21 xtraeme gba.gba_npins = SIO_GPIO_NPINS; 404 1.34 thorpej config_found(self, &gba, NULL, CFARGS_NONE); 405 1.11 jmcneill } 406 1.12 drochner #endif 407 1.1 drochner } 408 1.1 drochner 409 1.19 xtraeme static int 410 1.26 xtraeme nsclpcsio_isa_detach(device_t self, int flags) 411 1.19 xtraeme { 412 1.25 dyoung int i, rc; 413 1.19 xtraeme struct nsclpcsio_softc *sc = device_private(self); 414 1.19 xtraeme 415 1.25 dyoung if ((rc = config_detach_children(self, flags)) != 0) 416 1.25 dyoung return rc; 417 1.25 dyoung 418 1.25 dyoung if (sc->sc_sme != NULL) 419 1.25 dyoung sysmon_envsys_unregister(sc->sc_sme); 420 1.21 xtraeme mutex_destroy(&sc->sc_lock); 421 1.21 xtraeme 422 1.25 dyoung for (i = 0; i < __arraycount(sio_ld); i++) { 423 1.25 dyoung if (sc->sc_ld_en[sio_ld[i].ld_num] && 424 1.25 dyoung sio_ld[i].ld_iosize != 0) { 425 1.25 dyoung bus_space_unmap(sc->sc_iot, 426 1.25 dyoung sc->sc_ld_ioh[sio_ld[i].ld_num], 427 1.25 dyoung sio_ld[i].ld_iosize); 428 1.25 dyoung } 429 1.25 dyoung } 430 1.25 dyoung 431 1.19 xtraeme bus_space_unmap(sc->sc_iot, sc->sc_ioh, 2); 432 1.21 xtraeme 433 1.19 xtraeme return 0; 434 1.19 xtraeme } 435 1.19 xtraeme 436 1.1 drochner static void 437 1.21 xtraeme nsclpcsio_tms_init(struct nsclpcsio_softc *sc) 438 1.21 xtraeme { 439 1.21 xtraeme int i; 440 1.1 drochner 441 1.21 xtraeme /* Initialisation, PC87366.pdf, page 208 */ 442 1.21 xtraeme TMS_WRITE(sc, 0x08, 0x00); 443 1.21 xtraeme TMS_WRITE(sc, 0x09, 0x0f); 444 1.21 xtraeme TMS_WRITE(sc, 0x0a, 0x08); 445 1.21 xtraeme TMS_WRITE(sc, 0x0b, 0x04); 446 1.21 xtraeme TMS_WRITE(sc, 0x0c, 0x35); 447 1.21 xtraeme TMS_WRITE(sc, 0x0d, 0x05); 448 1.21 xtraeme TMS_WRITE(sc, 0x0e, 0x05); 449 1.21 xtraeme 450 1.21 xtraeme TMS_WRITE(sc, SIO_TMSCFG, 0x00); 451 1.21 xtraeme 452 1.21 xtraeme for (i = 0; i < SIO_VLM_OFF; i++) { 453 1.21 xtraeme TMS_WRITE(sc, SIO_TMSBS, i); 454 1.21 xtraeme TMS_WRITE(sc, SIO_TCHCFST, 0x01); 455 1.21 xtraeme sc->sc_sensor[i].units = ENVSYS_STEMP; 456 1.21 xtraeme } 457 1.21 xtraeme 458 1.21 xtraeme #define COPYDESCR(x, y) \ 459 1.21 xtraeme do { \ 460 1.21 xtraeme (void)strlcpy((x), (y), sizeof(x)); \ 461 1.21 xtraeme } while (/* CONSTCOND */ 0) 462 1.21 xtraeme 463 1.21 xtraeme COPYDESCR(sc->sc_sensor[0].desc, "TSENS1"); 464 1.21 xtraeme COPYDESCR(sc->sc_sensor[1].desc, "TSENS2"); 465 1.21 xtraeme COPYDESCR(sc->sc_sensor[2].desc, "TNSC"); 466 1.21 xtraeme } 467 1.21 xtraeme 468 1.21 xtraeme static void 469 1.21 xtraeme nsclpcsio_vlm_init(struct nsclpcsio_softc *sc) 470 1.21 xtraeme { 471 1.21 xtraeme int i; 472 1.21 xtraeme char tmp[16]; 473 1.25 dyoung envsys_data_t *sensor = &sc->sc_sensor[SIO_VLM_OFF]; 474 1.11 jmcneill 475 1.25 dyoung for (i = 0; i < SIO_NUM_SENSORS - SIO_VLM_OFF; i++) { 476 1.25 dyoung VLM_WRITE(sc, SIO_VLMBS, i); 477 1.21 xtraeme VLM_WRITE(sc, SIO_VCHCFST, 0x01); 478 1.25 dyoung sensor[i].units = ENVSYS_SVOLTS_DC; 479 1.21 xtraeme } 480 1.21 xtraeme 481 1.21 xtraeme for (i = 0; i < 7; i++) { 482 1.21 xtraeme (void)snprintf(tmp, sizeof(tmp), "VSENS%d", i); 483 1.25 dyoung COPYDESCR(sensor[i].desc, tmp); 484 1.21 xtraeme } 485 1.21 xtraeme 486 1.25 dyoung COPYDESCR(sensor[7 ].desc, "VSB"); 487 1.25 dyoung COPYDESCR(sensor[8 ].desc, "VDD"); 488 1.25 dyoung COPYDESCR(sensor[9 ].desc, "VBAT"); 489 1.25 dyoung COPYDESCR(sensor[10].desc, "AVDD"); 490 1.25 dyoung COPYDESCR(sensor[11].desc, "TS1"); 491 1.25 dyoung COPYDESCR(sensor[12].desc, "TS2"); 492 1.25 dyoung COPYDESCR(sensor[13].desc, "TS3"); 493 1.21 xtraeme } 494 1.11 jmcneill 495 1.1 drochner 496 1.22 xtraeme static void 497 1.22 xtraeme nsclpcsio_refresh(struct sysmon_envsys *sme, envsys_data_t *edata) 498 1.21 xtraeme { 499 1.21 xtraeme struct nsclpcsio_softc *sc = sme->sme_cookie; 500 1.21 xtraeme uint8_t status, data; 501 1.21 xtraeme int8_t sdata = 0; 502 1.21 xtraeme int scale, rfact; 503 1.1 drochner 504 1.21 xtraeme scale = rfact = 0; 505 1.21 xtraeme status = data = 0; 506 1.1 drochner 507 1.21 xtraeme mutex_enter(&sc->sc_lock); 508 1.21 xtraeme /* TMS */ 509 1.21 xtraeme if (edata->sensor < SIO_VLM_OFF && sc->sc_ld_en[SIO_LDN_TMS]) { 510 1.21 xtraeme TMS_WRITE(sc, SIO_TMSBS, edata->sensor); 511 1.21 xtraeme status = TMS_READ(sc, SIO_TCHCFST); 512 1.21 xtraeme if (!(status & 0x01)) 513 1.21 xtraeme edata->state = ENVSYS_SINVALID; 514 1.21 xtraeme 515 1.21 xtraeme sdata = TMS_READ(sc, SIO_RDCHT); 516 1.21 xtraeme edata->value_cur = sdata * 1000000 + 273150000; 517 1.21 xtraeme edata->state = ENVSYS_SVALID; 518 1.21 xtraeme /* VLM */ 519 1.21 xtraeme } else if (edata->sensor >= SIO_VLM_OFF && 520 1.21 xtraeme edata->sensor < SIO_NUM_SENSORS && 521 1.21 xtraeme sc->sc_ld_en[SIO_LDN_VLM]) { 522 1.21 xtraeme VLM_WRITE(sc, SIO_VLMBS, edata->sensor - SIO_VLM_OFF); 523 1.21 xtraeme status = VLM_READ(sc, SIO_VCHCFST); 524 1.21 xtraeme if (!(status & 0x01)) { 525 1.21 xtraeme edata->state = ENVSYS_SINVALID; 526 1.21 xtraeme } else { 527 1.21 xtraeme data = VLM_READ(sc, SIO_RDCHV); 528 1.21 xtraeme scale = 1; 529 1.21 xtraeme switch (edata->sensor - SIO_VLM_OFF) { 530 1.21 xtraeme case 7: 531 1.21 xtraeme case 8: 532 1.21 xtraeme case 10: 533 1.21 xtraeme scale = 2; 534 1.21 xtraeme break; 535 1.21 xtraeme } 536 1.21 xtraeme /* Vi = (2.450.05)*VREF *RDCHVi / 256 */ 537 1.21 xtraeme rfact = 10 * scale * ((245 * SIO_VREF) >> 8); 538 1.21 xtraeme edata->value_cur = data * rfact; 539 1.21 xtraeme edata->state = ENVSYS_SVALID; 540 1.1 drochner } 541 1.1 drochner } 542 1.16 xtraeme mutex_exit(&sc->sc_lock); 543 1.1 drochner } 544 1.11 jmcneill 545 1.12 drochner #if NGPIO > 0 546 1.11 jmcneill static void 547 1.11 jmcneill nsclpcsio_gpio_pin_select(struct nsclpcsio_softc *sc, int pin) 548 1.11 jmcneill { 549 1.21 xtraeme uint8_t v; 550 1.11 jmcneill 551 1.11 jmcneill v = ((pin / 8) << 4) | (pin % 8); 552 1.11 jmcneill 553 1.21 xtraeme nswrite(sc->sc_iot, sc->sc_ioh, SIO_REG_LDN, SIO_LDN_GPIO); 554 1.21 xtraeme nswrite(sc->sc_iot, sc->sc_ioh, SIO_GPIO_PINSEL, v); 555 1.11 jmcneill } 556 1.11 jmcneill 557 1.11 jmcneill static void 558 1.11 jmcneill nsclpcsio_gpio_init(struct nsclpcsio_softc *sc) 559 1.11 jmcneill { 560 1.11 jmcneill int i; 561 1.11 jmcneill 562 1.21 xtraeme for (i = 0; i < SIO_GPIO_NPINS; i++) { 563 1.11 jmcneill sc->sc_gpio_pins[i].pin_num = i; 564 1.11 jmcneill sc->sc_gpio_pins[i].pin_caps = GPIO_PIN_INPUT | 565 1.11 jmcneill GPIO_PIN_OUTPUT | GPIO_PIN_OPENDRAIN | 566 1.11 jmcneill GPIO_PIN_PUSHPULL | GPIO_PIN_TRISTATE | 567 1.11 jmcneill GPIO_PIN_PULLUP; 568 1.11 jmcneill /* safe defaults */ 569 1.11 jmcneill sc->sc_gpio_pins[i].pin_flags = GPIO_PIN_TRISTATE; 570 1.11 jmcneill sc->sc_gpio_pins[i].pin_state = GPIO_PIN_LOW; 571 1.11 jmcneill nsclpcsio_gpio_pin_ctl(sc, i, sc->sc_gpio_pins[i].pin_flags); 572 1.11 jmcneill nsclpcsio_gpio_pin_write(sc, i, sc->sc_gpio_pins[i].pin_state); 573 1.11 jmcneill } 574 1.11 jmcneill 575 1.11 jmcneill /* create controller tag */ 576 1.11 jmcneill sc->sc_gpio_gc.gp_cookie = sc; 577 1.11 jmcneill sc->sc_gpio_gc.gp_pin_read = nsclpcsio_gpio_pin_read; 578 1.11 jmcneill sc->sc_gpio_gc.gp_pin_write = nsclpcsio_gpio_pin_write; 579 1.11 jmcneill sc->sc_gpio_gc.gp_pin_ctl = nsclpcsio_gpio_pin_ctl; 580 1.11 jmcneill } 581 1.11 jmcneill 582 1.11 jmcneill static int 583 1.11 jmcneill nsclpcsio_gpio_pin_read(void *aux, int pin) 584 1.11 jmcneill { 585 1.11 jmcneill struct nsclpcsio_softc *sc = (struct nsclpcsio_softc *)aux; 586 1.11 jmcneill int port, shift, reg; 587 1.21 xtraeme uint8_t v; 588 1.11 jmcneill 589 1.11 jmcneill port = pin / 8; 590 1.11 jmcneill shift = pin % 8; 591 1.11 jmcneill 592 1.11 jmcneill switch (port) { 593 1.21 xtraeme case 0: 594 1.21 xtraeme reg = SIO_GPDI0; 595 1.21 xtraeme break; 596 1.21 xtraeme case 1: 597 1.21 xtraeme reg = SIO_GPDI1; 598 1.21 xtraeme break; 599 1.21 xtraeme case 2: 600 1.21 xtraeme reg = SIO_GPDI2; 601 1.21 xtraeme break; 602 1.21 xtraeme case 3: 603 1.21 xtraeme reg = SIO_GPDI3; 604 1.21 xtraeme break; 605 1.21 xtraeme default: 606 1.21 xtraeme reg = SIO_GPDI0; 607 1.21 xtraeme break; 608 1.11 jmcneill } 609 1.11 jmcneill 610 1.11 jmcneill v = GPIO_READ(sc, reg); 611 1.11 jmcneill 612 1.11 jmcneill return ((v >> shift) & 0x1); 613 1.11 jmcneill } 614 1.11 jmcneill 615 1.11 jmcneill static void 616 1.11 jmcneill nsclpcsio_gpio_pin_write(void *aux, int pin, int v) 617 1.11 jmcneill { 618 1.11 jmcneill struct nsclpcsio_softc *sc = (struct nsclpcsio_softc *)aux; 619 1.11 jmcneill int port, shift, reg; 620 1.21 xtraeme uint8_t d; 621 1.11 jmcneill 622 1.11 jmcneill port = pin / 8; 623 1.11 jmcneill shift = pin % 8; 624 1.11 jmcneill 625 1.11 jmcneill switch (port) { 626 1.21 xtraeme case 0: 627 1.21 xtraeme reg = SIO_GPDO0; 628 1.21 xtraeme break; 629 1.21 xtraeme case 1: 630 1.21 xtraeme reg = SIO_GPDO1; 631 1.21 xtraeme break; 632 1.21 xtraeme case 2: 633 1.21 xtraeme reg = SIO_GPDO2; 634 1.21 xtraeme break; 635 1.21 xtraeme case 3: 636 1.21 xtraeme reg = SIO_GPDO3; 637 1.21 xtraeme break; 638 1.21 xtraeme default: 639 1.21 xtraeme reg = SIO_GPDO0; 640 1.21 xtraeme break; /* shouldn't happen */ 641 1.11 jmcneill } 642 1.11 jmcneill 643 1.11 jmcneill d = GPIO_READ(sc, reg); 644 1.11 jmcneill if (v == 0) 645 1.11 jmcneill d &= ~(1 << shift); 646 1.11 jmcneill else if (v == 1) 647 1.11 jmcneill d |= (1 << shift); 648 1.11 jmcneill GPIO_WRITE(sc, reg, d); 649 1.11 jmcneill } 650 1.11 jmcneill 651 1.11 jmcneill void 652 1.11 jmcneill nsclpcsio_gpio_pin_ctl(void *aux, int pin, int flags) 653 1.11 jmcneill { 654 1.11 jmcneill struct nsclpcsio_softc *sc = (struct nsclpcsio_softc *)aux; 655 1.21 xtraeme uint8_t conf; 656 1.11 jmcneill 657 1.16 xtraeme mutex_enter(&sc->sc_lock); 658 1.11 jmcneill 659 1.21 xtraeme nswrite(sc->sc_iot, sc->sc_ioh, SIO_REG_LDN, SIO_LDN_GPIO); 660 1.11 jmcneill nsclpcsio_gpio_pin_select(sc, pin); 661 1.21 xtraeme conf = nsread(sc->sc_iot, sc->sc_ioh, SIO_GPIO_PINCFG); 662 1.11 jmcneill 663 1.11 jmcneill conf &= ~(SIO_GPIO_CONF_OUTPUTEN | SIO_GPIO_CONF_PUSHPULL | 664 1.11 jmcneill SIO_GPIO_CONF_PULLUP); 665 1.11 jmcneill if ((flags & GPIO_PIN_TRISTATE) == 0) 666 1.11 jmcneill conf |= SIO_GPIO_CONF_OUTPUTEN; 667 1.11 jmcneill if (flags & GPIO_PIN_PUSHPULL) 668 1.11 jmcneill conf |= SIO_GPIO_CONF_PUSHPULL; 669 1.11 jmcneill if (flags & GPIO_PIN_PULLUP) 670 1.11 jmcneill conf |= SIO_GPIO_CONF_PULLUP; 671 1.11 jmcneill 672 1.21 xtraeme nswrite(sc->sc_iot, sc->sc_ioh, SIO_GPIO_PINCFG, conf); 673 1.11 jmcneill 674 1.16 xtraeme mutex_exit(&sc->sc_lock); 675 1.11 jmcneill } 676 1.12 drochner #endif /* NGPIO */ 677 1.30 jmcneill 678 1.31 pgoyette MODULE(MODULE_CLASS_DRIVER, nsclpcsio, "sysmon_envsys"); 679 1.30 jmcneill 680 1.30 jmcneill #ifdef _MODULE 681 1.30 jmcneill #include "ioconf.c" 682 1.30 jmcneill #endif 683 1.30 jmcneill 684 1.30 jmcneill static int 685 1.30 jmcneill nsclpcsio_modcmd(modcmd_t cmd, void *opaque) 686 1.30 jmcneill { 687 1.30 jmcneill switch (cmd) { 688 1.30 jmcneill case MODULE_CMD_INIT: 689 1.30 jmcneill #ifdef _MODULE 690 1.30 jmcneill return config_init_component(cfdriver_ioconf_nsclpcsio, 691 1.30 jmcneill cfattach_ioconf_nsclpcsio, cfdata_ioconf_nsclpcsio); 692 1.30 jmcneill #else 693 1.30 jmcneill return 0; 694 1.30 jmcneill #endif 695 1.30 jmcneill case MODULE_CMD_FINI: 696 1.30 jmcneill #ifdef _MODULE 697 1.30 jmcneill return config_fini_component(cfdriver_ioconf_nsclpcsio, 698 1.30 jmcneill cfattach_ioconf_nsclpcsio, cfdata_ioconf_nsclpcsio); 699 1.30 jmcneill #else 700 1.30 jmcneill return 0; 701 1.30 jmcneill #endif 702 1.30 jmcneill default: 703 1.30 jmcneill return ENOTTY; 704 1.30 jmcneill } 705 1.30 jmcneill } 706