1 1.6 andvar /* $NetBSD: w83795g.c,v 1.6 2024/02/11 09:20:08 andvar 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.6 andvar __KERNEL_RCSID(0, "$NetBSD: w83795g.c,v 1.6 2024/02/11 09:20:08 andvar 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.3 thorpej 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.6 andvar aprint_normal(": Nuvoton 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, ®, 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.5 thorpej config_found(self, &gba, gpiobus_print, CFARGS_NONE); 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