Home | History | Annotate | Line # | Download | only in i2c
w83795g.c revision 1.2.30.1
      1  1.2.30.1  pgoyette /*	$NetBSD: w83795g.c,v 1.2.30.1 2018/06/25 07:25:50 pgoyette Exp $	*/
      2       1.1     soren 
      3       1.1     soren /*
      4       1.1     soren  * Copyright (c) 2013 Soren S. Jorvang.  All rights reserved.
      5       1.1     soren  *
      6       1.1     soren  * Redistribution and use in source and binary forms, with or without
      7       1.1     soren  * modification, are permitted provided that the following conditions
      8       1.1     soren  * are met:
      9       1.1     soren  * 1. Redistributions of source code must retain the above copyright
     10       1.1     soren  *    notice, this list of conditions, and the following disclaimer.
     11       1.1     soren  * 2. Redistributions in binary form must reproduce the above copyright
     12       1.1     soren  *    notice, this list of conditions and the following disclaimer in the
     13       1.1     soren  *    documentation and/or other materials provided with the distribution.
     14       1.1     soren  *
     15       1.1     soren  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
     16       1.1     soren  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
     17       1.1     soren  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
     18       1.1     soren  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
     19       1.1     soren  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
     20       1.1     soren  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
     21       1.1     soren  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
     22       1.1     soren  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
     23       1.1     soren  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
     24       1.1     soren  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
     25       1.1     soren  * SUCH DAMAGE.
     26       1.1     soren  */
     27       1.1     soren 
     28       1.1     soren #include <sys/cdefs.h>
     29  1.2.30.1  pgoyette __KERNEL_RCSID(0, "$NetBSD: w83795g.c,v 1.2.30.1 2018/06/25 07:25:50 pgoyette Exp $");
     30       1.1     soren 
     31       1.1     soren #include <sys/param.h>
     32       1.1     soren #include <sys/systm.h>
     33       1.1     soren #include <sys/device.h>
     34       1.1     soren #include <sys/conf.h>
     35       1.1     soren #include <sys/gpio.h>
     36       1.1     soren #include <sys/wdog.h>
     37       1.1     soren 
     38       1.1     soren #include <dev/i2c/i2cvar.h>
     39       1.1     soren #include <dev/gpio/gpiovar.h>
     40       1.1     soren #include <dev/sysmon/sysmonvar.h>
     41       1.1     soren 
     42       1.1     soren #include <dev/i2c/w83795greg.h>
     43       1.1     soren 
     44       1.1     soren #define NUM_SENSORS 53
     45       1.1     soren static const struct w83795g_sensor {
     46       1.1     soren 	const char *desc;
     47       1.1     soren 	enum envsys_units type;
     48       1.1     soren 	uint8_t en_reg;
     49       1.1     soren 	uint8_t en_mask;
     50       1.1     soren 	uint8_t en_bits;
     51       1.1     soren 	uint8_t msb;
     52       1.1     soren } sensors[NUM_SENSORS] = {
     53       1.1     soren #define _VOLT ENVSYS_SVOLTS_DC
     54       1.1     soren 	{ "VSEN1",   _VOLT, W83795G_V_CTRL1, 0x01, 0x01, W83795G_VSEN1 },
     55       1.1     soren 	{ "VSEN2",   _VOLT, W83795G_V_CTRL1, 0x02, 0x02, W83795G_VSEN2 },
     56       1.1     soren 	{ "VSEN3",   _VOLT, W83795G_V_CTRL1, 0x04, 0x04, W83795G_VSEN3 },
     57       1.1     soren 	{ "VSEN4",   _VOLT, W83795G_V_CTRL1, 0x08, 0x08, W83795G_VSEN4 },
     58       1.1     soren 	{ "VSEN5",   _VOLT, W83795G_V_CTRL1, 0x10, 0x10, W83795G_VSEN5 },
     59       1.1     soren 	{ "VSEN6",   _VOLT, W83795G_V_CTRL1, 0x20, 0x20, W83795G_VSEN6 },
     60       1.1     soren 	{ "VSEN7",   _VOLT, W83795G_V_CTRL1, 0x40, 0x40, W83795G_VSEN7 },
     61       1.1     soren 	{ "VSEN8",   _VOLT, W83795G_V_CTRL1, 0x80, 0x80, W83795G_VSEN8 },
     62       1.1     soren 	{ "VSEN9",   _VOLT, W83795G_V_CTRL2, 0x01, 0x01, W83795G_VSEN9 },
     63       1.1     soren 	{ "VSEN10",  _VOLT, W83795G_V_CTRL2, 0x02, 0x02, W83795G_VSEN10 },
     64       1.1     soren 	{ "VSEN11",  _VOLT, W83795G_V_CTRL2, 0x04, 0x04, W83795G_VSEN11 },
     65       1.1     soren 	{ "VTT",     _VOLT, W83795G_V_CTRL2, 0x08, 0x08, W83795G_VTT },
     66       1.1     soren 	{ "3VDD",    _VOLT, W83795G_V_CTRL2, 0x10, 0x10, W83795G_3VDD },
     67       1.1     soren 	{ "3VSB",    _VOLT, W83795G_V_CTRL2, 0x20, 0x20, W83795G_3VSB },
     68       1.1     soren 	{ "VBAT",    _VOLT, W83795G_V_CTRL2, 0x40, 0x40, W83795G_VBAT },
     69       1.1     soren 	{ "VSEN12",  _VOLT, W83795G_T_CTRL1, 0x03, 0x02, W83795G_VSEN12 },
     70       1.1     soren 	{ "VSEN13",  _VOLT, W83795G_T_CTRL1, 0x0c, 0x08, W83795G_VSEN13 },
     71       1.1     soren 	{ "VDSEN14", _VOLT, W83795G_T_CTRL2, 0x03, 0x02, W83795G_VDSEN14 },
     72       1.1     soren 	{ "VDSEN15", _VOLT, W83795G_T_CTRL2, 0x0c, 0x08, W83795G_VDSEN15 },
     73       1.1     soren 	{ "VDSEN16", _VOLT, W83795G_T_CTRL2, 0x30, 0x20, W83795G_VDSEN16 },
     74       1.1     soren 	{ "VDSEN17", _VOLT, W83795G_T_CTRL2, 0xc0, 0x80, W83795G_VDSEN17 },
     75       1.1     soren #define _TEMP ENVSYS_STEMP
     76       1.1     soren 	{ "TR5",     _TEMP, W83795G_T_CTRL1, 0x03, 0x03, W83795G_TR5 },
     77       1.1     soren 	{ "TR6",     _TEMP, W83795G_T_CTRL1, 0x0c, 0x0c, W83795G_TR6 },
     78       1.1     soren 	{ "TD1",     _TEMP, W83795G_T_CTRL2, 0x03, 0x01, W83795G_TD1 },
     79       1.1     soren 	{ "TD2",     _TEMP, W83795G_T_CTRL2, 0x0c, 0x04, W83795G_TD2 },
     80       1.1     soren 	{ "TD3",     _TEMP, W83795G_T_CTRL2, 0x30, 0x10, W83795G_TD3 },
     81       1.1     soren 	{ "TD4",     _TEMP, W83795G_T_CTRL2, 0xc0, 0x40, W83795G_TD4 },
     82       1.1     soren 	{ "TR1",     _TEMP, W83795G_T_CTRL2, 0x03, 0x03, W83795G_TR1 },
     83       1.1     soren 	{ "TR2",     _TEMP, W83795G_T_CTRL2, 0x0c, 0x0c, W83795G_TR2 },
     84       1.1     soren 	{ "TR3",     _TEMP, W83795G_T_CTRL2, 0x30, 0x30, W83795G_TR3 },
     85       1.1     soren 	{ "TR4",     _TEMP, W83795G_T_CTRL2, 0xc0, 0xc0, W83795G_TR4 },
     86       1.1     soren 	{ "DTS1",    _TEMP, W83795G_T_CTRL1, 0x20, 0x20, W83795G_DTS1 },
     87       1.1     soren 	{ "DTS2",    _TEMP, W83795G_T_CTRL1, 0x20, 0x20, W83795G_DTS2 },
     88       1.1     soren 	{ "DTS3",    _TEMP, W83795G_T_CTRL1, 0x20, 0x20, W83795G_DTS3 },
     89       1.1     soren 	{ "DTS4",    _TEMP, W83795G_T_CTRL1, 0x20, 0x20, W83795G_DTS4 },
     90       1.1     soren 	{ "DTS5",    _TEMP, W83795G_T_CTRL1, 0x20, 0x20, W83795G_DTS5 },
     91       1.1     soren 	{ "DTS6",    _TEMP, W83795G_T_CTRL1, 0x20, 0x20, W83795G_DTS6 },
     92       1.1     soren 	{ "DTS7",    _TEMP, W83795G_T_CTRL1, 0x20, 0x20, W83795G_DTS7 },
     93       1.1     soren 	{ "DTS8",    _TEMP, W83795G_T_CTRL1, 0x20, 0x20, W83795G_DTS8 },
     94       1.1     soren #define _FAN ENVSYS_SFANRPM
     95       1.1     soren 	{ "FANIN1",  _FAN,  W83795G_F_CTRL1, 0x01, 0x01, W83795G_FANIN1 },
     96       1.1     soren 	{ "FANIN2",  _FAN,  W83795G_F_CTRL1, 0x02, 0x02, W83795G_FANIN2 },
     97       1.1     soren 	{ "FANIN3",  _FAN,  W83795G_F_CTRL1, 0x04, 0x04, W83795G_FANIN3 },
     98       1.1     soren 	{ "FANIN4",  _FAN,  W83795G_F_CTRL1, 0x08, 0x08, W83795G_FANIN4 },
     99       1.1     soren 	{ "FANIN5",  _FAN,  W83795G_F_CTRL1, 0x10, 0x10, W83795G_FANIN5 },
    100       1.1     soren 	{ "FANIN6",  _FAN,  W83795G_F_CTRL1, 0x20, 0x20, W83795G_FANIN6 },
    101       1.1     soren 	{ "FANIN7",  _FAN,  W83795G_F_CTRL1, 0x40, 0x40, W83795G_FANIN7 },
    102       1.1     soren 	{ "FANIN8",  _FAN,  W83795G_F_CTRL1, 0x80, 0x80, W83795G_FANIN8 },
    103       1.1     soren 	{ "FANIN9",  _FAN,  W83795G_F_CTRL2, 0x01, 0x01, W83795G_FANIN9 },
    104       1.1     soren 	{ "FANIN10", _FAN,  W83795G_F_CTRL2, 0x02, 0x02, W83795G_FANIN10 },
    105       1.1     soren 	{ "FANIN11", _FAN,  W83795G_F_CTRL2, 0x04, 0x04, W83795G_FANIN11 },
    106       1.1     soren 	{ "FANIN12", _FAN,  W83795G_F_CTRL2, 0x08, 0x08, W83795G_FANIN12 },
    107       1.1     soren 	{ "FANIN13", _FAN,  W83795G_F_CTRL2, 0x10, 0x10, W83795G_FANIN13 },
    108       1.1     soren 	{ "FANIN14", _FAN,  W83795G_F_CTRL2, 0x20, 0x20, W83795G_FANIN14 },
    109       1.1     soren };
    110       1.1     soren 
    111       1.1     soren struct w83795g_softc {
    112       1.1     soren 	device_t		sc_dev;
    113       1.1     soren 	i2c_tag_t		sc_tag;
    114       1.1     soren 	i2c_addr_t		sc_addr;
    115       1.1     soren 	struct gpio_chipset_tag	sc_gpio_gc;
    116       1.1     soren 	gpio_pin_t		sc_gpio_pins[8];
    117       1.1     soren 	struct sysmon_envsys	*sc_sme;
    118       1.1     soren 	envsys_data_t 		sc_sensors[NUM_SENSORS];
    119       1.1     soren 	struct sysmon_wdog	sc_smw;
    120       1.1     soren };
    121       1.1     soren 
    122       1.1     soren static int	w83795g_match(device_t, cfdata_t, void *);
    123       1.1     soren static void	w83795g_attach(device_t, device_t, void *);
    124       1.1     soren 
    125       1.1     soren CFATTACH_DECL_NEW(w83795g, sizeof(struct w83795g_softc),
    126       1.1     soren     w83795g_match, w83795g_attach, NULL, NULL);
    127       1.1     soren 
    128       1.1     soren static void	w83795g_refresh(struct sysmon_envsys *, envsys_data_t *);
    129       1.1     soren static void	w83795g_get_limits(struct sysmon_envsys *, envsys_data_t *,
    130       1.1     soren    sysmon_envsys_lim_t *limits, uint32_t *props);
    131       1.1     soren 
    132       1.1     soren static int	w83795g_gpio_read(void *, int);
    133       1.1     soren static void	w83795g_gpio_write(void *, int, int);
    134       1.1     soren static void	w83795g_gpio_ctl(void *, int, int);
    135       1.1     soren 
    136       1.1     soren static int	w83795g_wdog_setmode(struct sysmon_wdog *);
    137       1.1     soren static int	w83795g_wdog_tickle(struct sysmon_wdog *);
    138       1.1     soren 
    139       1.1     soren static int
    140       1.1     soren w83795g_match(device_t parent, cfdata_t match, void *aux)
    141       1.1     soren {
    142       1.1     soren 	struct i2c_attach_args *ia = aux;
    143       1.1     soren 	uint8_t bank, vend, chip, deva;
    144       1.1     soren 
    145       1.1     soren 	if (ia->ia_addr < I2CADDR_MINADDR || ia->ia_addr > I2CADDR_MAXADDR)
    146       1.1     soren 		return 0;
    147       1.1     soren 
    148       1.1     soren 	iic_acquire_bus(ia->ia_tag, 0);
    149       1.1     soren 	iic_smbus_read_byte(ia->ia_tag, ia->ia_addr, W83795G_BANKSEL, &bank, 0);
    150       1.1     soren 	iic_smbus_read_byte(ia->ia_tag, ia->ia_addr, W83795G_VENDOR, &vend, 0);
    151       1.1     soren 	iic_smbus_read_byte(ia->ia_tag, ia->ia_addr, W83795G_CHIP, &chip, 0);
    152       1.1     soren 	iic_smbus_read_byte(ia->ia_tag, ia->ia_addr, W83795G_DEVICEA, &deva, 0);
    153       1.1     soren 	iic_release_bus(ia->ia_tag, 0);
    154       1.1     soren 
    155       1.1     soren 	if ((bank & BANKSEL_HBACS && vend == VENDOR_NUVOTON_ID_HI) ||
    156       1.1     soren 	   (~bank & BANKSEL_HBACS && vend == VENDOR_NUVOTON_ID_LO))
    157       1.1     soren 		if (chip == CHIP_W83795G && deva == DEVICEA_A)
    158  1.2.30.1  pgoyette 			return I2C_MATCH_ADDRESS_AND_PROBE;
    159       1.1     soren 
    160       1.1     soren 	return 0;
    161       1.1     soren }
    162       1.1     soren 
    163       1.1     soren static void
    164       1.1     soren w83795g_attach(device_t parent, device_t self, void *aux)
    165       1.1     soren {
    166       1.1     soren 	struct w83795g_softc *sc = device_private(self);
    167       1.1     soren 	struct i2c_attach_args *ia = aux;
    168       1.1     soren 	struct gpiobus_attach_args gba;
    169       1.1     soren 	uint8_t conf, rev, reg, gpiom, en_reg;
    170       1.1     soren 	int i;
    171       1.1     soren 
    172       1.1     soren 	sc->sc_dev = self;
    173       1.1     soren 	sc->sc_tag = ia->ia_tag;
    174       1.1     soren 	sc->sc_addr = ia->ia_addr;
    175       1.1     soren 	sc->sc_gpio_gc.gp_cookie = sc;
    176       1.1     soren 	sc->sc_gpio_gc.gp_pin_read = w83795g_gpio_read;
    177       1.1     soren 	sc->sc_gpio_gc.gp_pin_write = w83795g_gpio_write;
    178       1.1     soren 	sc->sc_gpio_gc.gp_pin_ctl = w83795g_gpio_ctl;
    179       1.1     soren 	sc->sc_sme = sysmon_envsys_create();
    180       1.1     soren 	sc->sc_sme->sme_name = device_xname(self);
    181       1.1     soren 	sc->sc_sme->sme_cookie = sc;
    182       1.1     soren 	sc->sc_sme->sme_refresh = w83795g_refresh;
    183       1.1     soren 	sc->sc_sme->sme_get_limits = w83795g_get_limits;
    184       1.1     soren 	sc->sc_smw.smw_name = device_xname(self);
    185       1.1     soren 	sc->sc_smw.smw_cookie = sc;
    186       1.1     soren 	sc->sc_smw.smw_setmode = w83795g_wdog_setmode;
    187       1.1     soren 	sc->sc_smw.smw_tickle = w83795g_wdog_tickle;
    188       1.1     soren 	sc->sc_smw.smw_period = 60;
    189       1.1     soren 
    190       1.1     soren 	iic_acquire_bus(sc->sc_tag, 0);
    191       1.1     soren 	iic_smbus_write_byte(sc->sc_tag, sc->sc_addr, W83795G_BANKSEL, 0, 0);
    192       1.1     soren 	iic_smbus_read_byte(sc->sc_tag, sc->sc_addr, W83795G_CONFIG, &conf, 0);
    193       1.1     soren 	iic_smbus_read_byte(sc->sc_tag, sc->sc_addr, W83795G_DEVICE, &rev, 0);
    194       1.1     soren 
    195       1.1     soren 	aprint_normal(": Nuvaton W83795");
    196       1.1     soren 	if (conf & CONFIG_CONFIG48)
    197       1.1     soren 		aprint_normal("ADG");
    198       1.1     soren 	else
    199       1.1     soren 		aprint_normal("G");
    200       1.1     soren 	aprint_verbose(" (rev %c)", rev - DEVICEA_A + 'A');
    201       1.1     soren 	aprint_normal(" Hardware Monitor\n");
    202       1.1     soren 	aprint_naive(": Hardware Monitor\n");
    203       1.1     soren 
    204       1.1     soren 	/* Debug dump of all register banks */
    205       1.1     soren 	for (i = 0; i < 1024; i++) {
    206       1.1     soren 		if (i % 256 == 0) {
    207       1.1     soren 			iic_smbus_write_byte(sc->sc_tag, sc->sc_addr,
    208       1.1     soren 			    W83795G_BANKSEL, i / 256, 0);
    209       1.1     soren 			aprint_debug_dev(self, "register bank %d:\n", i / 256);
    210       1.1     soren 		}
    211       1.1     soren 		if (i % 32 == 0)
    212       1.1     soren 			aprint_debug_dev(self, "%02x ", i % 256);
    213       1.1     soren 		iic_smbus_read_byte(sc->sc_tag, sc->sc_addr, i % 256, &reg, 0);
    214       1.1     soren 		aprint_debug("%02x", reg);
    215       1.1     soren 		if (i % 32 == 31)
    216       1.1     soren 			aprint_debug("\n");
    217       1.1     soren 		else if (i % 8 == 7)
    218       1.1     soren 			aprint_debug(" ");
    219       1.1     soren 	}
    220       1.1     soren 
    221       1.1     soren 	iic_smbus_write_byte(sc->sc_tag, sc->sc_addr, W83795G_BANKSEL, 0, 0);
    222       1.1     soren 
    223       1.1     soren 	for (i = 0; i < NUM_SENSORS; i++) {
    224       1.1     soren 		iic_smbus_read_byte(sc->sc_tag, sc->sc_addr,
    225       1.1     soren 		    sensors[i].en_reg, &en_reg, 0);
    226       1.1     soren 
    227       1.1     soren 		if ((en_reg & sensors[i].en_mask) != sensors[i].en_bits)
    228       1.1     soren 			continue;
    229       1.1     soren 
    230       1.1     soren 		strcpy(sc->sc_sensors[i].desc, sensors[i].desc);
    231       1.1     soren 		sc->sc_sensors[i].units = sensors[i].type;
    232       1.1     soren 		sc->sc_sensors[i].state = ENVSYS_SINVALID;
    233       1.1     soren 		sc->sc_sensors[i].flags = ENVSYS_FMONLIMITS;
    234       1.1     soren 		sc->sc_sensors[i].flags |= ENVSYS_FHAS_ENTROPY;
    235       1.1     soren 		sc->sc_sensors[i].private = i;
    236       1.1     soren 		sysmon_envsys_sensor_attach(sc->sc_sme, &sc->sc_sensors[i]);
    237       1.1     soren 	}
    238       1.1     soren 
    239       1.1     soren 	iic_smbus_read_byte(sc->sc_tag, sc->sc_addr, W83795G_GPIO_M, &gpiom, 0);
    240       1.1     soren 	iic_release_bus(sc->sc_tag, 0);
    241       1.1     soren 
    242       1.1     soren 	if (conf & CONFIG_CONFIG48)
    243       1.1     soren 		gba.gba_npins = 4;
    244       1.1     soren 	else
    245       1.1     soren 		gba.gba_npins = 8;
    246       1.1     soren 	gba.gba_gc = &sc->sc_gpio_gc;
    247       1.1     soren 	gba.gba_pins = sc->sc_gpio_pins;
    248       1.1     soren 
    249       1.1     soren 	for (i = 0; i < gba.gba_npins; i++) {
    250       1.1     soren 		sc->sc_gpio_pins[i].pin_num = i;
    251       1.1     soren 		sc->sc_gpio_pins[i].pin_caps = GPIO_PIN_OUTPUT | GPIO_PIN_INPUT;
    252       1.1     soren 		sc->sc_gpio_pins[i].pin_flags = (gpiom & (1 << i)) ?
    253       1.1     soren 		    GPIO_PIN_OUTPUT : GPIO_PIN_INPUT;
    254       1.1     soren 		sc->sc_gpio_pins[i].pin_state = w83795g_gpio_read(sc, i);
    255       1.1     soren 	}
    256       1.1     soren 
    257       1.1     soren 	if (sysmon_envsys_register(sc->sc_sme))
    258       1.1     soren 		aprint_error_dev(self, "unable to register with sysmon\n");
    259       1.1     soren 
    260       1.1     soren 	if (sysmon_wdog_register(&sc->sc_smw) != 0)
    261       1.1     soren 		aprint_error_dev(self, "couldn't register watchdog\n");
    262       1.1     soren 
    263       1.1     soren 	if (!pmf_device_register(self, NULL, NULL))
    264       1.1     soren 		aprint_error_dev(self, "couldn't establish power handler\n");
    265       1.1     soren 
    266       1.1     soren 	config_found(self, &gba, gpiobus_print);
    267       1.1     soren }
    268       1.1     soren 
    269       1.1     soren static void
    270       1.1     soren w83795g_refresh(struct sysmon_envsys *sme, envsys_data_t *edata)
    271       1.1     soren {
    272       1.1     soren 	struct w83795g_softc *sc = sme->sme_cookie;
    273       1.1     soren 	const struct w83795g_sensor *sensor = &sensors[edata->private];
    274       1.1     soren 	uint8_t msb, lsb;
    275       1.1     soren 
    276       1.1     soren 	sensor = &sensors[edata->private];
    277       1.1     soren 
    278       1.1     soren 	iic_acquire_bus(sc->sc_tag, 0);
    279       1.1     soren 	iic_smbus_write_byte(sc->sc_tag, sc->sc_addr, W83795G_BANKSEL, 0, 0);
    280       1.1     soren 	iic_smbus_read_byte(sc->sc_tag, sc->sc_addr, sensor->msb, &msb, 0);
    281       1.1     soren 	iic_smbus_read_byte(sc->sc_tag, sc->sc_addr, W83795G_VR_LSB, &lsb, 0);
    282       1.1     soren 	iic_release_bus(sc->sc_tag, 0);
    283       1.1     soren 
    284       1.1     soren 	switch (edata->units) {
    285       1.1     soren 	case ENVSYS_SVOLTS_DC:
    286       1.1     soren 		if (sensor->msb == W83795G_3VDD ||
    287       1.1     soren 		    sensor->msb == W83795G_3VSB ||
    288       1.1     soren 		    sensor->msb == W83795G_VBAT)
    289       1.1     soren 			edata->value_cur = (msb << 2 | lsb >> 6) * 6000;
    290       1.1     soren 		else
    291       1.1     soren 			edata->value_cur = (msb << 2 | lsb >> 6) * 2000;
    292       1.1     soren 		break;
    293       1.1     soren 	case ENVSYS_STEMP:
    294       1.1     soren 		edata->value_cur = ((int8_t)msb << 2 | lsb >> 6) * 250000 +
    295       1.1     soren 		    273150000;
    296       1.1     soren 		break;
    297       1.1     soren 	case ENVSYS_SFANRPM:
    298       1.1     soren 		edata->value_cur = 1350000 / (msb << 4 | lsb >> 4);
    299       1.1     soren 		break;
    300       1.1     soren 	}
    301       1.1     soren 
    302       1.1     soren 	edata->state = ENVSYS_SVALID;
    303       1.1     soren }
    304       1.1     soren 
    305       1.1     soren static void
    306       1.1     soren w83795g_get_limits(struct sysmon_envsys *sme, envsys_data_t *edata,
    307       1.1     soren     sysmon_envsys_lim_t *limits, uint32_t *props)
    308       1.1     soren {
    309       1.1     soren 	struct w83795g_softc *sc = sme->sme_cookie;
    310       1.1     soren 	const struct w83795g_sensor *sensor = &sensors[edata->private];
    311       1.1     soren 	uint8_t index, msb, lsb;
    312       1.1     soren 
    313       1.1     soren 	iic_acquire_bus(sc->sc_tag, 0);
    314       1.1     soren 	iic_smbus_write_byte(sc->sc_tag, sc->sc_addr, W83795G_BANKSEL, 0, 0);
    315       1.1     soren 
    316       1.1     soren 	switch (edata->units) {
    317       1.1     soren 	case ENVSYS_SVOLTS_DC:
    318       1.1     soren 		break;
    319       1.1     soren 	case ENVSYS_STEMP:
    320       1.1     soren 		if (sensor->msb == W83795G_TR5)
    321       1.1     soren 			index = W83795G_TR5CRIT;
    322       1.1     soren 		else if (sensor->msb == W83795G_TR6)
    323       1.1     soren 			index = W83795G_TR6CRIT;
    324       1.1     soren 		else if (sensor->msb >= W83795G_DTS1)
    325       1.1     soren 			index = W83795G_DTSCRIT;
    326       1.1     soren 		else
    327       1.1     soren 			index = W83795G_TD1CRIT +
    328       1.1     soren 			    (sensor->msb - W83795G_TD1) * 4;
    329       1.1     soren 		iic_smbus_read_byte(sc->sc_tag, sc->sc_addr, index, &msb, 0);
    330       1.1     soren 		limits->sel_critmax = (int8_t)msb * 1000000 + 273150000;
    331       1.1     soren 		index += 2;
    332       1.1     soren 		iic_smbus_read_byte(sc->sc_tag, sc->sc_addr, index++, &msb, 0);
    333       1.1     soren 		limits->sel_warnmax = (int8_t)msb * 1000000 + 273150000;
    334       1.1     soren 		*props |= PROP_CRITMAX | PROP_WARNMAX;
    335       1.1     soren 		break;
    336       1.1     soren 	case ENVSYS_SFANRPM:
    337       1.1     soren 		index = W83795G_FAN1HL + (sensor->msb - W83795G_FANIN1) * 2;
    338       1.1     soren 		iic_smbus_read_byte(sc->sc_tag, sc->sc_addr, index, &msb, 0);
    339       1.1     soren 		index = W83795G_FHL1LSB + (sensor->msb - W83795G_FANIN1) / 2;
    340       1.1     soren 		iic_smbus_read_byte(sc->sc_tag, sc->sc_addr, index, &lsb, 0);
    341       1.1     soren 		if (index % 2)
    342       1.2  christos 			lsb >>= 4;
    343       1.1     soren 		else
    344       1.1     soren 			lsb &= 0xf;
    345       1.1     soren 		limits->sel_warnmin = 1350000 / (msb << 4 | lsb);
    346       1.1     soren 		*props |= PROP_WARNMIN;
    347       1.1     soren 		break;
    348       1.1     soren 	}
    349       1.1     soren 
    350       1.1     soren 	iic_release_bus(sc->sc_tag, 0);
    351       1.1     soren }
    352       1.1     soren 
    353       1.1     soren static int
    354       1.1     soren w83795g_gpio_read(void *arg, int pin)
    355       1.1     soren {
    356       1.1     soren 	struct w83795g_softc *sc = arg;
    357       1.1     soren 	uint8_t in, out;
    358       1.1     soren 
    359       1.1     soren 	iic_acquire_bus(sc->sc_tag, 0);
    360       1.1     soren 	iic_smbus_write_byte(sc->sc_tag, sc->sc_addr, W83795G_BANKSEL, 0, 0);
    361       1.1     soren 	iic_smbus_read_byte(sc->sc_tag, sc->sc_addr, W83795G_GPIO_I, &in, 0);
    362       1.1     soren 	iic_smbus_read_byte(sc->sc_tag, sc->sc_addr, W83795G_GPIO_O, &out, 0);
    363       1.1     soren 	iic_release_bus(sc->sc_tag, 0);
    364       1.1     soren 
    365       1.1     soren 	if (sc->sc_gpio_pins[pin].pin_flags == GPIO_PIN_OUTPUT)
    366       1.1     soren 		in = out;
    367       1.1     soren 
    368       1.1     soren 	return (in & (1 << pin)) ? GPIO_PIN_HIGH : GPIO_PIN_LOW;
    369       1.1     soren }
    370       1.1     soren 
    371       1.1     soren static void
    372       1.1     soren w83795g_gpio_write(void *arg, int pin, int value)
    373       1.1     soren {
    374       1.1     soren 	struct w83795g_softc *sc = arg;
    375       1.1     soren 	uint8_t out;
    376       1.1     soren 
    377       1.1     soren 	iic_acquire_bus(sc->sc_tag, 0);
    378       1.1     soren 	iic_smbus_write_byte(sc->sc_tag, sc->sc_addr, W83795G_BANKSEL, 0, 0);
    379       1.1     soren 	iic_smbus_read_byte(sc->sc_tag, sc->sc_addr, W83795G_GPIO_O, &out, 0);
    380       1.1     soren 
    381       1.1     soren 	if (value == GPIO_PIN_LOW)
    382       1.1     soren 		out &= ~(1 << pin);
    383       1.1     soren 	else if (value == GPIO_PIN_HIGH)
    384       1.1     soren 		out |= (1 << pin);
    385       1.1     soren 
    386       1.1     soren 	iic_smbus_write_byte(sc->sc_tag, sc->sc_addr, W83795G_GPIO_O, out, 0);
    387       1.1     soren 	iic_release_bus(sc->sc_tag, 0);
    388       1.1     soren }
    389       1.1     soren 
    390       1.1     soren static void
    391       1.1     soren w83795g_gpio_ctl(void *arg, int pin, int flags)
    392       1.1     soren {
    393       1.1     soren 	struct w83795g_softc *sc = arg;
    394       1.1     soren 	uint8_t mode;
    395       1.1     soren 
    396       1.1     soren 	iic_acquire_bus(sc->sc_tag, 0);
    397       1.1     soren 	iic_smbus_write_byte(sc->sc_tag, sc->sc_addr, W83795G_BANKSEL, 0, 0);
    398       1.1     soren 	iic_smbus_read_byte(sc->sc_tag, sc->sc_addr, W83795G_GPIO_M, &mode, 0);
    399       1.1     soren 
    400       1.1     soren 	if (flags & GPIO_PIN_INPUT)
    401       1.1     soren 		mode &= ~(1 << pin);
    402       1.1     soren 	if (flags & GPIO_PIN_OUTPUT)
    403       1.1     soren 		mode |= (1 << pin);
    404       1.1     soren 
    405       1.1     soren 	iic_smbus_write_byte(sc->sc_tag, sc->sc_addr, W83795G_GPIO_M, mode, 0);
    406       1.1     soren 	iic_release_bus(sc->sc_tag, 0);
    407       1.1     soren }
    408       1.1     soren 
    409       1.1     soren static int
    410       1.1     soren w83795g_wdog_setmode(struct sysmon_wdog *smw)
    411       1.1     soren {
    412       1.1     soren 	struct w83795g_softc *sc = smw->smw_cookie;
    413       1.1     soren 
    414       1.1     soren 	/*
    415       1.1     soren 	 * This device also supports a "hard" watchdog mode, which survives
    416       1.1     soren 	 * across reboots, but making use of that would require sysmon_wdog
    417       1.1     soren 	 * to have a way of querying the watchdog state at startup.
    418       1.1     soren 	 */
    419       1.1     soren 
    420       1.1     soren 	iic_acquire_bus(sc->sc_tag, 0);
    421       1.1     soren 	iic_smbus_write_byte(sc->sc_tag, sc->sc_addr, W83795G_BANKSEL, 0, 0);
    422       1.1     soren 	iic_smbus_write_byte(sc->sc_tag, sc->sc_addr, W83795G_WDT_ENA,
    423       1.1     soren 	    WDT_ENA_ENWDT | WDT_ENA_SOFT, 0);
    424       1.1     soren 	if ((smw->smw_mode & WDOG_MODE_MASK) == WDOG_MODE_DISARMED)
    425       1.1     soren 		iic_smbus_write_byte(sc->sc_tag, sc->sc_addr, W83795G_WDTLOCK,
    426       1.1     soren 		    WDTLOCK_DISABLE_SOFT, 0);
    427       1.1     soren 	else
    428       1.1     soren 		iic_smbus_write_byte(sc->sc_tag, sc->sc_addr, W83795G_WDTLOCK,
    429       1.1     soren 		    WDTLOCK_ENABLE_SOFT, 0);
    430       1.1     soren 	iic_release_bus(sc->sc_tag, 0);
    431       1.1     soren 
    432       1.1     soren 	if (smw->smw_period == WDOG_PERIOD_DEFAULT)
    433       1.1     soren 		smw->smw_period = 60;
    434       1.1     soren 	smw->smw_period = roundup(smw->smw_period, 60);
    435       1.1     soren 	w83795g_wdog_tickle(smw);
    436       1.1     soren 
    437       1.1     soren 	return 0;
    438       1.1     soren }
    439       1.1     soren 
    440       1.1     soren static int
    441       1.1     soren w83795g_wdog_tickle(struct sysmon_wdog *smw)
    442       1.1     soren {
    443       1.1     soren 	struct w83795g_softc *sc = smw->smw_cookie;
    444       1.1     soren 
    445       1.1     soren 	iic_acquire_bus(sc->sc_tag, 0);
    446       1.1     soren 	iic_smbus_write_byte(sc->sc_tag, sc->sc_addr, W83795G_BANKSEL, 0, 0);
    447       1.1     soren 	iic_smbus_write_byte(sc->sc_tag, sc->sc_addr, W83795G_WDT_CNT,
    448       1.1     soren 	    smw->smw_period / 60, 0);
    449       1.1     soren 	iic_release_bus(sc->sc_tag, 0);
    450       1.1     soren 
    451       1.1     soren 	return 0;
    452       1.1     soren }
    453