Home | History | Annotate | Line # | Download | only in isa
      1 /*	$OpenBSD: fins.c,v 1.1 2008/03/19 19:33:09 deraadt Exp $	*/
      2 /*	$NetBSD: finsio_isa.c,v 1.9 2022/06/29 15:56:58 mlelstv Exp $	*/
      3 
      4 /*
      5  * Copyright (c) 2008 Juan Romero Pardines
      6  * Copyright (c) 2007, 2008 Geoff Steckel
      7  * Copyright (c) 2005, 2006 Mark Kettenis
      8  *
      9  * Permission to use, copy, modify, and distribute this software for any
     10  * purpose with or without fee is hereby granted, provided that the above
     11  * copyright notice and this permission notice appear in all copies.
     12  *
     13  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
     14  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
     15  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
     16  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
     17  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
     18  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
     19  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
     20  */
     21 #include <sys/cdefs.h>
     22 __KERNEL_RCSID(0, "$NetBSD: finsio_isa.c,v 1.9 2022/06/29 15:56:58 mlelstv Exp $");
     23 
     24 #include <sys/param.h>
     25 #include <sys/systm.h>
     26 #include <sys/device.h>
     27 #include <sys/module.h>
     28 #include <sys/bus.h>
     29 
     30 #include <dev/isa/isareg.h>
     31 #include <dev/isa/isavar.h>
     32 
     33 #include <dev/sysmon/sysmonvar.h>
     34 
     35 /* Derived from LM78 code. Only handles chips attached to ISA bus */
     36 
     37 /*
     38  * Fintek F71805/F71883 Super I/O datasheets:
     39  * http://www.fintek.com.tw/files/productfiles/F71805F_V025.pdf
     40  * http://www.fintek.com.tw/files/productfiles/F71883_V026P.pdf
     41  *
     42  * This chip is a multi-io chip with many functions.
     43  * Each function may be relocated in I/O space by the BIOS.
     44  * The base address (2E or 4E) accesses a configuration space which
     45  * has pointers to the individual functions. The config space must be
     46  * unlocked with a cookie and relocked afterwards. The chip ID is stored
     47  * in config space so it is not normally visible.
     48  *
     49  * The voltage dividers specified are from reading the chips on one board.
     50  * There is no way to determine what they are in the general case.
     51  */
     52 
     53 #define FINSIO_UNLOCK	0x87	/* magic constant - write 2x to select chip */
     54 #define FINSIO_LOCK	0xaa	/* magic constant - write 1x to deselect reg */
     55 
     56 #define FINSIO_FUNC_SEL	0x07	/* select which subchip to access */
     57 #  define FINSIO_FUNC_HWMON 0x4
     58 
     59 /* ISA registers index to an internal register space on chip */
     60 #define FINSIO_DECODE_SIZE (8)
     61 #define FINSIO_DECODE_MASK (FINSIO_DECODE_SIZE - 1)
     62 #define FINSIO_ADDR	5	/* global configuration index */
     63 #define FINSIO_DATA	6	/* and data registers */
     64 
     65 /* Global configuration registers */
     66 #define FINSIO_MANUF	0x23	/* manufacturer ID */
     67 # define FINTEK_ID	0x1934
     68 #define FINSIO_CHIP	0x20	/* chip ID */
     69 # define FINSIO_IDF71805	0x0406
     70 # define FINSIO_IDF71806 	0x0341	/* F71872 and F1806 F/FG */
     71 # define FINSIO_IDF71883	0x0541	/* F71882 and F1883 */
     72 # define FINSIO_IDF71862 	0x0601	/* F71862FG */
     73 # define FINSIO_IDF8000 	0x0581	/* F8000 */
     74 
     75 /* in bank sensors of config space */
     76 #define FINSIO_SENSADDR	0x60	/* sensors assigned I/O address (2 bytes) */
     77 
     78 #define FINSIO_HWMON_CONF	0x01	/* Hardware Monitor Config. Register */
     79 
     80 /* in sensors space */
     81 #define FINSIO_TMODE	0x01	/* temperature mode reg */
     82 
     83 #define FINSIO_MAX_SENSORS	20
     84 /*
     85  * Fintek chips typically measure voltages using 8mv steps.
     86  * To measure higher voltages the input is attenuated with (external)
     87  * resistors.  Negative voltages are measured using inverting op amps
     88  * and resistors.  So we have to convert the sensor values back to
     89  * real voltages by applying the appropriate resistor factor.
     90  */
     91 #define FRFACT_NONE	8000
     92 #define FRFACT(x, y)	(FRFACT_NONE * ((x) + (y)) / (y))
     93 #define FNRFACT(x, y)	(-FRFACT_NONE * (x) / (y))
     94 
     95 #if defined(FINSIODEBUG)
     96 #define DPRINTF(x)		do { printf x; } while (0)
     97 #else
     98 #define DPRINTF(x)
     99 #endif
    100 
    101 struct finsio_softc {
    102 	bus_space_tag_t sc_iot;
    103 	bus_space_handle_t sc_ioh;
    104 
    105 	struct sysmon_envsys *sc_sme;
    106 	envsys_data_t sc_sensor[FINSIO_MAX_SENSORS];
    107 	struct finsio_sensor *sc_finsio_sensors;
    108 
    109 	u_int sc_tempsel;
    110 };
    111 
    112 struct finsio_sensor {
    113 	const char *fs_desc;
    114 	u_int fs_type;
    115 	uint8_t fs_aux;
    116 	uint8_t fs_reg;
    117 	void (*fs_refresh)(struct finsio_softc *, envsys_data_t *);
    118 	int fs_rfact;
    119 };
    120 
    121 static int 	finsio_isa_match(device_t, cfdata_t, void *);
    122 static void 	finsio_isa_attach(device_t, device_t, void *);
    123 static int 	finsio_isa_detach(device_t, int);
    124 
    125 static void	finsio_enter(bus_space_tag_t, bus_space_handle_t);
    126 static void 	finsio_exit(bus_space_tag_t, bus_space_handle_t);
    127 static uint8_t 	finsio_readreg(bus_space_tag_t, bus_space_handle_t, int);
    128 static void 	finsio_writereg(bus_space_tag_t, bus_space_handle_t, int, int);
    129 
    130 static void 	finsio_refresh(struct sysmon_envsys *, envsys_data_t *);
    131 static void 	finsio_refresh_volt(struct finsio_softc *, envsys_data_t *);
    132 static void 	finsio_refresh_temp(struct finsio_softc *, envsys_data_t *);
    133 static void 	finsio_refresh_fanrpm(struct finsio_softc *, envsys_data_t *);
    134 
    135 CFATTACH_DECL_NEW(finsio, sizeof(struct finsio_softc),
    136     finsio_isa_match, finsio_isa_attach, finsio_isa_detach, NULL);
    137 
    138 /* Sensors available in F71805/F71806 */
    139 static struct finsio_sensor f71805_sensors[] = {
    140 	/* Voltage */
    141 	{
    142 		.fs_desc = "+3.3V",
    143 		.fs_type = ENVSYS_SVOLTS_DC,
    144 		.fs_aux = 0,
    145 		.fs_reg = 0x10,
    146 		.fs_refresh = finsio_refresh_volt,
    147 		.fs_rfact = FRFACT(100, 100)
    148 	},
    149 	{
    150 		.fs_desc = "Vtt",
    151 		.fs_type = ENVSYS_SVOLTS_DC,
    152 		.fs_aux = 0,
    153 		.fs_reg = 0x11,
    154 		.fs_refresh = finsio_refresh_volt,
    155 		.fs_rfact = FRFACT_NONE
    156 	},
    157 	{
    158 		.fs_desc = "Vram",
    159 		.fs_type = ENVSYS_SVOLTS_DC,
    160 		.fs_aux = 0,
    161 		.fs_reg = 0x12,
    162 		.fs_refresh = finsio_refresh_volt,
    163 		.fs_rfact = FRFACT(100, 100)
    164 	},
    165 	{
    166 		.fs_desc = "Vchips",
    167 		.fs_type = ENVSYS_SVOLTS_DC,
    168 		.fs_aux = 0,
    169 		.fs_reg = 0x13,
    170 		.fs_refresh = finsio_refresh_volt,
    171 		.fs_rfact = FRFACT(47, 100)
    172 	},
    173 	{
    174 		.fs_desc = "+5V",
    175 		.fs_type = ENVSYS_SVOLTS_DC,
    176 		.fs_aux = 0,
    177 		.fs_reg = 0x14,
    178 		.fs_refresh = finsio_refresh_volt,
    179 		.fs_rfact = FRFACT(200, 47)
    180 	},
    181 	{
    182 		.fs_desc = "+12V",
    183 		.fs_type = ENVSYS_SVOLTS_DC,
    184 		.fs_aux = 0,
    185 		.fs_reg = 0x15,
    186 		.fs_refresh = finsio_refresh_volt,
    187 		.fs_rfact = FRFACT(200, 20)
    188 	},
    189 	{
    190 		.fs_desc = "Vcc 1.5V",
    191 		.fs_type = ENVSYS_SVOLTS_DC,
    192 		.fs_aux = 0,
    193 		.fs_reg = 0x16,
    194 		.fs_refresh = finsio_refresh_volt,
    195 		.fs_rfact = FRFACT_NONE
    196 	},
    197 	{
    198 		.fs_desc = "VCore",
    199 		.fs_type = ENVSYS_SVOLTS_DC,
    200 		.fs_aux = 0,
    201 		.fs_reg = 0x17,
    202 		.fs_refresh = finsio_refresh_volt,
    203 		.fs_rfact = FRFACT_NONE
    204 	},
    205 	{
    206 		.fs_desc = "Vsb",
    207 		.fs_type = ENVSYS_SVOLTS_DC,
    208 		.fs_aux = 0,
    209 		.fs_reg = 0x18,
    210 		.fs_refresh = finsio_refresh_volt,
    211 		.fs_rfact = FRFACT(200, 47)
    212 	},
    213 	{
    214 		.fs_desc = "Vsbint",
    215 		.fs_type = ENVSYS_SVOLTS_DC,
    216 		.fs_aux = 0,
    217 		.fs_reg = 0x19,
    218 		.fs_refresh = finsio_refresh_volt,
    219 		.fs_rfact = FRFACT(200, 47)
    220 	},
    221 	{
    222 		.fs_desc = "Vbat",
    223 		.fs_type = ENVSYS_SVOLTS_DC,
    224 		.fs_aux = 0,
    225 		.fs_reg = 0x1a,
    226 		.fs_refresh = finsio_refresh_volt,
    227 		.fs_rfact = FRFACT(200, 47)
    228 	},
    229 	/* Temperature */
    230 	{
    231 		.fs_desc = "Temp1",
    232 		.fs_type = ENVSYS_STEMP,
    233 		.fs_aux = 0x01,
    234 		.fs_reg = 0x1b,
    235 		.fs_refresh = finsio_refresh_temp,
    236 		.fs_rfact = 0
    237 	},
    238 	{
    239 		.fs_desc = "Temp2",
    240 		.fs_type = ENVSYS_STEMP,
    241 		.fs_aux = 0x02,
    242 		.fs_reg = 0x1c,
    243 		.fs_refresh = finsio_refresh_temp,
    244 		.fs_rfact = 0
    245 	},
    246 	{
    247 		.fs_desc = "Temp3",
    248 		.fs_type = ENVSYS_STEMP,
    249 		.fs_aux = 0x04,
    250 		.fs_reg = 0x1d,
    251 		.fs_refresh = finsio_refresh_temp,
    252 		.fs_rfact = 0
    253 	},
    254 	/* Fans */
    255 	{
    256 		.fs_desc = "Fan1",
    257 		.fs_type = ENVSYS_SFANRPM,
    258 		.fs_aux = 0,
    259 		.fs_reg = 0x20,
    260 		.fs_refresh = finsio_refresh_fanrpm,
    261 		.fs_rfact = 0
    262 	},
    263 	{
    264 		.fs_desc = "Fan2",
    265 		.fs_type = ENVSYS_SFANRPM,
    266 		.fs_aux = 0,
    267 		.fs_reg = 0x22,
    268 		.fs_refresh = finsio_refresh_fanrpm,
    269 		.fs_rfact = 0
    270 	},
    271 	{
    272 		.fs_desc = "Fan3",
    273 		.fs_type = ENVSYS_SFANRPM,
    274 		.fs_aux = 0,
    275 		.fs_reg = 0x24,
    276 		.fs_refresh = finsio_refresh_fanrpm,
    277 		.fs_rfact = 0
    278 	},
    279 
    280 	{	.fs_desc = NULL }
    281 };
    282 
    283 /* Sensors available in F71862/F71882/F71883 */
    284 static struct finsio_sensor f71883_sensors[] = {
    285 	/* Voltage */
    286 	{
    287 		.fs_desc = "+3.3V",
    288 		.fs_type = ENVSYS_SVOLTS_DC,
    289 		.fs_aux = 0,
    290 		.fs_reg = 0x20,
    291 		.fs_refresh = finsio_refresh_volt,
    292 		.fs_rfact = FRFACT(100, 100)
    293 	},
    294 	{
    295 		.fs_desc = "Vcore",
    296 		.fs_type = ENVSYS_SVOLTS_DC,
    297 		.fs_aux = 0,
    298 		.fs_reg = 0x21,
    299 		.fs_refresh = finsio_refresh_volt,
    300 		.fs_rfact = FRFACT_NONE
    301 	},
    302 	{
    303 		.fs_desc = "VIN2",
    304 		.fs_type = ENVSYS_SVOLTS_DC,
    305 		.fs_aux = 0,
    306 		.fs_reg = 0x22,
    307 		.fs_refresh = finsio_refresh_volt,
    308 		.fs_rfact = FRFACT(100, 100)
    309 	},
    310 	{
    311 		.fs_desc = "VIN3",
    312 		.fs_type = ENVSYS_SVOLTS_DC,
    313 		.fs_aux = 0,
    314 		.fs_reg = 0x23,
    315 		.fs_refresh = finsio_refresh_volt,
    316 		.fs_rfact = FRFACT(47, 100)
    317 	},
    318 	{
    319 		.fs_desc = "VIN4",
    320 		.fs_type = ENVSYS_SVOLTS_DC,
    321 		.fs_aux = 0,
    322 		.fs_reg = 0x24,
    323 		.fs_refresh = finsio_refresh_volt,
    324 		.fs_rfact = FRFACT(200, 47)
    325 	},
    326 	{
    327 		.fs_desc = "VIN5",
    328 		.fs_type = ENVSYS_SVOLTS_DC,
    329 		.fs_aux = 0,
    330 		.fs_reg = 0x25,
    331 		.fs_refresh = finsio_refresh_volt,
    332 		.fs_rfact = FRFACT(200, 20)
    333 	},
    334 	{
    335 		.fs_desc = "VIN6",
    336 		.fs_type = ENVSYS_SVOLTS_DC,
    337 		.fs_aux = 0,
    338 		.fs_reg = 0x26,
    339 		.fs_refresh = finsio_refresh_volt,
    340 		.fs_rfact = FRFACT(100, 100)
    341 	},
    342 	{
    343 		.fs_desc = "VSB +3.3V",
    344 		.fs_type = ENVSYS_SVOLTS_DC,
    345 		.fs_aux = 0,
    346 		.fs_reg = 0x27,
    347 		.fs_refresh = finsio_refresh_volt,
    348 		.fs_rfact = FRFACT(200, 47)
    349 	},
    350 	{
    351 		.fs_desc = "VBAT",
    352 		.fs_type = ENVSYS_SVOLTS_DC,
    353 		.fs_aux = 0,
    354 		.fs_reg = 0x28,
    355 		.fs_refresh = finsio_refresh_volt,
    356 		.fs_rfact = FRFACT(200, 47)
    357 	},
    358 	/* Temperature */
    359 	{
    360 		.fs_desc = "Temp1",
    361 		.fs_type = ENVSYS_STEMP,
    362 		.fs_aux = 0x1,
    363 		.fs_reg = 0x72,
    364 		.fs_refresh = finsio_refresh_temp,
    365 		.fs_rfact = 0
    366 	},
    367 	{
    368 		.fs_desc = "Temp2",
    369 		.fs_type = ENVSYS_STEMP,
    370 		.fs_aux = 0x2,
    371 		.fs_reg = 0x74,
    372 		.fs_refresh = finsio_refresh_temp,
    373 		.fs_rfact = 0
    374 	},
    375 	{
    376 		.fs_desc = "Temp3",
    377 		.fs_type = ENVSYS_STEMP,
    378 		.fs_aux = 0x4,
    379 		.fs_reg = 0x76,
    380 		.fs_refresh = finsio_refresh_temp,
    381 		.fs_rfact = 0
    382 	},
    383 	/* Fan */
    384 	{
    385 		.fs_desc = "Fan1",
    386 		.fs_type = ENVSYS_SFANRPM,
    387 		.fs_aux = 0,
    388 		.fs_reg = 0xa0,
    389 		.fs_refresh = finsio_refresh_fanrpm,
    390 		.fs_rfact = 0
    391 	},
    392 	{
    393 		.fs_desc = "Fan2",
    394 		.fs_type = ENVSYS_SFANRPM,
    395 		.fs_aux = 0,
    396 		.fs_reg = 0xb0,
    397 		.fs_refresh = finsio_refresh_fanrpm,
    398 		.fs_rfact = 0
    399 	},
    400 	{
    401 		.fs_desc = "Fan3",
    402 		.fs_type = ENVSYS_SFANRPM,
    403 		.fs_aux = 0,
    404 		.fs_reg = 0xc0,
    405 		.fs_refresh = finsio_refresh_fanrpm,
    406 		.fs_rfact = 0
    407 	},
    408 	{
    409 		.fs_desc = "Fan4",
    410 		.fs_type = ENVSYS_SFANRPM,
    411 		.fs_aux = 0,
    412 		.fs_reg = 0xd0,
    413 		.fs_refresh = finsio_refresh_fanrpm,
    414 		.fs_rfact = 0
    415 	},
    416 
    417 	{	.fs_desc = NULL }
    418 };
    419 
    420 static int
    421 finsio_isa_match(device_t parent, cfdata_t match, void *aux)
    422 {
    423 	struct isa_attach_args *ia = aux;
    424 	bus_space_handle_t ioh;
    425 	uint16_t val;
    426 
    427         /* Must supply an address */
    428 	if (ia->ia_nio < 1)
    429 		return 0;
    430 
    431 	if (ISA_DIRECT_CONFIG(ia))
    432 		return 0;
    433 
    434 	if (ia->ia_io[0].ir_addr == ISA_UNKNOWN_PORT)
    435 		return 0;
    436 
    437 	if (bus_space_map(ia->ia_iot, ia->ia_io[0].ir_addr, 2, 0, &ioh))
    438 		return 0;
    439 
    440 	finsio_enter(ia->ia_iot, ioh);
    441 	/* Find out Manufacturer ID */
    442 	val = finsio_readreg(ia->ia_iot, ioh, FINSIO_MANUF) << 8;
    443 	val |= finsio_readreg(ia->ia_iot, ioh, FINSIO_MANUF + 1);
    444 	finsio_exit(ia->ia_iot, ioh);
    445 	bus_space_unmap(ia->ia_iot, ioh, 2);
    446 
    447 	if (val != FINTEK_ID)
    448 		return 0;
    449 
    450 	ia->ia_nio = 1;
    451 	ia->ia_io[0].ir_size = 2;
    452 	ia->ia_niomem = 0;
    453 	ia->ia_nirq = 0;
    454 	ia->ia_ndrq = 0;
    455 
    456 	return 1;
    457 }
    458 
    459 static void
    460 finsio_isa_attach(device_t parent, device_t self, void *aux)
    461 {
    462 	struct finsio_softc *sc = device_private(self);
    463 	struct isa_attach_args *ia = aux;
    464 	bus_space_handle_t ioh;
    465 	uint16_t hwmon_baddr, chipid, cr;
    466 	int i, rv = 0;
    467 
    468 	aprint_naive("\n");
    469 
    470 	sc->sc_iot = ia->ia_iot;
    471 
    472 	/* Map Super I/O configuration space */
    473 	if (bus_space_map(sc->sc_iot, ia->ia_io[0].ir_addr, 2, 0, &ioh)) {
    474 		aprint_error(": can't map configuration I/O space\n");
    475 		return;
    476 	}
    477 
    478 	finsio_enter(sc->sc_iot, ioh);
    479 	/* Get the Chip ID */
    480 	chipid = finsio_readreg(sc->sc_iot, ioh, FINSIO_CHIP) << 8;
    481 	chipid |= finsio_readreg(sc->sc_iot, ioh, FINSIO_CHIP + 1);
    482 	/*
    483 	 * Select the Hardware Monitor LDN to find out the I/O
    484 	 * address space.
    485 	 */
    486 	finsio_writereg(sc->sc_iot, ioh, FINSIO_FUNC_SEL, FINSIO_FUNC_HWMON);
    487 	hwmon_baddr = finsio_readreg(sc->sc_iot, ioh, FINSIO_SENSADDR) << 8;
    488 	hwmon_baddr |= finsio_readreg(sc->sc_iot, ioh, FINSIO_SENSADDR + 1);
    489 	finsio_exit(sc->sc_iot, ioh);
    490 	bus_space_unmap(sc->sc_iot, ioh, 2);
    491 
    492 	/*
    493 	 * The address decoder ignores the bottom 3 bits, so do we.
    494 	 */
    495 	hwmon_baddr &= ~FINSIO_DECODE_MASK;
    496 
    497 	switch (chipid) {
    498 	case FINSIO_IDF71805:
    499 		sc->sc_finsio_sensors = f71805_sensors;
    500 		aprint_normal(": Fintek F71805 Super I/O\n");
    501 		break;
    502 	case FINSIO_IDF71806:
    503 		sc->sc_finsio_sensors = f71805_sensors;
    504 		aprint_normal(": Fintek F71806/F71872 Super I/O\n");
    505 		break;
    506 	case FINSIO_IDF71862:
    507 		sc->sc_finsio_sensors = f71883_sensors;
    508 		aprint_normal(": Fintek F71862 Super I/O\n");
    509 		break;
    510 	case FINSIO_IDF71883:
    511 		sc->sc_finsio_sensors = f71883_sensors;
    512 		aprint_normal(": Fintek F71882/F71883 Super I/O\n");
    513 		break;
    514 	case FINSIO_IDF8000:
    515 		sc->sc_finsio_sensors = f71883_sensors;
    516 		aprint_normal(": ASUS F8000 Super I/O\n");
    517 		break;
    518 	default:
    519 		/*
    520 		 * Unknown Chip ID, assume the same register layout
    521 		 * than F71805 for now.
    522 		 */
    523 		sc->sc_finsio_sensors = f71805_sensors;
    524 		aprint_normal(": Fintek Super I/O (unknown chip ID %x)\n",
    525 		    chipid);
    526 		break;
    527 	}
    528 
    529 	/* Map Hardware Monitor I/O space */
    530 	if (bus_space_map(sc->sc_iot, hwmon_baddr, FINSIO_DECODE_SIZE,
    531 	    0, &sc->sc_ioh)) {
    532 		aprint_error(": can't map hwmon I/O space\n");
    533 		return;
    534 	}
    535 
    536 	/*
    537 	 * Enable Hardware monitoring for fan/temperature and
    538 	 * voltage sensors.
    539 	 */
    540 	cr = finsio_readreg(sc->sc_iot, sc->sc_ioh, FINSIO_HWMON_CONF);
    541 	finsio_writereg(sc->sc_iot, sc->sc_ioh, FINSIO_HWMON_CONF, cr | 0x3);
    542 
    543 	/* Find out the temperature mode */
    544 	sc->sc_tempsel = finsio_readreg(sc->sc_iot, sc->sc_ioh, FINSIO_TMODE);
    545 
    546 	/*
    547 	 * Initialize and attach sensors with sysmon_envsys(9).
    548 	 */
    549 	sc->sc_sme = sysmon_envsys_create();
    550 	for (i = 0; sc->sc_finsio_sensors[i].fs_desc; i++) {
    551 		sc->sc_sensor[i].state = ENVSYS_SINVALID;
    552 		sc->sc_sensor[i].units = sc->sc_finsio_sensors[i].fs_type;
    553 		if (sc->sc_sensor[i].units == ENVSYS_SVOLTS_DC)
    554 			sc->sc_sensor[i].flags = ENVSYS_FCHANGERFACT;
    555 		strlcpy(sc->sc_sensor[i].desc, sc->sc_finsio_sensors[i].fs_desc,
    556 			sizeof(sc->sc_sensor[i].desc));
    557 		if (sysmon_envsys_sensor_attach(sc->sc_sme,
    558 						&sc->sc_sensor[i]))
    559 			goto fail;
    560 	}
    561 
    562 	sc->sc_sme->sme_name = device_xname(self);
    563 	sc->sc_sme->sme_cookie = sc;
    564 	sc->sc_sme->sme_refresh = finsio_refresh;
    565 	if ((rv = sysmon_envsys_register(sc->sc_sme))) {
    566 		aprint_error(": unable to register with sysmon (%d)\n", rv);
    567 		goto fail;
    568 	}
    569 
    570 	aprint_normal_dev(self,
    571 	    "Hardware Monitor registers at 0x%x\n", hwmon_baddr);
    572 	return;
    573 
    574 fail:
    575 	sysmon_envsys_destroy(sc->sc_sme);
    576 	sc->sc_sme = NULL;
    577 	bus_space_unmap(sc->sc_iot, sc->sc_ioh, FINSIO_DECODE_SIZE);
    578 }
    579 
    580 static int
    581 finsio_isa_detach(device_t self, int flags)
    582 {
    583 	struct finsio_softc *sc = device_private(self);
    584 
    585 	if (sc->sc_sme != NULL)
    586 		sysmon_envsys_unregister(sc->sc_sme);
    587 	bus_space_unmap(sc->sc_iot, sc->sc_ioh, FINSIO_DECODE_SIZE);
    588 	return 0;
    589 }
    590 
    591 /* Enter Super I/O configuration mode */
    592 static void
    593 finsio_enter(bus_space_tag_t iot, bus_space_handle_t ioh)
    594 {
    595 	bus_space_write_1(iot, ioh, FINSIO_ADDR, FINSIO_UNLOCK);
    596 	bus_space_write_1(iot, ioh, FINSIO_ADDR, FINSIO_UNLOCK);
    597 }
    598 
    599 /* Exit Super I/O configuration mode */
    600 static void
    601 finsio_exit(bus_space_tag_t iot, bus_space_handle_t ioh)
    602 {
    603 	bus_space_write_1(iot, ioh, FINSIO_ADDR, FINSIO_LOCK);
    604 }
    605 
    606 static uint8_t
    607 finsio_readreg(bus_space_tag_t iot, bus_space_handle_t ioh, int reg)
    608 {
    609 	bus_space_write_1(iot, ioh, FINSIO_ADDR, reg);
    610 	return bus_space_read_1(iot, ioh, FINSIO_DATA);
    611 }
    612 
    613 static void
    614 finsio_writereg(bus_space_tag_t iot, bus_space_handle_t ioh, int reg, int val)
    615 {
    616 	bus_space_write_1(iot, ioh, FINSIO_ADDR, reg);
    617 	bus_space_write_1(iot, ioh, FINSIO_DATA, val);
    618 }
    619 
    620 static void
    621 finsio_refresh(struct sysmon_envsys *sme, envsys_data_t *edata)
    622 {
    623 	struct finsio_softc *sc = sme->sme_cookie;
    624 	int i = edata->sensor;
    625 
    626 	sc->sc_finsio_sensors[i].fs_refresh(sc, edata);
    627 }
    628 
    629 static void
    630 finsio_refresh_volt(struct finsio_softc *sc, envsys_data_t *edata)
    631 {
    632 	struct finsio_sensor *fs = &sc->sc_finsio_sensors[edata->sensor];
    633 	int data;
    634 
    635 	data = finsio_readreg(sc->sc_iot, sc->sc_ioh, fs->fs_reg);
    636 	DPRINTF(("%s: data 0x%x\n", __func__, data));
    637 
    638 	if (data == 0xff || data == 0)
    639 		edata->state = ENVSYS_SINVALID;
    640 	else {
    641 		edata->state = ENVSYS_SVALID;
    642 		if (edata->rfact)
    643 			edata->value_cur = data * edata->rfact;
    644 		else
    645 			edata->value_cur = data * fs->fs_rfact;
    646 	}
    647 }
    648 
    649 /* The BIOS seems to add a fudge factor to the CPU temp of +5C */
    650 static void
    651 finsio_refresh_temp(struct finsio_softc *sc, envsys_data_t *edata)
    652 {
    653 	struct finsio_sensor *fs = &sc->sc_finsio_sensors[edata->sensor];
    654 	u_int data;
    655 	u_int llmax;
    656 
    657 	/*
    658 	 * The data sheet says that the range of the temperature
    659 	 * sensor is between 0 and 127 or 140 degrees C depending on
    660 	 * what kind of sensor is used.
    661 	 * A disconnected sensor seems to read over 110 or so.
    662 	 */
    663 	data = finsio_readreg(sc->sc_iot, sc->sc_ioh, fs->fs_reg) & 0xFF;
    664 	DPRINTF(("%s: data 0x%x\n", __func__, data));
    665 
    666 	llmax = (sc->sc_tempsel & fs->fs_aux) ? 111 : 128;
    667 	if (data == 0 || data >= llmax) 	/* disconnected? */
    668 		edata->state = ENVSYS_SINVALID;
    669 	else {
    670 		edata->state = ENVSYS_SVALID;
    671 		edata->value_cur = data * 1000000 + 273150000;
    672 	}
    673 }
    674 
    675 /* fan speed appears to be a 12-bit number */
    676 static void
    677 finsio_refresh_fanrpm(struct finsio_softc *sc, envsys_data_t *edata)
    678 {
    679 	struct finsio_sensor *fs = &sc->sc_finsio_sensors[edata->sensor];
    680 	int data;
    681 
    682 	data = finsio_readreg(sc->sc_iot, sc->sc_ioh, fs->fs_reg) << 8;
    683 	data |= finsio_readreg(sc->sc_iot, sc->sc_ioh, fs->fs_reg + 1);
    684 	DPRINTF(("%s: data 0x%x\n", __func__, data));
    685 
    686 	if (data >= 0xfff)
    687 		edata->state = ENVSYS_SINVALID;
    688 	else {
    689 		edata->value_cur = 1500000 / data;
    690 		edata->state = ENVSYS_SVALID;
    691 	}
    692 }
    693 
    694 MODULE(MODULE_CLASS_DRIVER, finsio, "sysmon_envsys");
    695 
    696 #ifdef _MODULE
    697 #include "ioconf.c"
    698 #endif
    699 
    700 static int
    701 finsio_modcmd(modcmd_t cmd, void *opaque)
    702 {
    703 	int error = 0;
    704 
    705 	switch (cmd) {
    706 	case MODULE_CMD_INIT:
    707 #ifdef _MODULE
    708 		error = config_init_component(cfdriver_ioconf_finsio,
    709 		    cfattach_ioconf_finsio, cfdata_ioconf_finsio);
    710 #endif
    711 		return error;
    712 	case MODULE_CMD_FINI:
    713 #ifdef _MODULE
    714 		error = config_fini_component(cfdriver_ioconf_finsio,
    715 		    cfattach_ioconf_finsio, cfdata_ioconf_finsio);
    716 #endif
    717 		return error;
    718 	default:
    719 		return ENOTTY;
    720 	}
    721 }
    722