Home | History | Annotate | Line # | Download | only in ic
nslm7x.c revision 1.32
      1 /*	$NetBSD: nslm7x.c,v 1.32 2007/03/11 22:25:48 christos Exp $ */
      2 
      3 /*-
      4  * Copyright (c) 2000 The NetBSD Foundation, Inc.
      5  * All rights reserved.
      6  *
      7  * This code is derived from software contributed to The NetBSD Foundation
      8  * by Bill Squier.
      9  *
     10  * Redistribution and use in source and binary forms, with or without
     11  * modification, are permitted provided that the following conditions
     12  * are met:
     13  * 1. Redistributions of source code must retain the above copyright
     14  *    notice, this list of conditions and the following disclaimer.
     15  * 2. Redistributions in binary form must reproduce the above copyright
     16  *    notice, this list of conditions and the following disclaimer in the
     17  *    documentation and/or other materials provided with the distribution.
     18  * 3. All advertising materials mentioning features or use of this software
     19  *    must display the following acknowledgement:
     20  *        This product includes software developed by the NetBSD
     21  *        Foundation, Inc. and its contributors.
     22  * 4. Neither the name of The NetBSD Foundation nor the names of its
     23  *    contributors may be used to endorse or promote products derived
     24  *    from this software without specific prior written permission.
     25  *
     26  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
     27  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
     28  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
     29  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
     30  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
     31  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
     32  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
     33  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
     34  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
     35  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
     36  * POSSIBILITY OF SUCH DAMAGE.
     37  */
     38 
     39 #include <sys/cdefs.h>
     40 __KERNEL_RCSID(0, "$NetBSD: nslm7x.c,v 1.32 2007/03/11 22:25:48 christos Exp $");
     41 
     42 #include <sys/param.h>
     43 #include <sys/systm.h>
     44 #include <sys/kernel.h>
     45 #include <sys/proc.h>
     46 #include <sys/device.h>
     47 #include <sys/conf.h>
     48 #include <sys/time.h>
     49 
     50 #include <machine/bus.h>
     51 
     52 #include <dev/isa/isareg.h>
     53 #include <dev/isa/isavar.h>
     54 
     55 #include <dev/sysmon/sysmonvar.h>
     56 
     57 #include <dev/ic/nslm7xvar.h>
     58 
     59 #include <machine/intr.h>
     60 
     61 #if defined(LMDEBUG)
     62 #define DPRINTF(x)	do { printf x; } while (0)
     63 #else
     64 #define DPRINTF(x)
     65 #endif
     66 
     67 /*
     68  * LM78-compatible chips can typically measure voltages up to 4.096 V.
     69  * To measure higher voltages the input is attenuated with (external)
     70  * resistors.  Negative voltages are measured using inverting op amps
     71  * and resistors.  So we have to convert the sensor values back to
     72  * real voltages by applying the appropriate resistor factor.
     73  */
     74 #define RFACT_NONE	10000
     75 #define RFACT(x, y)	(RFACT_NONE * ((x) + (y)) / (y))
     76 #define NRFACT(x, y)	(-RFACT_NONE * (x) / (y))
     77 
     78 const struct envsys_range lm_ranges[] = {	/* sc->sensors sub-intervals */
     79 						/* for each unit type */
     80 	{ 7, 7,    ENVSYS_STEMP   },
     81 	{ 8, 10,   ENVSYS_SFANRPM },
     82 	{ 1, 0,    ENVSYS_SVOLTS_AC },	/* None */
     83 	{ 0, 6,    ENVSYS_SVOLTS_DC },
     84 	{ 1, 0,    ENVSYS_SOHMS },	/* None */
     85 	{ 1, 0,    ENVSYS_SWATTS },	/* None */
     86 	{ 1, 0,    ENVSYS_SAMPS }	/* None */
     87 };
     88 
     89 static int lm_match(struct lm_softc *);
     90 static int wb_match(struct lm_softc *);
     91 static int def_match(struct lm_softc *);
     92 
     93 static void lm_generic_banksel(struct lm_softc *, int);
     94 static void lm_setup_sensors(struct lm_softc *, struct lm_sensor *);
     95 
     96 static void lm_refresh_sensor_data(struct lm_softc *);
     97 static void lm_refresh_volt(struct lm_softc *, int);
     98 static void lm_refresh_temp(struct lm_softc *, int);
     99 static void lm_refresh_fanrpm(struct lm_softc *, int);
    100 
    101 static void wb_refresh_sensor_data(struct lm_softc *);
    102 static void wb_w83637hf_refresh_vcore(struct lm_softc *, int);
    103 static void wb_refresh_nvolt(struct lm_softc *, int);
    104 static void wb_w83627ehf_refresh_nvolt(struct lm_softc *, int);
    105 static void wb_refresh_temp(struct lm_softc *, int);
    106 static void wb_refresh_fanrpm(struct lm_softc *, int);
    107 static void wb_w83792d_refresh_fanrpm(struct lm_softc *, int);
    108 
    109 static void as_refresh_temp(struct lm_softc *, int);
    110 
    111 static int lm_gtredata(struct sysmon_envsys *, struct envsys_tre_data *);
    112 static int generic_streinfo_fan(struct lm_softc *, struct envsys_basic_info *,
    113            int, struct envsys_basic_info *);
    114 static int lm_streinfo(struct sysmon_envsys *, struct envsys_basic_info *);
    115 static int wb781_streinfo(struct sysmon_envsys *, struct envsys_basic_info *);
    116 static int wb782_streinfo(struct sysmon_envsys *, struct envsys_basic_info *);
    117 
    118 struct lm_chip {
    119 	int (*chip_match)(struct lm_softc *);
    120 };
    121 
    122 static struct lm_chip lm_chips[] = {
    123 	{ wb_match },
    124 	{ lm_match },
    125 	{ def_match } /* Must be last */
    126 };
    127 
    128 static struct lm_sensor lm78_sensors[] = {
    129 	/* Voltage */
    130 	{ "VCore A", ENVSYS_SVOLTS_DC, 0, 0x20, lm_refresh_volt, RFACT_NONE },
    131 	{ "VCore B", ENVSYS_SVOLTS_DC, 0, 0x21, lm_refresh_volt, RFACT_NONE },
    132 	{ "+3.3V", ENVSYS_SVOLTS_DC, 0, 0x22, lm_refresh_volt, RFACT_NONE },
    133 	{ "+5V", ENVSYS_SVOLTS_DC, 0, 0x23, lm_refresh_volt, RFACT(68, 100) },
    134 	{ "+12V", ENVSYS_SVOLTS_DC, 0, 0x24, lm_refresh_volt, RFACT(30, 10) },
    135 	{ "-12V", ENVSYS_SVOLTS_DC, 0, 0x25, lm_refresh_volt, NRFACT(240, 60) },
    136 	{ "-5V", ENVSYS_SVOLTS_DC, 0, 0x26, lm_refresh_volt, NRFACT(100, 60) },
    137 
    138 	/* Temperature */
    139 	{ "Temp0", ENVSYS_STEMP, 0, 0x27, lm_refresh_temp, 0 },
    140 
    141 	/* Fans */
    142 	{ "Fan0", ENVSYS_SFANRPM, 0, 0x28, lm_refresh_fanrpm, 0 },
    143 	{ "Fan1", ENVSYS_SFANRPM, 0, 0x29, lm_refresh_fanrpm, 0 },
    144 	{ "Fan2", ENVSYS_SFANRPM, 0, 0x2a, lm_refresh_fanrpm, 0 },
    145 
    146 	{ .desc = NULL }
    147 };
    148 
    149 static struct lm_sensor w83627hf_sensors[] = {
    150 	/* Voltage */
    151 	{ "VCore A", ENVSYS_SVOLTS_DC, 0, 0x20, lm_refresh_volt, RFACT_NONE },
    152 	{ "VCore B", ENVSYS_SVOLTS_DC, 0, 0x21, lm_refresh_volt, RFACT_NONE },
    153 	{ "+3.3V", ENVSYS_SVOLTS_DC, 0, 0x22, lm_refresh_volt, RFACT_NONE },
    154 	{ "+5V", ENVSYS_SVOLTS_DC, 0, 0x23, lm_refresh_volt, RFACT(34, 50) },
    155 	{ "+12V", ENVSYS_SVOLTS_DC, 0, 0x24, lm_refresh_volt, RFACT(28, 10) },
    156 	{ "-12V", ENVSYS_SVOLTS_DC, 0, 0x25, wb_refresh_nvolt, RFACT(232, 56) },
    157 	{ "-5V", ENVSYS_SVOLTS_DC, 0, 0x26, wb_refresh_nvolt, RFACT(120, 56) },
    158 	{ "5VSB", ENVSYS_SVOLTS_DC, 5, 0x50, lm_refresh_volt, RFACT(17, 33) },
    159 	{ "VBAT", ENVSYS_SVOLTS_DC, 5, 0x51, lm_refresh_volt, RFACT_NONE },
    160 
    161 	/* Temperature */
    162 	{ "Temp0", ENVSYS_STEMP, 0, 0x27, lm_refresh_temp, 0 },
    163 	{ "Temp1", ENVSYS_STEMP, 1, 0x50, wb_refresh_temp, 0 },
    164 	{ "Temp2", ENVSYS_STEMP, 2, 0x50, wb_refresh_temp, 0 },
    165 
    166 	/* Fans */
    167 	{ "Fan0", ENVSYS_SFANRPM, 0, 0x28, wb_refresh_fanrpm, 0 },
    168 	{ "Fan1", ENVSYS_SFANRPM, 0, 0x29, wb_refresh_fanrpm, 0 },
    169 	{ "Fan2", ENVSYS_SFANRPM, 0, 0x2a, wb_refresh_fanrpm, 0 },
    170 
    171 	{ .desc = NULL }
    172 };
    173 
    174 /*
    175  * The W83627EHF can measure voltages up to 2.048 V instead of the
    176  * traditional 4.096 V.  For measuring positive voltages, this can be
    177  * accounted for by halving the resistor factor.  Negative voltages
    178  * need special treatment, also because the reference voltage is 2.048 V
    179  * instead of the traditional 3.6 V.
    180  */
    181 static struct lm_sensor w83627ehf_sensors[] = {
    182 	/* Voltage */
    183 	{ "VCore", ENVSYS_SVOLTS_DC, 0, 0x20, lm_refresh_volt, RFACT_NONE / 2},
    184 	{ "+12V", ENVSYS_SVOLTS_DC, 0, 0x21, lm_refresh_volt, RFACT(56, 10) / 2 },
    185 	{ "+3.3V", ENVSYS_SVOLTS_DC, 0, 0x22, lm_refresh_volt, RFACT(34, 34) / 2 },
    186 	{ "+3.3V", ENVSYS_SVOLTS_DC, 0, 0x23, lm_refresh_volt, RFACT(34, 24) / 2 },
    187 	{ "-12V", ENVSYS_SVOLTS_DC, 0, 0x24, wb_w83627ehf_refresh_nvolt, 0 },
    188 	{ "Unknown", ENVSYS_SVOLTS_DC, 0, 0x25, lm_refresh_volt, RFACT_NONE / 2 },
    189 	{ "Unknown", ENVSYS_SVOLTS_DC, 0, 0x26, lm_refresh_volt, RFACT_NONE / 2 },
    190 	{ "3.3VSB", ENVSYS_SVOLTS_DC, 5, 0x50, lm_refresh_volt, RFACT(34, 34) / 2 },
    191 	{ "VBAT", ENVSYS_SVOLTS_DC, 5, 0x51, lm_refresh_volt, RFACT_NONE / 2 },
    192 	{ "Unknown", ENVSYS_SVOLTS_DC, 5, 0x52, lm_refresh_volt, RFACT_NONE / 2 },
    193 
    194 	/* Temperature */
    195 	{ "Temp0", ENVSYS_STEMP, 0, 0x27, lm_refresh_temp, 0 },
    196 	{ "Temp1", ENVSYS_STEMP, 1, 0x50, wb_refresh_temp, 0 },
    197 	{ "Temp2", ENVSYS_STEMP, 2, 0x50, wb_refresh_temp, 0 },
    198 
    199 	/* Fans */
    200 	{ "Fan0", ENVSYS_SFANRPM, 0, 0x28, wb_refresh_fanrpm, 0 },
    201 	{ "Fan1", ENVSYS_SFANRPM, 0, 0x29, wb_refresh_fanrpm, 0 },
    202 	{ "Fan2", ENVSYS_SFANRPM, 0, 0x2a, wb_refresh_fanrpm, 0 },
    203 
    204 	{ .desc = NULL }
    205 };
    206 
    207 static struct lm_sensor w83627dhg_sensors[] = {
    208 	/* Voltage */
    209 	{ "VCore", ENVSYS_SVOLTS_DC, 0, 0x20, lm_refresh_volt, RFACT_NONE/2 },
    210 	{ "+12V", ENVSYS_SVOLTS_DC, 0, 0x21, lm_refresh_volt, RFACT(56,10)/2 },
    211 	{ "+3.3V", ENVSYS_SVOLTS_DC, 0, 0x22, lm_refresh_volt, RFACT_NONE },
    212 	{ "AVCC", ENVSYS_SVOLTS_DC, 0, 0x23, lm_refresh_volt, RFACT_NONE },
    213 	{ "+5V", ENVSYS_SVOLTS_DC, 0, 0x25, lm_refresh_volt, RFACT(32, 56) },
    214 	/*
    215 	 * I'm not sure about which one is -12V or -5V.
    216 	 */
    217 #if 0
    218 	{ "-12V", ENVSYS_SVOLTS_DC, 0, 0x24, wb_refresh_nvolt, RFACT(232, 60) },
    219 	{ "-5V", ENVSYS_SVOLTS_DC, 0, 0x26, wb_w83627ehf_refresh_nvolt },
    220 #endif
    221 	{ "+3.3VSB", ENVSYS_SVOLTS_DC, 5, 0x50, lm_refresh_volt, RFACT_NONE },
    222 	{ "VBAT", ENVSYS_SVOLTS_DC, 5, 0x51, lm_refresh_volt, RFACT_NONE },
    223 
    224 	/* Temperature */
    225 	{ "System Temp", ENVSYS_STEMP, 0, 0x27, lm_refresh_temp, 0 },
    226 	{ "CPU Temp", ENVSYS_STEMP, 1, 0x50, wb_refresh_temp, 0 },
    227 	{ "Aux Temp", ENVSYS_STEMP, 2, 0x50, wb_refresh_temp, 0 },
    228 
    229 	/* Fans */
    230 	{ "System Fan", ENVSYS_SFANRPM, 0, 0x28, wb_refresh_fanrpm, 0 },
    231 	{ "CPU Fan", ENVSYS_SFANRPM, 0, 0x29, wb_refresh_fanrpm, 0 },
    232 	{ "Aux Fan", ENVSYS_SFANRPM, 0, 0x2a, wb_refresh_fanrpm, 0 },
    233 
    234 	{ .desc = NULL }
    235 };
    236 
    237 static struct lm_sensor w83637hf_sensors[] = {
    238 	/* Voltage */
    239 	{ "VCore", ENVSYS_SVOLTS_DC, 0, 0x20, wb_w83637hf_refresh_vcore, 0 },
    240 	{ "+12V", ENVSYS_SVOLTS_DC, 0, 0x21, lm_refresh_volt, RFACT(28, 10) },
    241 	{ "+3.3V", ENVSYS_SVOLTS_DC, 0, 0x22, lm_refresh_volt, RFACT_NONE },
    242 	{ "+5V", ENVSYS_SVOLTS_DC, 0, 0x23, lm_refresh_volt, RFACT(34, 51) },
    243 	{ "-12V", ENVSYS_SVOLTS_DC, 0, 0x24, wb_refresh_nvolt, RFACT(232, 56) },
    244 	{ "5VSB", ENVSYS_SVOLTS_DC, 5, 0x50, lm_refresh_volt, RFACT(34, 51) },
    245 	{ "VBAT", ENVSYS_SVOLTS_DC, 5, 0x51, lm_refresh_volt, RFACT_NONE },
    246 
    247 	/* Temperature */
    248 	{ "Temp0", ENVSYS_STEMP, 0, 0x27, lm_refresh_temp, 0 },
    249 	{ "Temp1", ENVSYS_STEMP, 1, 0x50, wb_refresh_temp, 0 },
    250 	{ "Temp2", ENVSYS_STEMP, 2, 0x50, wb_refresh_temp, 0 },
    251 
    252 	/* Fans */
    253 	{ "Fan0", ENVSYS_SFANRPM, 0, 0x28, wb_refresh_fanrpm, 0 },
    254 	{ "Fan1", ENVSYS_SFANRPM, 0, 0x29, wb_refresh_fanrpm, 0 },
    255 	{ "Fan2", ENVSYS_SFANRPM, 0, 0x2a, wb_refresh_fanrpm, 0 },
    256 
    257 	{ .desc = NULL }
    258 };
    259 
    260 static struct lm_sensor w83697hf_sensors[] = {
    261 	/* Voltage */
    262 	{ "VCore", ENVSYS_SVOLTS_DC, 0, 0x20, lm_refresh_volt, RFACT_NONE },
    263 	{ "+3.3V", ENVSYS_SVOLTS_DC, 0, 0x22, lm_refresh_volt, RFACT_NONE },
    264 	{ "+5V", ENVSYS_SVOLTS_DC, 0, 0x23, lm_refresh_volt, RFACT(34, 50) },
    265 	{ "+12V", ENVSYS_SVOLTS_DC, 0, 0x24, lm_refresh_volt, RFACT(28, 10) },
    266 	{ "-12V", ENVSYS_SVOLTS_DC, 0, 0x25, wb_refresh_nvolt, RFACT(232, 56) },
    267 	{ "-5V", ENVSYS_SVOLTS_DC, 0, 0x26, wb_refresh_nvolt, RFACT(120, 56) },
    268 	{ "5VSB", ENVSYS_SVOLTS_DC, 5, 0x50, lm_refresh_volt, RFACT(17, 33) },
    269 	{ "VBAT", ENVSYS_SVOLTS_DC, 5, 0x51, lm_refresh_volt, RFACT_NONE },
    270 
    271 	/* Temperature */
    272 	{ "Temp0", ENVSYS_STEMP, 0, 0x27, lm_refresh_temp, 0 },
    273 	{ "Temp1", ENVSYS_STEMP, 1, 0x50, wb_refresh_temp, 0 },
    274 
    275 	/* Fans */
    276 	{ "Fan0", ENVSYS_SFANRPM, 0, 0x28, wb_refresh_fanrpm, 0 },
    277 	{ "Fan1", ENVSYS_SFANRPM, 0, 0x29, wb_refresh_fanrpm, 0 },
    278 
    279 	{ .desc = NULL }
    280 };
    281 
    282 /*
    283  * The datasheet doesn't mention the (internal) resistors used for the
    284  * +5V, but using the values from the W83782D datasheets seems to
    285  * provide sensible results.
    286  */
    287 static struct lm_sensor w83781d_sensors[] = {
    288 	/* Voltage */
    289 	{ "VCore A", ENVSYS_SVOLTS_DC, 0, 0x20, lm_refresh_volt, RFACT_NONE },
    290 	{ "VCore B", ENVSYS_SVOLTS_DC, 0, 0x21, lm_refresh_volt, RFACT_NONE },
    291 	{ "+3.3V", ENVSYS_SVOLTS_DC, 0, 0x22, lm_refresh_volt, RFACT_NONE },
    292 	{ "+5V", ENVSYS_SVOLTS_DC, 0, 0x23, lm_refresh_volt, RFACT(34, 50) },
    293 	{ "+12V", ENVSYS_SVOLTS_DC, 0, 0x24, lm_refresh_volt, RFACT(28, 10) },
    294 	{ "-12V", ENVSYS_SVOLTS_DC, 0, 0x25, lm_refresh_volt, NRFACT(2100, 604) },
    295 	{ "-5V", ENVSYS_SVOLTS_DC, 0, 0x26, lm_refresh_volt, NRFACT(909, 604) },
    296 
    297 	/* Temperature */
    298 	{ "Temp0", ENVSYS_STEMP, 0, 0x27, lm_refresh_temp, 0 },
    299 	{ "Temp1", ENVSYS_STEMP, 1, 0x50, wb_refresh_temp, 0 },
    300 	{ "Temp2", ENVSYS_STEMP, 2, 0x50, wb_refresh_temp, 0 },
    301 
    302 	/* Fans */
    303 	{ "Fan0", ENVSYS_SFANRPM, 0, 0x28, lm_refresh_fanrpm, 0 },
    304 	{ "Fan1", ENVSYS_SFANRPM, 0, 0x29, lm_refresh_fanrpm, 0 },
    305 	{ "Fan2", ENVSYS_SFANRPM, 0, 0x2a, lm_refresh_fanrpm, 0 },
    306 
    307 	{ .desc = NULL }
    308 };
    309 
    310 static struct lm_sensor w83782d_sensors[] = {
    311 	/* Voltage */
    312 	{ "VCore", ENVSYS_SVOLTS_DC, 0, 0x20, lm_refresh_volt, RFACT_NONE },
    313 	{ "VINR0", ENVSYS_SVOLTS_DC, 0, 0x21, lm_refresh_volt, RFACT_NONE },
    314 	{ "+3.3V", ENVSYS_SVOLTS_DC, 0, 0x22, lm_refresh_volt, RFACT_NONE },
    315 	{ "+5V", ENVSYS_SVOLTS_DC, 0, 0x23, lm_refresh_volt, RFACT(34, 50) },
    316 	{ "+12V", ENVSYS_SVOLTS_DC, 0, 0x24, lm_refresh_volt, RFACT(28, 10) },
    317 	{ "-12V", ENVSYS_SVOLTS_DC, 0, 0x25, wb_refresh_nvolt, RFACT(232, 56) },
    318 	{ "-5V", ENVSYS_SVOLTS_DC, 0, 0x26, wb_refresh_nvolt, RFACT(120, 56) },
    319 	{ "5VSB", ENVSYS_SVOLTS_DC, 5, 0x50, lm_refresh_volt, RFACT(17, 33) },
    320 	{ "VBAT", ENVSYS_SVOLTS_DC, 5, 0x51, lm_refresh_volt, RFACT_NONE },
    321 
    322 	/* Temperature */
    323 	{ "Temp0", ENVSYS_STEMP, 0, 0x27, lm_refresh_temp, 0 },
    324 	{ "Temp1", ENVSYS_STEMP, 1, 0x50, wb_refresh_temp, 0 },
    325 	{ "Temp2", ENVSYS_STEMP, 2, 0x50, wb_refresh_temp, 0 },
    326 
    327 	/* Fans */
    328 	{ "Fan0", ENVSYS_SFANRPM, 0, 0x28, wb_refresh_fanrpm, 0 },
    329 	{ "Fan1", ENVSYS_SFANRPM, 0, 0x29, wb_refresh_fanrpm, 0 },
    330 	{ "Fan2", ENVSYS_SFANRPM, 0, 0x2a, wb_refresh_fanrpm, 0 },
    331 
    332 	{ .desc = NULL }
    333 };
    334 
    335 static struct lm_sensor w83783s_sensors[] = {
    336 	/* Voltage */
    337 	{ "VCore", ENVSYS_SVOLTS_DC, 0, 0x20, lm_refresh_volt, RFACT_NONE },
    338 	{ "+3.3V", ENVSYS_SVOLTS_DC, 0, 0x22, lm_refresh_volt, RFACT_NONE },
    339 	{ "+5V", ENVSYS_SVOLTS_DC, 0, 0x23, lm_refresh_volt, RFACT(34, 50) },
    340 	{ "+12V", ENVSYS_SVOLTS_DC, 0, 0x24, lm_refresh_volt, RFACT(28, 10) },
    341 	{ "-12V", ENVSYS_SVOLTS_DC, 0, 0x25, wb_refresh_nvolt, RFACT(232, 56) },
    342 	{ "-5V", ENVSYS_SVOLTS_DC, 0, 0x26, wb_refresh_nvolt, RFACT(120, 56) },
    343 
    344 	/* Temperature */
    345 	{ "Temp0", ENVSYS_STEMP, 0, 0x27, lm_refresh_temp, 0 },
    346 	{ "Temp1", ENVSYS_STEMP, 1, 0x50, wb_refresh_temp, 0 },
    347 
    348 	/* Fans */
    349 	{ "Fan0", ENVSYS_SFANRPM, 0, 0x28, wb_refresh_fanrpm, 0 },
    350 	{ "Fan1", ENVSYS_SFANRPM, 0, 0x29, wb_refresh_fanrpm, 0 },
    351 	{ "Fan2", ENVSYS_SFANRPM, 0, 0x2a, wb_refresh_fanrpm, 0 },
    352 
    353 	{ .desc = NULL }
    354 };
    355 
    356 static struct lm_sensor w83791d_sensors[] = {
    357 	/* Voltage */
    358 	{ "VCore", ENVSYS_SVOLTS_DC, 0, 0x20, lm_refresh_volt, 10000 },
    359 	{ "VINR0", ENVSYS_SVOLTS_DC, 0, 0x21, lm_refresh_volt, 10000 },
    360 	{ "+3.3V", ENVSYS_SVOLTS_DC, 0, 0x22, lm_refresh_volt, 10000 },
    361 	{ "+5V", ENVSYS_SVOLTS_DC, 0, 0x23, lm_refresh_volt, RFACT(34, 50) },
    362 	{ "+12V", ENVSYS_SVOLTS_DC, 0, 0x24, lm_refresh_volt, RFACT(28, 10) },
    363 	{ "-12V", ENVSYS_SVOLTS_DC, 0, 0x25, wb_refresh_nvolt, RFACT(232, 56) },
    364 	{ "-5V", ENVSYS_SVOLTS_DC, 0, 0x26, wb_refresh_nvolt, RFACT(120, 56) },
    365 	{ "5VSB", ENVSYS_SVOLTS_DC, 0, 0xb0, lm_refresh_volt, RFACT(17, 33) },
    366 	{ "VBAT", ENVSYS_SVOLTS_DC, 0, 0xb1, lm_refresh_volt, RFACT_NONE },
    367 	{ "VINR1", ENVSYS_SVOLTS_DC, 0, 0xb2, lm_refresh_volt, RFACT_NONE },
    368 
    369 	/* Temperature */
    370 	{ "Temp0", ENVSYS_STEMP, 0, 0x27, lm_refresh_temp, 0 },
    371 	{ "Temp1", ENVSYS_STEMP, 0, 0xc0, wb_refresh_temp, 0 },
    372 	{ "Temp2", ENVSYS_STEMP, 0, 0xc8, wb_refresh_temp, 0 },
    373 
    374 	/* Fans */
    375 	{ "Fan0", ENVSYS_SFANRPM, 0, 0x28, wb_refresh_fanrpm, 0 },
    376 	{ "Fan1", ENVSYS_SFANRPM, 0, 0x29, wb_refresh_fanrpm, 0 },
    377 	{ "Fan2", ENVSYS_SFANRPM, 0, 0x2a, wb_refresh_fanrpm, 0 },
    378 	{ "Fan3", ENVSYS_SFANRPM, 0, 0xba, wb_refresh_fanrpm, 0 },
    379 	{ "Fan4", ENVSYS_SFANRPM, 0, 0xbb, wb_refresh_fanrpm, 0 },
    380 
    381         { .desc = NULL }
    382 };
    383 
    384 static struct lm_sensor w83792d_sensors[] = {
    385 	/* Voltage */
    386 	{ "VCore A", ENVSYS_SVOLTS_DC, 0, 0x20, lm_refresh_volt, RFACT_NONE },
    387 	{ "VCore B", ENVSYS_SVOLTS_DC, 0, 0x21, lm_refresh_volt, RFACT_NONE },
    388 	{ "+3.3V", ENVSYS_SVOLTS_DC, 0, 0x22, lm_refresh_volt, RFACT_NONE },
    389 	{ "-5V", ENVSYS_SVOLTS_DC, 0, 0x23, wb_refresh_nvolt, RFACT(120, 56) },
    390 	{ "+12V", ENVSYS_SVOLTS_DC, 0, 0x24, lm_refresh_volt, RFACT(28, 10) },
    391 	{ "-12V", ENVSYS_SVOLTS_DC, 0, 0x25, wb_refresh_nvolt, RFACT(232, 56) },
    392 	{ "+5V", ENVSYS_SVOLTS_DC, 0, 0x26, lm_refresh_volt, RFACT(34, 50) },
    393 	{ "5VSB", ENVSYS_SVOLTS_DC, 0, 0xb0, lm_refresh_volt, RFACT(17, 33) },
    394 	{ "VBAT", ENVSYS_SVOLTS_DC, 0, 0xb1, lm_refresh_volt, RFACT_NONE },
    395 
    396 	/* Temperature */
    397 	{ "Temp0", ENVSYS_STEMP, 0, 0x27, lm_refresh_temp, 0 },
    398 	{ "Temp1", ENVSYS_STEMP, 0, 0xc0, wb_refresh_temp, 0 },
    399 	{ "Temp2", ENVSYS_STEMP, 0, 0xc8, wb_refresh_temp, 0 },
    400 
    401 	/* Fans */
    402 	{ "Fan0", ENVSYS_SFANRPM, 0, 0x28, wb_w83792d_refresh_fanrpm, 0 },
    403 	{ "Fan1", ENVSYS_SFANRPM, 0, 0x29, wb_w83792d_refresh_fanrpm, 0 },
    404 	{ "Fan2", ENVSYS_SFANRPM, 0, 0x2a, wb_w83792d_refresh_fanrpm, 0 },
    405 	{ "Fan3", ENVSYS_SFANRPM, 0, 0xb8, wb_w83792d_refresh_fanrpm, 0 },
    406 	{ "Fan4", ENVSYS_SFANRPM, 0, 0xb9, wb_w83792d_refresh_fanrpm, 0 },
    407 	{ "Fan5", ENVSYS_SFANRPM, 0, 0xba, wb_w83792d_refresh_fanrpm, 0 },
    408 	{ "Fan6", ENVSYS_SFANRPM, 0, 0xbe, wb_w83792d_refresh_fanrpm, 0 },
    409 
    410 	{ .desc = NULL }
    411 };
    412 
    413 static struct lm_sensor as99127f_sensors[] = {
    414 	/* Voltage */
    415 	{ "VCore A", ENVSYS_SVOLTS_DC, 0, 0x20, lm_refresh_volt, RFACT_NONE },
    416 	{ "VCore B", ENVSYS_SVOLTS_DC, 0, 0x21, lm_refresh_volt, RFACT_NONE },
    417 	{ "+3.3V", ENVSYS_SVOLTS_DC, 0, 0x22, lm_refresh_volt, RFACT_NONE },
    418 	{ "+5V", ENVSYS_SVOLTS_DC, 0, 0x23, lm_refresh_volt, RFACT(34, 50) },
    419 	{ "+12V", ENVSYS_SVOLTS_DC, 0, 0x24, lm_refresh_volt, RFACT(28, 10) },
    420 	{ "-12V", ENVSYS_SVOLTS_DC, 0, 0x25, wb_refresh_nvolt, RFACT(232, 56) },
    421 	{ "-5V", ENVSYS_SVOLTS_DC, 0, 0x26, wb_refresh_nvolt, RFACT(120, 56) },
    422 
    423 	/* Temperature */
    424 	{ "Temp0", ENVSYS_STEMP, 0, 0x27, lm_refresh_temp, 0 },
    425 	{ "Temp1", ENVSYS_STEMP, 1, 0x50, as_refresh_temp, 0 },
    426 	{ "Temp2", ENVSYS_STEMP, 2, 0x50, as_refresh_temp, 0 },
    427 
    428 	/* Fans */
    429 	{ "Fan0", ENVSYS_SFANRPM, 0, 0x28, lm_refresh_fanrpm, 0 },
    430 	{ "Fan1", ENVSYS_SFANRPM, 0, 0x29, lm_refresh_fanrpm, 0 },
    431 	{ "Fan2", ENVSYS_SFANRPM, 0, 0x2a, lm_refresh_fanrpm, 0 },
    432 
    433 	{ .desc = NULL }
    434 };
    435 
    436 static void
    437 lm_generic_banksel(struct lm_softc *lmsc, int bank)
    438 {
    439 	(*lmsc->lm_writereg)(lmsc, WB_BANKSEL, bank);
    440 }
    441 
    442 /*
    443  * bus independent probe
    444  */
    445 int
    446 lm_probe(bus_space_tag_t iot, bus_space_handle_t ioh)
    447 {
    448 	uint8_t cr;
    449 	int rv;
    450 
    451 	/* Check for some power-on defaults */
    452 	bus_space_write_1(iot, ioh, LMC_ADDR, LMD_CONFIG);
    453 
    454 	/* Perform LM78 reset */
    455 	bus_space_write_1(iot, ioh, LMC_DATA, 0x80);
    456 
    457 	/* XXX - Why do I have to reselect the register? */
    458 	bus_space_write_1(iot, ioh, LMC_ADDR, LMD_CONFIG);
    459 	cr = bus_space_read_1(iot, ioh, LMC_DATA);
    460 
    461 	/* XXX - spec says *only* 0x08! */
    462 	if ((cr == 0x08) || (cr == 0x01) || (cr == 0x03))
    463 		rv = 1;
    464 	else
    465 		rv = 0;
    466 
    467 	DPRINTF(("lm: rv = %d, cr = %x\n", rv, cr));
    468 
    469 	return rv;
    470 }
    471 
    472 
    473 /*
    474  * pre:  lmsc contains valid busspace tag and handle
    475  */
    476 void
    477 lm_attach(struct lm_softc *lmsc)
    478 {
    479 	uint32_t i;
    480 
    481 	for (i = 0; i < __arraycount(lm_chips); i++)
    482 		if (lm_chips[i].chip_match(lmsc))
    483 			break;
    484 
    485 	/* Start the monitoring loop */
    486 	(*lmsc->lm_writereg)(lmsc, LMD_CONFIG, 0x01);
    487 
    488 	/* Indicate we have never read the registers */
    489 	timerclear(&lmsc->lastread);
    490 
    491 	/* Initialize sensors */
    492 	for (i = 0; i < lmsc->numsensors; ++i) {
    493 		lmsc->sensors[i].sensor = lmsc->info[i].sensor = i;
    494 		lmsc->sensors[i].validflags = (ENVSYS_FVALID|ENVSYS_FCURVALID);
    495 		lmsc->info[i].validflags = ENVSYS_FVALID;
    496 		lmsc->sensors[i].warnflags = ENVSYS_WARN_OK;
    497 	}
    498 	/*
    499 	 * Hook into the System Monitor.
    500 	 */
    501 	lmsc->sc_sysmon.sme_ranges = lm_ranges;
    502 	lmsc->sc_sysmon.sme_sensor_info = lmsc->info;
    503 	lmsc->sc_sysmon.sme_sensor_data = lmsc->sensors;
    504 	lmsc->sc_sysmon.sme_cookie = lmsc;
    505 
    506 	lmsc->sc_sysmon.sme_gtredata = lm_gtredata;
    507 	/* sme_streinfo set in chip-specific attach */
    508 
    509 	lmsc->sc_sysmon.sme_nsensors = lmsc->numsensors;
    510 	lmsc->sc_sysmon.sme_envsys_version = 1000;
    511 
    512 	if (sysmon_envsys_register(&lmsc->sc_sysmon))
    513 		aprint_error("%s: unable to register with sysmon\n",
    514 		    lmsc->sc_dev.dv_xname);
    515 }
    516 
    517 static int
    518 lm_match(struct lm_softc *sc)
    519 {
    520 	const char *model = NULL;
    521 	int chipid;
    522 
    523 	/* See if we have an LM78/LM78J/LM79 or LM81 */
    524 	chipid = (*sc->lm_readreg)(sc, LMD_CHIPID) & LM_ID_MASK;
    525 	switch(chipid) {
    526 	case LM_ID_LM78:
    527 		model = "LM78";
    528 		break;
    529 	case LM_ID_LM78J:
    530 		model = "LM78J";
    531 		break;
    532 	case LM_ID_LM79:
    533 		model = "LM79";
    534 		break;
    535 	case LM_ID_LM81:
    536 		model = "LM81";
    537 		break;
    538 	default:
    539 		return 0;
    540 	}
    541 
    542 	aprint_normal(": National Semiconductor %s Hardware monitor\n", model);
    543 
    544 	lm_setup_sensors(sc, lm78_sensors);
    545 	sc->sc_sysmon.sme_streinfo = lm_streinfo;
    546 	sc->refresh_sensor_data = lm_refresh_sensor_data;
    547 	return 1;
    548 }
    549 
    550 static int
    551 def_match(struct lm_softc *sc)
    552 {
    553 	int chipid;
    554 
    555 	chipid = (*sc->lm_readreg)(sc, LMD_CHIPID) & LM_ID_MASK;
    556 	aprint_error(": Unknown chip (ID %d)\n", chipid);
    557 
    558 	lm_setup_sensors(sc, lm78_sensors);
    559 	sc->sc_sysmon.sme_streinfo = lm_streinfo;
    560 	sc->refresh_sensor_data = lm_refresh_sensor_data;
    561 	return 1;
    562 }
    563 
    564 static int
    565 wb_match(struct lm_softc *sc)
    566 {
    567 	const char *model;
    568 	int banksel, vendid, devid;
    569 
    570 	model = NULL;
    571 
    572 	/* Read vendor ID */
    573 	banksel = (*sc->lm_readreg)(sc, WB_BANKSEL);
    574 	lm_generic_banksel(sc, WB_BANKSEL_HBAC);
    575 
    576 	vendid = (*sc->lm_readreg)(sc, WB_VENDID) << 8;
    577 	lm_generic_banksel(sc, 0);
    578 	vendid |= (*sc->lm_readreg)(sc, WB_VENDID);
    579 	DPRINTF(("winbond vend id 0x%x\n", vendid));
    580 	if (vendid != WB_VENDID_WINBOND && vendid != WB_VENDID_ASUS)
    581 		return 0;
    582 
    583 	/* Read device/chip ID */
    584 	lm_generic_banksel(sc, WB_BANKSEL_B0);
    585 	devid = (*sc->lm_readreg)(sc, LMD_CHIPID);
    586 	sc->chipid = (*sc->lm_readreg)(sc, WB_BANK0_CHIPID);
    587 	lm_generic_banksel(sc, banksel);
    588 	DPRINTF(("winbond chip id 0x%x\n", sc->chipid));
    589 
    590 	switch(sc->chipid) {
    591 	case WB_CHIPID_W83627HF:
    592 		model = "W83627HF";
    593 		lm_setup_sensors(sc, w83627hf_sensors);
    594 		break;
    595 	case WB_CHIPID_W83627THF:
    596 		model = "W83627THF";
    597 		lm_setup_sensors(sc, w83637hf_sensors);
    598 		break;
    599 	case WB_CHIPID_W83627EHF:
    600 		model = "W83627EHF";
    601 		lm_setup_sensors(sc, w83627ehf_sensors);
    602 		break;
    603 	case WB_CHIPID_W83627DHG:
    604 		model = "W83627DHG";
    605 		lm_setup_sensors(sc, w83627dhg_sensors);
    606 		break;
    607 	case WB_CHIPID_W83637HF:
    608 		model = "W83637HF";
    609 		lm_generic_banksel(sc, WB_BANKSEL_B0);
    610 		if ((*sc->lm_readreg)(sc, WB_BANK0_CONFIG) & WB_CONFIG_VMR9)
    611 			sc->vrm9 = 1;
    612 		lm_generic_banksel(sc, banksel);
    613 		lm_setup_sensors(sc, w83637hf_sensors);
    614 		break;
    615 	case WB_CHIPID_W83697HF:
    616 		model = "W83697HF";
    617 		lm_setup_sensors(sc, w83697hf_sensors);
    618 		break;
    619 	case WB_CHIPID_W83781D:
    620 	case WB_CHIPID_W83781D_2:
    621 		model = "W83781D";
    622 		lm_setup_sensors(sc, w83781d_sensors);
    623 		sc->sc_sysmon.sme_streinfo = wb781_streinfo;
    624 		break;
    625 	case WB_CHIPID_W83782D:
    626 		model = "W83782D";
    627 		lm_setup_sensors(sc, w83782d_sensors);
    628 		sc->sc_sysmon.sme_streinfo = wb782_streinfo;
    629 		break;
    630 	case WB_CHIPID_W83783S:
    631 		model = "W83783S";
    632 		lm_setup_sensors(sc, w83783s_sensors);
    633 		break;
    634 	case WB_CHIPID_W83791D:
    635 		model = "W83791D";
    636 		lm_setup_sensors(sc, w83791d_sensors);
    637 		break;
    638 	case WB_CHIPID_W83791SD:
    639 		model = "W83791SD";
    640 		break;
    641 	case WB_CHIPID_W83792D:
    642 		model = "W83792D";
    643 		lm_setup_sensors(sc, w83792d_sensors);
    644 		break;
    645 	case WB_CHIPID_AS99127F:
    646 		if (vendid == WB_VENDID_ASUS) {
    647 			model = "AS99127F";
    648 			lm_setup_sensors(sc, w83781d_sensors);
    649 		} else {
    650 			model = "AS99127F rev 2";
    651 			lm_setup_sensors(sc, as99127f_sensors);
    652 		}
    653 		break;
    654 	default:
    655 		aprint_normal(": unknown Winbond chip (ID 0x%x)\n",
    656 		    sc->chipid);
    657 		/* Handle as a standard LM78. */
    658 		lm_setup_sensors(sc, lm78_sensors);
    659 		sc->refresh_sensor_data = lm_refresh_sensor_data;
    660 		return 1;
    661 	}
    662 
    663 	aprint_normal(": Winbond %s Hardware monitor\n", model);
    664 
    665 	sc->sc_sysmon.sme_streinfo = lm_streinfo;
    666 	sc->refresh_sensor_data = wb_refresh_sensor_data;
    667 	return 1;
    668 }
    669 
    670 static void
    671 lm_setup_sensors(struct lm_softc *sc, struct lm_sensor *sensors)
    672 {
    673 	int i;
    674 
    675 	for (i = 0; sensors[i].desc; i++) {
    676 		sc->sensors[i].units = sc->info[i].units = sensors[i].type;
    677 		strlcpy(sc->info[i].desc, sensors[i].desc,
    678 		    sizeof(sc->info[i].desc));
    679 		sc->numsensors++;
    680 	}
    681 	sc->lm_sensors = sensors;
    682 }
    683 
    684 static void
    685 lm_refresh_sensor_data(struct lm_softc *sc)
    686 {
    687 	int i;
    688 
    689 	/* Refresh our stored data for every sensor */
    690 	for (i = 0; i < sc->numsensors; i++)
    691 		sc->lm_sensors[i].refresh(sc, i);
    692 }
    693 
    694 static void
    695 lm_refresh_volt(struct lm_softc *sc, int n)
    696 {
    697 	int data;
    698 
    699 	data = (*sc->lm_readreg)(sc, sc->lm_sensors[n].reg);
    700 	DPRINTF(("%s: volt[%d] 0x%x\n", __func__, n, data));
    701 	sc->sensors[n].cur.data_s = (data << 4);
    702 	sc->sensors[n].cur.data_s *= sc->lm_sensors[n].rfact;
    703 	sc->sensors[n].cur.data_s /= 10;
    704 	sc->info[n].rfact = sc->lm_sensors[n].rfact;
    705 }
    706 
    707 #define INVALIDATE_SENSOR(x)						\
    708 	do {								\
    709 		sc->sensors[(x)].validflags &= ~ENVSYS_FCURVALID;	\
    710 		sc->sensors[(x)].cur.data_us = 0;			\
    711 	} while (/* CONSTCOND */ 0)
    712 
    713 static void
    714 lm_refresh_temp(struct lm_softc *sc, int n)
    715 {
    716 	int sdata;
    717 
    718 	/*
    719 	 * The data sheet suggests that the range of the temperature
    720 	 * sensor is between -55 degC and +125 degC.
    721 	 */
    722 	sdata = (*sc->lm_readreg)(sc, sc->lm_sensors[n].reg);
    723 	if (sdata > 0x7d && sdata < 0xc9) {
    724 		INVALIDATE_SENSOR(n);
    725 	} else {
    726 		if (sdata & 0x80)
    727 			sdata -= 0x100;
    728 		sc->sensors[n].validflags |= (ENVSYS_FVALID|ENVSYS_FCURVALID);
    729 		sc->sensors[n].cur.data_us = sdata * 1000000 + 273150000;
    730 	}
    731 }
    732 
    733 static void
    734 lm_refresh_fanrpm(struct lm_softc *sc, int n)
    735 {
    736 	int data, divisor = 1;
    737 
    738 	/*
    739 	 * We might get more accurate fan readings by adjusting the
    740 	 * divisor, but that might interfere with APM or other SMM
    741 	 * BIOS code reading the fan speeds.
    742 	 */
    743 
    744 	/* FAN3 has a fixed fan divisor. */
    745 	if (sc->lm_sensors[n].reg == LMD_FAN1 ||
    746 	    sc->lm_sensors[n].reg == LMD_FAN2) {
    747 		data = (*sc->lm_readreg)(sc, LMD_VIDFAN);
    748 		if (sc->lm_sensors[n].reg == LMD_FAN1)
    749 			divisor = (data >> 4) & 0x03;
    750 		else
    751 			divisor = (data >> 6) & 0x03;
    752 	}
    753 
    754 	data = (*sc->lm_readreg)(sc, sc->lm_sensors[n].reg);
    755 	if (data == 0xff || data == 0x00) {
    756 		INVALIDATE_SENSOR(n);
    757 	} else {
    758 		sc->sensors[n].validflags |= (ENVSYS_FVALID|ENVSYS_FCURVALID);
    759 		sc->sensors[n].cur.data_us = 1350000 / (data << divisor);
    760 	}
    761 }
    762 
    763 static void
    764 wb_refresh_sensor_data(struct lm_softc *sc)
    765 {
    766 	int banksel, bank, i;
    767 
    768 	/*
    769 	 * Properly save and restore bank selection register.
    770 	 */
    771 
    772 	banksel = bank = sc->lm_readreg(sc, WB_BANKSEL);
    773 	for (i = 0; i < sc->numsensors; i++) {
    774 		if (bank != sc->lm_sensors[i].bank) {
    775 			bank = sc->lm_sensors[i].bank;
    776 			lm_generic_banksel(sc, bank);
    777 		}
    778 		sc->lm_sensors[i].refresh(sc, i);
    779 	}
    780 	lm_generic_banksel(sc, banksel);
    781 }
    782 
    783 static void
    784 wb_w83637hf_refresh_vcore(struct lm_softc *sc, int n)
    785 {
    786 	int data;
    787 
    788 	data = (*sc->lm_readreg)(sc, sc->lm_sensors[n].reg);
    789 
    790 	/*
    791 	 * Depending on the voltage detection method,
    792 	 * one of the following formulas is used:
    793 	 *	VRM8 method: value = raw * 0.016V
    794 	 *	VRM9 method: value = raw * 0.00488V + 0.70V
    795 	 */
    796 	if (sc->vrm9)
    797 		sc->sensors[n].cur.data_s = (data * 4880) + 700000;
    798 	else
    799 		sc->sensors[n].cur.data_s = (data * 16000);
    800 }
    801 
    802 static void
    803 wb_refresh_nvolt(struct lm_softc *sc, int n)
    804 {
    805 	int data;
    806 
    807 	data = (*sc->lm_readreg)(sc, sc->lm_sensors[n].reg);
    808 	sc->sensors[n].cur.data_s = ((data << 4) - WB_VREF);
    809 	sc->sensors[n].cur.data_s *= sc->lm_sensors[n].rfact;
    810 	sc->sensors[n].cur.data_s /= 10;
    811 	sc->sensors[n].cur.data_s += WB_VREF * 1000;
    812 }
    813 
    814 static void
    815 wb_w83627ehf_refresh_nvolt(struct lm_softc *sc, int n)
    816 {
    817 	int data;
    818 
    819 	data = (*sc->lm_readreg)(sc, sc->lm_sensors[n].reg);
    820 	sc->sensors[n].cur.data_s = ((data << 3) - WB_W83627EHF_VREF);
    821 	sc->sensors[n].cur.data_s *= RFACT(232, 10);
    822 	sc->sensors[n].cur.data_s /= 10;
    823 	sc->sensors[n].cur.data_s += WB_W83627EHF_VREF * 1000;
    824 }
    825 
    826 static void
    827 wb_refresh_temp(struct lm_softc *sc, int n)
    828 {
    829 	int sdata;
    830 
    831 	/*
    832 	 * The data sheet suggests that the range of the temperature
    833 	 * sensor is between -55 degC and +125 degC.  However, values
    834 	 * around -48 degC seem to be a very common bogus values.
    835 	 * Since such values are unreasonably low, we use -45 degC for
    836 	 * the lower limit instead.
    837 	 */
    838 	sdata = (*sc->lm_readreg)(sc, sc->lm_sensors[n].reg) << 1;
    839 	sdata += (*sc->lm_readreg)(sc, sc->lm_sensors[n].reg + 1) >> 7;
    840 	if (sdata > 0x0fa && sdata < 0x1a6) {
    841 		INVALIDATE_SENSOR(n);
    842 	} else {
    843 		if (sdata & 0x100)
    844 			sdata -= 0x200;
    845 		sc->sensors[n].validflags |= (ENVSYS_FVALID|ENVSYS_FCURVALID);
    846 		sc->sensors[n].cur.data_us = sdata * 500000 + 273150000;
    847 	}
    848 }
    849 
    850 static void
    851 wb_refresh_fanrpm(struct lm_softc *sc, int n)
    852 {
    853 	int fan, data, divisor = 0;
    854 
    855 	/*
    856 	 * This is madness; the fan divisor bits are scattered all
    857 	 * over the place.
    858 	 */
    859 
    860 	if (sc->lm_sensors[n].reg == LMD_FAN1 ||
    861 	    sc->lm_sensors[n].reg == LMD_FAN2 ||
    862 	    sc->lm_sensors[n].reg == LMD_FAN3) {
    863 		data = (*sc->lm_readreg)(sc, WB_BANK0_VBAT);
    864 		fan = (sc->lm_sensors[n].reg - LMD_FAN1);
    865 		if ((data >> 5) & (1 << fan))
    866 			divisor |= 0x04;
    867 	}
    868 
    869 	if (sc->lm_sensors[n].reg == LMD_FAN1 ||
    870 	    sc->lm_sensors[n].reg == LMD_FAN2) {
    871 		data = (*sc->lm_readreg)(sc, LMD_VIDFAN);
    872 		if (sc->lm_sensors[n].reg == LMD_FAN1)
    873 			divisor |= (data >> 4) & 0x03;
    874 		else
    875 			divisor |= (data >> 6) & 0x03;
    876 	} else if (sc->lm_sensors[n].reg == LMD_FAN3) {
    877 		data = (*sc->lm_readreg)(sc, WB_PIN);
    878 		divisor |= (data >> 6) & 0x03;
    879 	} else if (sc->lm_sensors[n].reg == WB_BANK0_FAN4 ||
    880 		   sc->lm_sensors[n].reg == WB_BANK0_FAN5) {
    881 		data = (*sc->lm_readreg)(sc, WB_BANK0_FAN45);
    882 		if (sc->lm_sensors[n].reg == WB_BANK0_FAN4)
    883 			divisor |= (data >> 0) & 0x07;
    884 		else
    885 			divisor |= (data >> 4) & 0x07;
    886 	}
    887 
    888 	data = (*sc->lm_readreg)(sc, sc->lm_sensors[n].reg);
    889 	if (data == 0xff || data == 0x00) {
    890 		INVALIDATE_SENSOR(n);
    891 	} else {
    892 		sc->sensors[n].validflags |= (ENVSYS_FVALID|ENVSYS_FCURVALID);
    893 		sc->sensors[n].cur.data_us = 1350000 / (data << divisor);
    894 	}
    895 }
    896 
    897 static void
    898 wb_w83792d_refresh_fanrpm(struct lm_softc *sc, int n)
    899 {
    900 	int reg, shift, data, divisor = 1;
    901 
    902 	shift = 0;
    903 
    904 	switch (sc->lm_sensors[n].reg) {
    905 	case 0x28:
    906 		reg = 0x47; shift = 0;
    907 		break;
    908 	case 0x29:
    909 		reg = 0x47; shift = 4;
    910 		break;
    911 	case 0x2a:
    912 		reg = 0x5b; shift = 0;
    913 		break;
    914 	case 0xb8:
    915 		reg = 0x5b; shift = 4;
    916 		break;
    917 	case 0xb9:
    918 		reg = 0x5c; shift = 0;
    919 		break;
    920 	case 0xba:
    921 		reg = 0x5c; shift = 4;
    922 		break;
    923 	case 0xbe:
    924 		reg = 0x9e; shift = 0;
    925 		break;
    926 	default:
    927 		reg = 0;
    928 		break;
    929 	}
    930 
    931 	data = (*sc->lm_readreg)(sc, sc->lm_sensors[n].reg);
    932 	if (data == 0xff || data == 0x00) {
    933 		INVALIDATE_SENSOR(n);
    934 	} else {
    935 		if (reg != 0)
    936 			divisor = ((*sc->lm_readreg)(sc, reg) >> shift) & 0x7;
    937 		sc->sensors[n].validflags |= (ENVSYS_FVALID|ENVSYS_FCURVALID);
    938 		sc->sensors[n].cur.data_us = 1350000 / (data << divisor);
    939 	}
    940 }
    941 
    942 static void
    943 as_refresh_temp(struct lm_softc *sc, int n)
    944 {
    945 	int sdata;
    946 
    947 	/*
    948 	 * It seems a shorted temperature diode produces an all-ones
    949 	 * bit pattern.
    950 	 */
    951 	sdata = (*sc->lm_readreg)(sc, sc->lm_sensors[n].reg) << 1;
    952 	sdata += (*sc->lm_readreg)(sc, sc->lm_sensors[n].reg + 1) >> 7;
    953 	if (sdata == 0x1ff) {
    954 		INVALIDATE_SENSOR(n);
    955 	} else {
    956 		if (sdata & 0x100)
    957 			sdata -= 0x200;
    958 		sc->sensors[n].validflags |= (ENVSYS_FVALID|ENVSYS_FCURVALID);
    959 		sc->sensors[n].cur.data_us = sdata * 500000 + 273150000;
    960 	}
    961 }
    962 
    963 #undef INVALIDATE_SENSOR
    964 
    965 static int
    966 lm_gtredata(struct sysmon_envsys *sme, envsys_tre_data_t *tred)
    967 {
    968 	static const struct timeval onepointfive = { 1, 500000 };
    969 	struct timeval t, utv;
    970 	struct lm_softc *sc = sme->sme_cookie;
    971 
    972 	/* read new values at most once every 1.5 seconds */
    973 	getmicrouptime(&utv);
    974 	timeradd(&sc->lastread, &onepointfive, &t);
    975 	if (timercmp(&utv, &t, >)) {
    976 		sc->lastread = utv;
    977 		sc->refresh_sensor_data(sc);
    978 	}
    979 
    980 	*tred = sc->sensors[tred->sensor];
    981 
    982 	return 0;
    983 }
    984 
    985 static int
    986 generic_streinfo_fan(struct lm_softc *sc, envsys_basic_info_t *info, int n,
    987 	envsys_basic_info_t *binfo)
    988 {
    989 	uint8_t sdata;
    990 	int divisor;
    991 
    992 	/* FAN1 and FAN2 can have divisors set, but not FAN3 */
    993 	if ((sc->info[binfo->sensor].units == ENVSYS_SFANRPM)
    994 	    && (n < 2)) {
    995 		if (binfo->rpms == 0) {
    996 			binfo->validflags = 0;
    997 			return 0;
    998 		}
    999 
   1000 		/* write back the nominal FAN speed  */
   1001 		info->rpms = binfo->rpms;
   1002 
   1003 		/* 153 is the nominal FAN speed value */
   1004 		divisor = 1350000 / (binfo->rpms * 153);
   1005 
   1006 		/* ...but we need lg(divisor) */
   1007 		if (divisor <= 1)
   1008 		    divisor = 0;
   1009 		else if (divisor <= 2)
   1010 		    divisor = 1;
   1011 		else if (divisor <= 4)
   1012 		    divisor = 2;
   1013 		else
   1014 		    divisor = 3;
   1015 
   1016 		/*
   1017 		 * FAN1 div is in bits <5:4>, FAN2 div is
   1018 		 * in <7:6>
   1019 		 */
   1020 		sdata = (*sc->lm_readreg)(sc, LMD_VIDFAN);
   1021 		if ( n == 0 ) {  /* FAN1 */
   1022 		    divisor <<= 4;
   1023 		    sdata = (sdata & 0xCF) | divisor;
   1024 		} else { /* FAN2 */
   1025 		    divisor <<= 6;
   1026 		    sdata = (sdata & 0x3F) | divisor;
   1027 		}
   1028 
   1029 		(*sc->lm_writereg)(sc, LMD_VIDFAN, sdata);
   1030 	}
   1031 	return 0;
   1032 
   1033 }
   1034 
   1035 static int
   1036 lm_streinfo(struct sysmon_envsys *sme, envsys_basic_info_t *binfo)
   1037 {
   1038 	 struct lm_softc *sc = sme->sme_cookie;
   1039 
   1040 	 if (sc->info[binfo->sensor].units == ENVSYS_SVOLTS_DC)
   1041 		  sc->info[binfo->sensor].rfact = binfo->rfact;
   1042 	 else {
   1043 		if (sc->info[binfo->sensor].units == ENVSYS_SFANRPM) {
   1044 			generic_streinfo_fan(sc, &sc->info[binfo->sensor],
   1045 			    binfo->sensor - 8, binfo);
   1046 		}
   1047 		strlcpy(sc->info[binfo->sensor].desc, binfo->desc,
   1048 		    sizeof(sc->info[binfo->sensor].desc));
   1049 		binfo->validflags = ENVSYS_FVALID;
   1050 	 }
   1051 	 return 0;
   1052 }
   1053 
   1054 static int
   1055 wb781_streinfo(struct sysmon_envsys *sme, envsys_basic_info_t *binfo)
   1056 {
   1057 	 struct lm_softc *sc = sme->sme_cookie;
   1058 	 int divisor;
   1059 	 uint8_t sdata;
   1060 	 int i;
   1061 
   1062 	 if (sc->info[binfo->sensor].units == ENVSYS_SVOLTS_DC)
   1063 		  sc->info[binfo->sensor].rfact = binfo->rfact;
   1064 	 else {
   1065 		if (sc->info[binfo->sensor].units == ENVSYS_SFANRPM) {
   1066 			if (binfo->rpms == 0) {
   1067 				binfo->validflags = 0;
   1068 				return 0;
   1069 			}
   1070 
   1071 			/* write back the nominal FAN speed  */
   1072 			sc->info[binfo->sensor].rpms = binfo->rpms;
   1073 
   1074 			/* 153 is the nominal FAN speed value */
   1075 			divisor = 1350000 / (binfo->rpms * 153);
   1076 
   1077 			/* ...but we need lg(divisor) */
   1078 			for (i = 0; i < 7; i++) {
   1079 				if (divisor <= (1 << i))
   1080 				 	break;
   1081 			}
   1082 			divisor = i;
   1083 
   1084 			if (binfo->sensor == 10 || binfo->sensor == 11) {
   1085 				/*
   1086 				 * FAN1 div is in bits <5:4>, FAN2 div
   1087 				 * is in <7:6>
   1088 				 */
   1089 				sdata = (*sc->lm_readreg)(sc, LMD_VIDFAN);
   1090 				if ( binfo->sensor == 10 ) {  /* FAN1 */
   1091 					 sdata = (sdata & 0xCF) |
   1092 					     ((divisor & 0x3) << 4);
   1093 				} else { /* FAN2 */
   1094 					 sdata = (sdata & 0x3F) |
   1095 					     ((divisor & 0x3) << 6);
   1096 				}
   1097 				(*sc->lm_writereg)(sc, LMD_VIDFAN, sdata);
   1098 			} else {
   1099 				/* FAN3 is in WB_PIN <7:6> */
   1100 				sdata = (*sc->lm_readreg)(sc, WB_PIN);
   1101 				sdata = (sdata & 0x3F) |
   1102 				     ((divisor & 0x3) << 6);
   1103 				(*sc->lm_writereg)(sc, WB_PIN, sdata);
   1104 			}
   1105 		}
   1106 		strlcpy(sc->info[binfo->sensor].desc, binfo->desc,
   1107 		    sizeof(sc->info[binfo->sensor].desc));
   1108 		binfo->validflags = ENVSYS_FVALID;
   1109 	 }
   1110 	 return 0;
   1111 }
   1112 
   1113 static int
   1114 wb782_streinfo(struct sysmon_envsys *sme, envsys_basic_info_t *binfo)
   1115 {
   1116 	 struct lm_softc *sc = sme->sme_cookie;
   1117 	 int divisor;
   1118 	 uint8_t sdata;
   1119 	 int i;
   1120 
   1121 	 if (sc->info[binfo->sensor].units == ENVSYS_SVOLTS_DC)
   1122 		  sc->info[binfo->sensor].rfact = binfo->rfact;
   1123 	 else {
   1124 	 	if (sc->info[binfo->sensor].units == ENVSYS_SFANRPM) {
   1125 			if (binfo->rpms == 0) {
   1126 				binfo->validflags = 0;
   1127 				return 0;
   1128 			}
   1129 
   1130 			/* write back the nominal FAN speed  */
   1131 			sc->info[binfo->sensor].rpms = binfo->rpms;
   1132 
   1133 			/* 153 is the nominal FAN speed value */
   1134 			divisor = 1350000 / (binfo->rpms * 153);
   1135 
   1136 			/* ...but we need lg(divisor) */
   1137 			for (i = 0; i < 7; i++) {
   1138 				if (divisor <= (1 << i))
   1139 				 	break;
   1140 			}
   1141 			divisor = i;
   1142 
   1143 			if (binfo->sensor == 12 || binfo->sensor == 13) {
   1144 				/*
   1145 				 * FAN1 div is in bits <5:4>, FAN2 div
   1146 				 * is in <7:6>
   1147 				 */
   1148 				sdata = (*sc->lm_readreg)(sc, LMD_VIDFAN);
   1149 				if ( binfo->sensor == 12 ) {  /* FAN1 */
   1150 					 sdata = (sdata & 0xCF) |
   1151 					     ((divisor & 0x3) << 4);
   1152 				} else { /* FAN2 */
   1153 					 sdata = (sdata & 0x3F) |
   1154 					     ((divisor & 0x3) << 6);
   1155 				}
   1156 				(*sc->lm_writereg)(sc, LMD_VIDFAN, sdata);
   1157 			} else {
   1158 				/* FAN3 is in WB_PIN <7:6> */
   1159 				sdata = (*sc->lm_readreg)(sc, WB_PIN);
   1160 				sdata = (sdata & 0x3F) |
   1161 				     ((divisor & 0x3) << 6);
   1162 				(*sc->lm_writereg)(sc, WB_PIN, sdata);
   1163 			}
   1164 			/* Bit 2 of divisor is in WB_BANK0_VBAT */
   1165 			lm_generic_banksel(sc, WB_BANKSEL_B0);
   1166 			sdata = (*sc->lm_readreg)(sc, WB_BANK0_VBAT);
   1167 			sdata &= ~(0x20 << (binfo->sensor - 12));
   1168 			sdata |= (divisor & 0x4) << (binfo->sensor - 9);
   1169 			(*sc->lm_writereg)(sc, WB_BANK0_VBAT, sdata);
   1170 		}
   1171 
   1172 		strlcpy(sc->info[binfo->sensor].desc, binfo->desc,
   1173 		    sizeof(sc->info[binfo->sensor].desc));
   1174 		binfo->validflags = ENVSYS_FVALID;
   1175 	}
   1176 	return 0;
   1177 }
   1178