Home | History | Annotate | Line # | Download | only in isa
nsclpcsio_isa.c revision 1.32.30.1
      1  1.32.30.1   thorpej /* $NetBSD: nsclpcsio_isa.c,v 1.32.30.1 2021/03/23 07:14:53 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.32.30.1   thorpej __KERNEL_RCSID(0, "$NetBSD: nsclpcsio_isa.c,v 1.32.30.1 2021/03/23 07:14:53 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.32.30.1   thorpej 		config_found(self, &gba, NULL, CFARG_EOL);
    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