[BACK]Return to lm78.c CVS log [TXT][DIR] Up to [local] / sys / dev / ic

Annotation of sys/dev/ic/lm78.c, Revision 1.1.1.1

1.1       nbrk        1: /*     $OpenBSD: lm78.c,v 1.20 2007/06/25 22:50:18 cnst Exp $  */
                      2:
                      3: /*
                      4:  * Copyright (c) 2005, 2006 Mark Kettenis
                      5:  *
                      6:  * Permission to use, copy, modify, and distribute this software for any
                      7:  * purpose with or without fee is hereby granted, provided that the above
                      8:  * copyright notice and this permission notice appear in all copies.
                      9:  *
                     10:  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
                     11:  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
                     12:  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
                     13:  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
                     14:  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
                     15:  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
                     16:  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
                     17:  */
                     18:
                     19: #include <sys/param.h>
                     20: #include <sys/systm.h>
                     21: #include <sys/device.h>
                     22: #include <sys/kernel.h>
                     23: #include <sys/queue.h>
                     24: #include <sys/sensors.h>
                     25: #include <machine/bus.h>
                     26:
                     27: #include <dev/ic/lm78var.h>
                     28:
                     29: #if defined(LMDEBUG)
                     30: #define DPRINTF(x)             do { printf x; } while (0)
                     31: #else
                     32: #define DPRINTF(x)
                     33: #endif
                     34:
                     35: /*
                     36:  * LM78-compatible chips can typically measure voltages up to 4.096 V.
                     37:  * To measure higher voltages the input is attenuated with (external)
                     38:  * resistors.  Negative voltages are measured using inverting op amps
                     39:  * and resistors.  So we have to convert the sensor values back to
                     40:  * real voltages by applying the appropriate resistor factor.
                     41:  */
                     42: #define RFACT_NONE     10000
                     43: #define RFACT(x, y)    (RFACT_NONE * ((x) + (y)) / (y))
                     44: #define NRFACT(x, y)   (-RFACT_NONE * (x) / (y))
                     45:
                     46: struct cfdriver lm_cd = {
                     47:        NULL, "lm", DV_DULL
                     48: };
                     49:
                     50: int  lm_match(struct lm_softc *);
                     51: int  wb_match(struct lm_softc *);
                     52: int  def_match(struct lm_softc *);
                     53:
                     54: void lm_setup_sensors(struct lm_softc *, struct lm_sensor *);
                     55: void lm_refresh(void *);
                     56:
                     57: void lm_refresh_sensor_data(struct lm_softc *);
                     58: void lm_refresh_volt(struct lm_softc *, int);
                     59: void lm_refresh_temp(struct lm_softc *, int);
                     60: void lm_refresh_fanrpm(struct lm_softc *, int);
                     61:
                     62: void wb_refresh_sensor_data(struct lm_softc *);
                     63: void wb_w83637hf_refresh_vcore(struct lm_softc *, int);
                     64: void wb_refresh_nvolt(struct lm_softc *, int);
                     65: void wb_w83627ehf_refresh_nvolt(struct lm_softc *, int);
                     66: void wb_refresh_temp(struct lm_softc *, int);
                     67: void wb_refresh_fanrpm(struct lm_softc *, int);
                     68: void wb_w83792d_refresh_fanrpm(struct lm_softc *, int);
                     69:
                     70: void as_refresh_temp(struct lm_softc *, int);
                     71:
                     72: struct lm_chip {
                     73:        int (*chip_match)(struct lm_softc *);
                     74: };
                     75:
                     76: struct lm_chip lm_chips[] = {
                     77:        { wb_match },
                     78:        { lm_match },
                     79:        { def_match } /* Must be last */
                     80: };
                     81:
                     82: struct lm_sensor lm78_sensors[] = {
                     83:        /* Voltage */
                     84:        { "VCore A", SENSOR_VOLTS_DC, 0, 0x20, lm_refresh_volt, RFACT_NONE },
                     85:        { "VCore B", SENSOR_VOLTS_DC, 0, 0x21, lm_refresh_volt, RFACT_NONE },
                     86:        { "+3.3V", SENSOR_VOLTS_DC, 0, 0x22, lm_refresh_volt, RFACT_NONE },
                     87:        { "+5V", SENSOR_VOLTS_DC, 0, 0x23, lm_refresh_volt, RFACT(68, 100) },
                     88:        { "+12V", SENSOR_VOLTS_DC, 0, 0x24, lm_refresh_volt, RFACT(30, 10) },
                     89:        { "-12V", SENSOR_VOLTS_DC, 0, 0x25, lm_refresh_volt, NRFACT(240, 60) },
                     90:        { "-5V", SENSOR_VOLTS_DC, 0, 0x26, lm_refresh_volt, NRFACT(100, 60) },
                     91:
                     92:        /* Temperature */
                     93:        { "", SENSOR_TEMP, 0, 0x27, lm_refresh_temp },
                     94:
                     95:        /* Fans */
                     96:        { "", SENSOR_FANRPM, 0, 0x28, lm_refresh_fanrpm },
                     97:        { "", SENSOR_FANRPM, 0, 0x29, lm_refresh_fanrpm },
                     98:        { "", SENSOR_FANRPM, 0, 0x2a, lm_refresh_fanrpm },
                     99:
                    100:        { NULL }
                    101: };
                    102:
                    103: struct lm_sensor w83627hf_sensors[] = {
                    104:        /* Voltage */
                    105:        { "VCore A", SENSOR_VOLTS_DC, 0, 0x20, lm_refresh_volt, RFACT_NONE },
                    106:        { "VCore B", SENSOR_VOLTS_DC, 0, 0x21, lm_refresh_volt, RFACT_NONE },
                    107:        { "+3.3V", SENSOR_VOLTS_DC, 0, 0x22, lm_refresh_volt, RFACT_NONE },
                    108:        { "+5V", SENSOR_VOLTS_DC, 0, 0x23, lm_refresh_volt, RFACT(34, 50) },
                    109:        { "+12V", SENSOR_VOLTS_DC, 0, 0x24, lm_refresh_volt, RFACT(28, 10) },
                    110:        { "-12V", SENSOR_VOLTS_DC, 0, 0x25, wb_refresh_nvolt, RFACT(232, 56) },
                    111:        { "-5V", SENSOR_VOLTS_DC, 0, 0x26, wb_refresh_nvolt, RFACT(120, 56) },
                    112:        { "5VSB", SENSOR_VOLTS_DC, 5, 0x50, lm_refresh_volt, RFACT(17, 33) },
                    113:        { "VBAT", SENSOR_VOLTS_DC, 5, 0x51, lm_refresh_volt, RFACT_NONE },
                    114:
                    115:        /* Temperature */
                    116:        { "", SENSOR_TEMP, 0, 0x27, lm_refresh_temp },
                    117:        { "", SENSOR_TEMP, 1, 0x50, wb_refresh_temp },
                    118:        { "", SENSOR_TEMP, 2, 0x50, wb_refresh_temp },
                    119:
                    120:        /* Fans */
                    121:        { "", SENSOR_FANRPM, 0, 0x28, wb_refresh_fanrpm },
                    122:        { "", SENSOR_FANRPM, 0, 0x29, wb_refresh_fanrpm },
                    123:        { "", SENSOR_FANRPM, 0, 0x2a, wb_refresh_fanrpm },
                    124:
                    125:        { NULL }
                    126: };
                    127:
                    128: /*
                    129:  * The W83627EHF can measure voltages up to 2.048 V instead of the
                    130:  * traditional 4.096 V.  For measuring positive voltages, this can be
                    131:  * accounted for by halving the resistor factor.  Negative voltages
                    132:  * need special treatment, also because the reference voltage is 2.048 V
                    133:  * instead of the traditional 3.6 V.
                    134:  */
                    135: struct lm_sensor w83627ehf_sensors[] = {
                    136:        /* Voltage */
                    137:        { "VCore", SENSOR_VOLTS_DC, 0, 0x20, lm_refresh_volt, RFACT_NONE / 2},
                    138:        { "+12V", SENSOR_VOLTS_DC, 0, 0x21, lm_refresh_volt, RFACT(56, 10) / 2 },
                    139:        { "+3.3V", SENSOR_VOLTS_DC, 0, 0x22, lm_refresh_volt, RFACT(34, 34) / 2 },
                    140:        { "+3.3V", SENSOR_VOLTS_DC, 0, 0x23, lm_refresh_volt, RFACT(34, 34) / 2 },
                    141:        { "-12V", SENSOR_VOLTS_DC, 0, 0x24, wb_w83627ehf_refresh_nvolt },
                    142:        { "", SENSOR_VOLTS_DC, 0, 0x25, lm_refresh_volt, RFACT_NONE / 2 },
                    143:        { "", SENSOR_VOLTS_DC, 0, 0x26, lm_refresh_volt, RFACT_NONE / 2 },
                    144:        { "3.3VSB", SENSOR_VOLTS_DC, 5, 0x50, lm_refresh_volt, RFACT(34, 34) / 2 },
                    145:        { "VBAT", SENSOR_VOLTS_DC, 5, 0x51, lm_refresh_volt, RFACT_NONE / 2 },
                    146:        { "", SENSOR_VOLTS_DC, 5, 0x52, lm_refresh_volt, RFACT_NONE / 2 },
                    147:
                    148:        /* Temperature */
                    149:        { "", SENSOR_TEMP, 0, 0x27, lm_refresh_temp },
                    150:        { "", SENSOR_TEMP, 1, 0x50, wb_refresh_temp },
                    151:        { "", SENSOR_TEMP, 2, 0x50, wb_refresh_temp },
                    152:
                    153:        /* Fans */
                    154:        { "", SENSOR_FANRPM, 0, 0x28, wb_refresh_fanrpm },
                    155:        { "", SENSOR_FANRPM, 0, 0x29, wb_refresh_fanrpm },
                    156:        { "", SENSOR_FANRPM, 0, 0x2a, wb_refresh_fanrpm },
                    157:
                    158:        { NULL }
                    159: };
                    160:
                    161: /*
                    162:  * w83627dhg is almost identical to w83627ehf, except that
                    163:  * it has 9 instead of 10 voltage sensors
                    164:  */
                    165: struct lm_sensor w83627dhg_sensors[] = {
                    166:        /* Voltage */
                    167:        { "VCore", SENSOR_VOLTS_DC, 0, 0x20, lm_refresh_volt, RFACT_NONE / 2},
                    168:        { "+12V", SENSOR_VOLTS_DC, 0, 0x21, lm_refresh_volt, RFACT(56, 10) / 2 },
                    169:        { "+3.3V", SENSOR_VOLTS_DC, 0, 0x22, lm_refresh_volt, RFACT(34, 34) / 2 },
                    170:        { "+3.3V", SENSOR_VOLTS_DC, 0, 0x23, lm_refresh_volt, RFACT(34, 34) / 2 },
                    171:        { "-12V", SENSOR_VOLTS_DC, 0, 0x24, wb_w83627ehf_refresh_nvolt },
                    172:        { "", SENSOR_VOLTS_DC, 0, 0x25, lm_refresh_volt, RFACT_NONE / 2 },
                    173:        { "", SENSOR_VOLTS_DC, 0, 0x26, lm_refresh_volt, RFACT_NONE / 2 },
                    174:        { "3.3VSB", SENSOR_VOLTS_DC, 5, 0x50, lm_refresh_volt, RFACT(34, 34) / 2 },
                    175:        { "VBAT", SENSOR_VOLTS_DC, 5, 0x51, lm_refresh_volt, RFACT_NONE / 2 },
                    176:
                    177:        /* Temperature */
                    178:        { "", SENSOR_TEMP, 0, 0x27, lm_refresh_temp },
                    179:        { "", SENSOR_TEMP, 1, 0x50, wb_refresh_temp },
                    180:        { "", SENSOR_TEMP, 2, 0x50, wb_refresh_temp },
                    181:
                    182:        /* Fans */
                    183:        { "", SENSOR_FANRPM, 0, 0x28, wb_refresh_fanrpm },
                    184:        { "", SENSOR_FANRPM, 0, 0x29, wb_refresh_fanrpm },
                    185:        { "", SENSOR_FANRPM, 0, 0x2a, wb_refresh_fanrpm },
                    186:
                    187:        { NULL }
                    188: };
                    189:
                    190: struct lm_sensor w83637hf_sensors[] = {
                    191:        /* Voltage */
                    192:        { "VCore", SENSOR_VOLTS_DC, 0, 0x20, wb_w83637hf_refresh_vcore },
                    193:        { "+12V", SENSOR_VOLTS_DC, 0, 0x21, lm_refresh_volt, RFACT(28, 10) },
                    194:        { "+3.3V", SENSOR_VOLTS_DC, 0, 0x22, lm_refresh_volt, RFACT_NONE },
                    195:        { "+5V", SENSOR_VOLTS_DC, 0, 0x23, lm_refresh_volt, RFACT(34, 51) },
                    196:        { "-12V", SENSOR_VOLTS_DC, 0, 0x24, wb_refresh_nvolt, RFACT(232, 56) },
                    197:        { "5VSB", SENSOR_VOLTS_DC, 5, 0x50, lm_refresh_volt, RFACT(34, 51) },
                    198:        { "VBAT", SENSOR_VOLTS_DC, 5, 0x51, lm_refresh_volt, RFACT_NONE },
                    199:
                    200:        /* Temperature */
                    201:        { "", SENSOR_TEMP, 0, 0x27, lm_refresh_temp },
                    202:        { "", SENSOR_TEMP, 1, 0x50, wb_refresh_temp },
                    203:        { "", SENSOR_TEMP, 2, 0x50, wb_refresh_temp },
                    204:
                    205:        /* Fans */
                    206:        { "", SENSOR_FANRPM, 0, 0x28, wb_refresh_fanrpm },
                    207:        { "", SENSOR_FANRPM, 0, 0x29, wb_refresh_fanrpm },
                    208:        { "", SENSOR_FANRPM, 0, 0x2a, wb_refresh_fanrpm },
                    209:
                    210:        { NULL }
                    211: };
                    212:
                    213: struct lm_sensor w83697hf_sensors[] = {
                    214:        /* Voltage */
                    215:        { "VCore", SENSOR_VOLTS_DC, 0, 0x20, lm_refresh_volt, RFACT_NONE },
                    216:        { "+3.3V", SENSOR_VOLTS_DC, 0, 0x22, lm_refresh_volt, RFACT_NONE },
                    217:        { "+5V", SENSOR_VOLTS_DC, 0, 0x23, lm_refresh_volt, RFACT(34, 50) },
                    218:        { "+12V", SENSOR_VOLTS_DC, 0, 0x24, lm_refresh_volt, RFACT(28, 10) },
                    219:        { "-12V", SENSOR_VOLTS_DC, 0, 0x25, wb_refresh_nvolt, RFACT(232, 56) },
                    220:        { "-5V", SENSOR_VOLTS_DC, 0, 0x26, wb_refresh_nvolt, RFACT(120, 56) },
                    221:        { "5VSB", SENSOR_VOLTS_DC, 5, 0x50, lm_refresh_volt, RFACT(17, 33) },
                    222:        { "VBAT", SENSOR_VOLTS_DC, 5, 0x51, lm_refresh_volt, RFACT_NONE },
                    223:
                    224:        /* Temperature */
                    225:        { "", SENSOR_TEMP, 0, 0x27, lm_refresh_temp },
                    226:        { "", SENSOR_TEMP, 1, 0x50, wb_refresh_temp },
                    227:
                    228:        /* Fans */
                    229:        { "", SENSOR_FANRPM, 0, 0x28, wb_refresh_fanrpm },
                    230:        { "", SENSOR_FANRPM, 0, 0x29, wb_refresh_fanrpm },
                    231:
                    232:        { NULL }
                    233: };
                    234:
                    235: /*
                    236:  * The datasheet doesn't mention the (internal) resistors used for the
                    237:  * +5V, but using the values from the W83782D datasheets seems to
                    238:  * provide sensible results.
                    239:  */
                    240: struct lm_sensor w83781d_sensors[] = {
                    241:        /* Voltage */
                    242:        { "VCore A", SENSOR_VOLTS_DC, 0, 0x20, lm_refresh_volt, RFACT_NONE },
                    243:        { "VCore B", SENSOR_VOLTS_DC, 0, 0x21, lm_refresh_volt, RFACT_NONE },
                    244:        { "+3.3V", SENSOR_VOLTS_DC, 0, 0x22, lm_refresh_volt, RFACT_NONE },
                    245:        { "+5V", SENSOR_VOLTS_DC, 0, 0x23, lm_refresh_volt, RFACT(34, 50) },
                    246:        { "+12V", SENSOR_VOLTS_DC, 0, 0x24, lm_refresh_volt, RFACT(28, 10) },
                    247:        { "-12V", SENSOR_VOLTS_DC, 0, 0x25, lm_refresh_volt, NRFACT(2100, 604) },
                    248:        { "-5V", SENSOR_VOLTS_DC, 0, 0x26, lm_refresh_volt, NRFACT(909, 604) },
                    249:
                    250:        /* Temperature */
                    251:        { "", SENSOR_TEMP, 0, 0x27, lm_refresh_temp },
                    252:        { "", SENSOR_TEMP, 1, 0x50, wb_refresh_temp },
                    253:        { "", SENSOR_TEMP, 2, 0x50, wb_refresh_temp },
                    254:
                    255:        /* Fans */
                    256:        { "", SENSOR_FANRPM, 0, 0x28, lm_refresh_fanrpm },
                    257:        { "", SENSOR_FANRPM, 0, 0x29, lm_refresh_fanrpm },
                    258:        { "", SENSOR_FANRPM, 0, 0x2a, lm_refresh_fanrpm },
                    259:
                    260:        { NULL }
                    261: };
                    262:
                    263: struct lm_sensor w83782d_sensors[] = {
                    264:        /* Voltage */
                    265:        { "VCore", SENSOR_VOLTS_DC, 0, 0x20, lm_refresh_volt, RFACT_NONE },
                    266:        { "VINR0", SENSOR_VOLTS_DC, 0, 0x21, lm_refresh_volt, RFACT_NONE },
                    267:        { "+3.3V", SENSOR_VOLTS_DC, 0, 0x22, lm_refresh_volt, RFACT_NONE },
                    268:        { "+5V", SENSOR_VOLTS_DC, 0, 0x23, lm_refresh_volt, RFACT(34, 50) },
                    269:        { "+12V", SENSOR_VOLTS_DC, 0, 0x24, lm_refresh_volt, RFACT(28, 10) },
                    270:        { "-12V", SENSOR_VOLTS_DC, 0, 0x25, wb_refresh_nvolt, RFACT(232, 56) },
                    271:        { "-5V", SENSOR_VOLTS_DC, 0, 0x26, wb_refresh_nvolt, RFACT(120, 56) },
                    272:        { "5VSB", SENSOR_VOLTS_DC, 5, 0x50, lm_refresh_volt, RFACT(17, 33) },
                    273:        { "VBAT", SENSOR_VOLTS_DC, 5, 0x51, lm_refresh_volt, RFACT_NONE },
                    274:
                    275:        /* Temperature */
                    276:        { "", SENSOR_TEMP, 0, 0x27, lm_refresh_temp },
                    277:        { "", SENSOR_TEMP, 1, 0x50, wb_refresh_temp },
                    278:        { "", SENSOR_TEMP, 2, 0x50, wb_refresh_temp },
                    279:
                    280:        /* Fans */
                    281:        { "", SENSOR_FANRPM, 0, 0x28, wb_refresh_fanrpm },
                    282:        { "", SENSOR_FANRPM, 0, 0x29, wb_refresh_fanrpm },
                    283:        { "", SENSOR_FANRPM, 0, 0x2a, wb_refresh_fanrpm },
                    284:
                    285:        { NULL }
                    286: };
                    287:
                    288: struct lm_sensor w83783s_sensors[] = {
                    289:        /* Voltage */
                    290:        { "VCore", SENSOR_VOLTS_DC, 0, 0x20, lm_refresh_volt, RFACT_NONE },
                    291:        { "+3.3V", SENSOR_VOLTS_DC, 0, 0x22, lm_refresh_volt, RFACT_NONE },
                    292:        { "+5V", SENSOR_VOLTS_DC, 0, 0x23, lm_refresh_volt, RFACT(34, 50) },
                    293:        { "+12V", SENSOR_VOLTS_DC, 0, 0x24, lm_refresh_volt, RFACT(28, 10) },
                    294:        { "-12V", SENSOR_VOLTS_DC, 0, 0x25, wb_refresh_nvolt, RFACT(232, 56) },
                    295:        { "-5V", SENSOR_VOLTS_DC, 0, 0x26, wb_refresh_nvolt, RFACT(120, 56) },
                    296:
                    297:        /* Temperature */
                    298:        { "", SENSOR_TEMP, 0, 0x27, lm_refresh_temp },
                    299:        { "", SENSOR_TEMP, 1, 0x50, wb_refresh_temp },
                    300:
                    301:        /* Fans */
                    302:        { "", SENSOR_FANRPM, 0, 0x28, wb_refresh_fanrpm },
                    303:        { "", SENSOR_FANRPM, 0, 0x29, wb_refresh_fanrpm },
                    304:        { "", SENSOR_FANRPM, 0, 0x2a, wb_refresh_fanrpm },
                    305:
                    306:        { NULL }
                    307: };
                    308:
                    309: struct lm_sensor w83791d_sensors[] = {
                    310:        /* Voltage */
                    311:        { "VCore", SENSOR_VOLTS_DC, 0, 0x20, lm_refresh_volt, 10000 },
                    312:        { "VINR0", SENSOR_VOLTS_DC, 0, 0x21, lm_refresh_volt, 10000 },
                    313:        { "+3.3V", SENSOR_VOLTS_DC, 0, 0x22, lm_refresh_volt, 10000 },
                    314:        { "+5V", SENSOR_VOLTS_DC, 0, 0x23, lm_refresh_volt, RFACT(34, 50) },
                    315:        { "+12V", SENSOR_VOLTS_DC, 0, 0x24, lm_refresh_volt, RFACT(28, 10) },
                    316:        { "-12V", SENSOR_VOLTS_DC, 0, 0x25, wb_refresh_nvolt, RFACT(232, 56) },
                    317:        { "-5V", SENSOR_VOLTS_DC, 0, 0x26, wb_refresh_nvolt, RFACT(120, 56) },
                    318:        { "5VSB", SENSOR_VOLTS_DC, 0, 0xb0, lm_refresh_volt, RFACT(17, 33) },
                    319:        { "VBAT", SENSOR_VOLTS_DC, 0, 0xb1, lm_refresh_volt, RFACT_NONE },
                    320:        { "VINR1", SENSOR_VOLTS_DC, 0, 0xb2, lm_refresh_volt, RFACT_NONE },
                    321:
                    322:        /* Temperature */
                    323:        { "", SENSOR_TEMP, 0, 0x27, lm_refresh_temp },
                    324:        { "", SENSOR_TEMP, 0, 0xc0, wb_refresh_temp },
                    325:        { "", SENSOR_TEMP, 0, 0xc8, wb_refresh_temp },
                    326:
                    327:        /* Fans */
                    328:        { "", SENSOR_FANRPM, 0, 0x28, wb_refresh_fanrpm },
                    329:        { "", SENSOR_FANRPM, 0, 0x29, wb_refresh_fanrpm },
                    330:        { "", SENSOR_FANRPM, 0, 0x2a, wb_refresh_fanrpm },
                    331:        { "", SENSOR_FANRPM, 0, 0xba, wb_refresh_fanrpm },
                    332:        { "", SENSOR_FANRPM, 0, 0xbb, wb_refresh_fanrpm },
                    333:
                    334:        { NULL }
                    335: };
                    336:
                    337: struct lm_sensor w83792d_sensors[] = {
                    338:        /* Voltage */
                    339:        { "VCore A", SENSOR_VOLTS_DC, 0, 0x20, lm_refresh_volt, RFACT_NONE },
                    340:        { "VCore B", SENSOR_VOLTS_DC, 0, 0x21, lm_refresh_volt, RFACT_NONE },
                    341:        { "+3.3V", SENSOR_VOLTS_DC, 0, 0x22, lm_refresh_volt, RFACT_NONE },
                    342:        { "-5V", SENSOR_VOLTS_DC, 0, 0x23, wb_refresh_nvolt, RFACT(120, 56) },
                    343:        { "+12V", SENSOR_VOLTS_DC, 0, 0x24, lm_refresh_volt, RFACT(28, 10) },
                    344:        { "-12V", SENSOR_VOLTS_DC, 0, 0x25, wb_refresh_nvolt, RFACT(232, 56) },
                    345:        { "+5V", SENSOR_VOLTS_DC, 0, 0x26, lm_refresh_volt, RFACT(34, 50) },
                    346:        { "5VSB", SENSOR_VOLTS_DC, 0, 0xb0, lm_refresh_volt, RFACT(17, 33) },
                    347:        { "VBAT", SENSOR_VOLTS_DC, 0, 0xb1, lm_refresh_volt, RFACT_NONE },
                    348:
                    349:        /* Temperature */
                    350:        { "", SENSOR_TEMP, 0, 0x27, lm_refresh_temp },
                    351:        { "", SENSOR_TEMP, 0, 0xc0, wb_refresh_temp },
                    352:        { "", SENSOR_TEMP, 0, 0xc8, wb_refresh_temp },
                    353:
                    354:        /* Fans */
                    355:        { "", SENSOR_FANRPM, 0, 0x28, wb_w83792d_refresh_fanrpm },
                    356:        { "", SENSOR_FANRPM, 0, 0x29, wb_w83792d_refresh_fanrpm },
                    357:        { "", SENSOR_FANRPM, 0, 0x2a, wb_w83792d_refresh_fanrpm },
                    358:        { "", SENSOR_FANRPM, 0, 0xb8, wb_w83792d_refresh_fanrpm },
                    359:        { "", SENSOR_FANRPM, 0, 0xb9, wb_w83792d_refresh_fanrpm },
                    360:        { "", SENSOR_FANRPM, 0, 0xba, wb_w83792d_refresh_fanrpm },
                    361:        { "", SENSOR_FANRPM, 0, 0xbe, wb_w83792d_refresh_fanrpm },
                    362:
                    363:        { NULL }
                    364: };
                    365:
                    366: struct lm_sensor as99127f_sensors[] = {
                    367:        /* Voltage */
                    368:        { "VCore A", SENSOR_VOLTS_DC, 0, 0x20, lm_refresh_volt, RFACT_NONE },
                    369:        { "VCore B", SENSOR_VOLTS_DC, 0, 0x21, lm_refresh_volt, RFACT_NONE },
                    370:        { "+3.3V", SENSOR_VOLTS_DC, 0, 0x22, lm_refresh_volt, RFACT_NONE },
                    371:        { "+5V", SENSOR_VOLTS_DC, 0, 0x23, lm_refresh_volt, RFACT(34, 50) },
                    372:        { "+12V", SENSOR_VOLTS_DC, 0, 0x24, lm_refresh_volt, RFACT(28, 10) },
                    373:        { "-12V", SENSOR_VOLTS_DC, 0, 0x25, wb_refresh_nvolt, RFACT(232, 56) },
                    374:        { "-5V", SENSOR_VOLTS_DC, 0, 0x26, wb_refresh_nvolt, RFACT(120, 56) },
                    375:
                    376:        /* Temperature */
                    377:        { "", SENSOR_TEMP, 0, 0x27, lm_refresh_temp },
                    378:        { "", SENSOR_TEMP, 1, 0x50, as_refresh_temp },
                    379:        { "", SENSOR_TEMP, 2, 0x50, as_refresh_temp },
                    380:
                    381:        /* Fans */
                    382:        { "", SENSOR_FANRPM, 0, 0x28, lm_refresh_fanrpm },
                    383:        { "", SENSOR_FANRPM, 0, 0x29, lm_refresh_fanrpm },
                    384:        { "", SENSOR_FANRPM, 0, 0x2a, lm_refresh_fanrpm },
                    385:
                    386:        { NULL }
                    387: };
                    388:
                    389: void
                    390: lm_attach(struct lm_softc *sc)
                    391: {
                    392:        u_int i, config;
                    393:
                    394:        for (i = 0; i < sizeof(lm_chips) / sizeof(lm_chips[0]); i++)
                    395:                if (lm_chips[i].chip_match(sc))
                    396:                        break;
                    397:
                    398:        /* No point in doing anything if we don't have any sensors. */
                    399:        if (sc->numsensors == 0)
                    400:                return;
                    401:
                    402:        sc->sensortask = sensor_task_register(sc, lm_refresh, 5);
                    403:        if (sc->sensortask == NULL) {
                    404:                printf("%s: unable to register update task\n",
                    405:                    sc->sc_dev.dv_xname);
                    406:                return;
                    407:        }
                    408:
                    409:        /* Start the monitoring loop */
                    410:        config = sc->lm_readreg(sc, LM_CONFIG);
                    411:        sc->lm_writereg(sc, LM_CONFIG, config | 0x01);
                    412:
                    413:        /* Add sensors */
                    414:        for (i = 0; i < sc->numsensors; ++i)
                    415:                sensor_attach(&sc->sensordev, &sc->sensors[i]);
                    416:        sensordev_install(&sc->sensordev);
                    417: }
                    418:
                    419: int
                    420: lm_detach(struct lm_softc *sc)
                    421: {
                    422:        int i;
                    423:
                    424:        /* Remove sensors */
                    425:        sensordev_deinstall(&sc->sensordev);
                    426:        for (i = 0; i < sc->numsensors; i++)
                    427:                sensor_detach(&sc->sensordev, &sc->sensors[i]);
                    428:
                    429:        if (sc->sensortask != NULL)
                    430:                sensor_task_unregister(sc->sensortask);
                    431:
                    432:        return 0;
                    433: }
                    434:
                    435: int
                    436: lm_match(struct lm_softc *sc)
                    437: {
                    438:        int chipid;
                    439:
                    440:        /* See if we have an LM78 or LM79. */
                    441:        chipid = sc->lm_readreg(sc, LM_CHIPID) & LM_CHIPID_MASK;
                    442:        switch(chipid) {
                    443:        case LM_CHIPID_LM78:
                    444:                printf(": LM78\n");
                    445:                break;
                    446:        case LM_CHIPID_LM78J:
                    447:                printf(": LM78J\n");
                    448:                break;
                    449:        case LM_CHIPID_LM79:
                    450:                printf(": LM79\n");
                    451:                break;
                    452:        case LM_CHIPID_LM81:
                    453:                printf(": LM81\n");
                    454:                break;
                    455:        default:
                    456:                return 0;
                    457:        }
                    458:
                    459:        lm_setup_sensors(sc, lm78_sensors);
                    460:        sc->refresh_sensor_data = lm_refresh_sensor_data;
                    461:        return 1;
                    462: }
                    463:
                    464: int
                    465: def_match(struct lm_softc *sc)
                    466: {
                    467:        int chipid;
                    468:
                    469:        chipid = sc->lm_readreg(sc, LM_CHIPID) & LM_CHIPID_MASK;
                    470:        printf(": unknown chip (ID %d)\n", chipid);
                    471:
                    472:        lm_setup_sensors(sc, lm78_sensors);
                    473:        sc->refresh_sensor_data = lm_refresh_sensor_data;
                    474:        return 1;
                    475: }
                    476:
                    477: int
                    478: wb_match(struct lm_softc *sc)
                    479: {
                    480:        int banksel, vendid, devid;
                    481:
                    482:        /* Read vendor ID */
                    483:        banksel = sc->lm_readreg(sc, WB_BANKSEL);
                    484:        sc->lm_writereg(sc, WB_BANKSEL, WB_BANKSEL_HBAC);
                    485:        vendid = sc->lm_readreg(sc, WB_VENDID) << 8;
                    486:        sc->lm_writereg(sc, WB_BANKSEL, 0);
                    487:        vendid |= sc->lm_readreg(sc, WB_VENDID);
                    488:        sc->lm_writereg(sc, WB_BANKSEL, banksel);
                    489:        DPRINTF((" winbond vend id 0x%x\n", vendid));
                    490:        if (vendid != WB_VENDID_WINBOND && vendid != WB_VENDID_ASUS)
                    491:                return 0;
                    492:
                    493:        /* Read device/chip ID */
                    494:        sc->lm_writereg(sc, WB_BANKSEL, WB_BANKSEL_B0);
                    495:        devid = sc->lm_readreg(sc, LM_CHIPID);
                    496:        sc->chipid = sc->lm_readreg(sc, WB_BANK0_CHIPID);
                    497:        sc->lm_writereg(sc, WB_BANKSEL, banksel);
                    498:        DPRINTF((" winbond chip id 0x%x\n", sc->chipid));
                    499:        switch(sc->chipid) {
                    500:        case WB_CHIPID_W83627HF:
                    501:                printf(": W83627HF\n");
                    502:                lm_setup_sensors(sc, w83627hf_sensors);
                    503:                break;
                    504:        case WB_CHIPID_W83627THF:
                    505:                printf(": W83627THF\n");
                    506:                lm_setup_sensors(sc, w83637hf_sensors);
                    507:                break;
                    508:        case WB_CHIPID_W83627EHF_A:
                    509:                printf(": W83627EHF-A\n");
                    510:                lm_setup_sensors(sc, w83627ehf_sensors);
                    511:                break;
                    512:        case WB_CHIPID_W83627EHF:
                    513:                printf(": W83627EHF\n");
                    514:                lm_setup_sensors(sc, w83627ehf_sensors);
                    515:                break;
                    516:        case WB_CHIPID_W83627DHG:
                    517:                printf(": W83627DHG\n");
                    518:                lm_setup_sensors(sc, w83627dhg_sensors);
                    519:                break;
                    520:        case WB_CHIPID_W83637HF:
                    521:                printf(": W83637HF\n");
                    522:                sc->lm_writereg(sc, WB_BANKSEL, WB_BANKSEL_B0);
                    523:                if (sc->lm_readreg(sc, WB_BANK0_CONFIG) & WB_CONFIG_VMR9)
                    524:                        sc->vrm9 = 1;
                    525:                sc->lm_writereg(sc, WB_BANKSEL, banksel);
                    526:                lm_setup_sensors(sc, w83637hf_sensors);
                    527:                break;
                    528:        case WB_CHIPID_W83697HF:
                    529:                printf(": W83697HF\n");
                    530:                lm_setup_sensors(sc, w83697hf_sensors);
                    531:                break;
                    532:        case WB_CHIPID_W83781D:
                    533:        case WB_CHIPID_W83781D_2:
                    534:                printf(": W83781D\n");
                    535:                lm_setup_sensors(sc, w83781d_sensors);
                    536:                break;
                    537:        case WB_CHIPID_W83782D:
                    538:                printf(": W83782D\n");
                    539:                lm_setup_sensors(sc, w83782d_sensors);
                    540:                break;
                    541:        case WB_CHIPID_W83783S:
                    542:                printf(": W83783S\n");
                    543:                lm_setup_sensors(sc, w83783s_sensors);
                    544:                break;
                    545:        case WB_CHIPID_W83791D:
                    546:                printf(": W83791D\n");
                    547:                lm_setup_sensors(sc, w83791d_sensors);
                    548:                break;
                    549:        case WB_CHIPID_W83791SD:
                    550:                printf(": W83791SD\n");
                    551:                break;
                    552:        case WB_CHIPID_W83792D:
                    553:                if (devid >= 0x10 && devid <= 0x29)
                    554:                        printf(": W83792D rev %c\n", 'A' + devid - 0x10);
                    555:                else
                    556:                        printf(": W83792D rev 0x%x\n", devid);
                    557:                lm_setup_sensors(sc, w83792d_sensors);
                    558:                break;
                    559:        case WB_CHIPID_AS99127F:
                    560:                if (vendid == WB_VENDID_ASUS) {
                    561:                        printf(": AS99127F\n");
                    562:                        lm_setup_sensors(sc, w83781d_sensors);
                    563:                } else {
                    564:                        printf(": AS99127F rev 2\n");
                    565:                        lm_setup_sensors(sc, as99127f_sensors);
                    566:                }
                    567:                break;
                    568:        default:
                    569:                printf(": unknown Winbond chip (ID 0x%x)\n", sc->chipid);
                    570:                /* Handle as a standard LM78. */
                    571:                lm_setup_sensors(sc, lm78_sensors);
                    572:                sc->refresh_sensor_data = lm_refresh_sensor_data;
                    573:                return 1;
                    574:        }
                    575:
                    576:        sc->refresh_sensor_data = wb_refresh_sensor_data;
                    577:        return 1;
                    578: }
                    579:
                    580: void
                    581: lm_setup_sensors(struct lm_softc *sc, struct lm_sensor *sensors)
                    582: {
                    583:        int i;
                    584:
                    585:        strlcpy(sc->sensordev.xname, sc->sc_dev.dv_xname,
                    586:            sizeof(sc->sensordev.xname));
                    587:
                    588:        for (i = 0; sensors[i].desc; i++) {
                    589:                sc->sensors[i].type = sensors[i].type;
                    590:                strlcpy(sc->sensors[i].desc, sensors[i].desc,
                    591:                    sizeof(sc->sensors[i].desc));
                    592:                sc->numsensors++;
                    593:        }
                    594:        sc->lm_sensors = sensors;
                    595: }
                    596:
                    597: void
                    598: lm_refresh(void *arg)
                    599: {
                    600:        struct lm_softc *sc = arg;
                    601:
                    602:        sc->refresh_sensor_data(sc);
                    603: }
                    604:
                    605: void
                    606: lm_refresh_sensor_data(struct lm_softc *sc)
                    607: {
                    608:        int i;
                    609:
                    610:        for (i = 0; i < sc->numsensors; i++)
                    611:                sc->lm_sensors[i].refresh(sc, i);
                    612: }
                    613:
                    614: void
                    615: lm_refresh_volt(struct lm_softc *sc, int n)
                    616: {
                    617:        struct ksensor *sensor = &sc->sensors[n];
                    618:        int data;
                    619:
                    620:        data = sc->lm_readreg(sc, sc->lm_sensors[n].reg);
                    621:        sensor->value = (data << 4);
                    622:        sensor->value *= sc->lm_sensors[n].rfact;
                    623:        sensor->value /= 10;
                    624: }
                    625:
                    626: void
                    627: lm_refresh_temp(struct lm_softc *sc, int n)
                    628: {
                    629:        struct ksensor *sensor = &sc->sensors[n];
                    630:        int sdata;
                    631:
                    632:        /*
                    633:         * The data sheet suggests that the range of the temperature
                    634:         * sensor is between -55 degC and +125 degC.
                    635:         */
                    636:        sdata = sc->lm_readreg(sc, sc->lm_sensors[n].reg);
                    637:        if (sdata > 0x7d && sdata < 0xc9) {
                    638:                sensor->flags |= SENSOR_FINVALID;
                    639:                sensor->value = 0;
                    640:        } else {
                    641:                if (sdata & 0x80)
                    642:                        sdata -= 0x100;
                    643:                sensor->flags &= ~SENSOR_FINVALID;
                    644:                sensor->value = sdata * 1000000 + 273150000;
                    645:        }
                    646: }
                    647:
                    648: void
                    649: lm_refresh_fanrpm(struct lm_softc *sc, int n)
                    650: {
                    651:        struct ksensor *sensor = &sc->sensors[n];
                    652:        int data, divisor = 1;
                    653:
                    654:        /*
                    655:         * We might get more accurate fan readings by adjusting the
                    656:         * divisor, but that might interfere with APM or other SMM
                    657:         * BIOS code reading the fan speeds.
                    658:         */
                    659:
                    660:        /* FAN3 has a fixed fan divisor. */
                    661:        if (sc->lm_sensors[n].reg == LM_FAN1 ||
                    662:            sc->lm_sensors[n].reg == LM_FAN2) {
                    663:                data = sc->lm_readreg(sc, LM_VIDFAN);
                    664:                if (sc->lm_sensors[n].reg == LM_FAN1)
                    665:                        divisor = (data >> 4) & 0x03;
                    666:                else
                    667:                        divisor = (data >> 6) & 0x03;
                    668:        }
                    669:
                    670:        data = sc->lm_readreg(sc, sc->lm_sensors[n].reg);
                    671:        if (data == 0xff || data == 0x00) {
                    672:                sensor->flags |= SENSOR_FINVALID;
                    673:                sensor->value = 0;
                    674:        } else {
                    675:                sensor->flags &= ~SENSOR_FINVALID;
                    676:                sensor->value = 1350000 / (data << divisor);
                    677:        }
                    678: }
                    679:
                    680: void
                    681: wb_refresh_sensor_data(struct lm_softc *sc)
                    682: {
                    683:        int banksel, bank, i;
                    684:
                    685:        /*
                    686:         * Properly save and restore bank selection register.
                    687:         */
                    688:
                    689:        banksel = bank = sc->lm_readreg(sc, WB_BANKSEL);
                    690:        for (i = 0; i < sc->numsensors; i++) {
                    691:                if (bank != sc->lm_sensors[i].bank) {
                    692:                        bank = sc->lm_sensors[i].bank;
                    693:                        sc->lm_writereg(sc, WB_BANKSEL, bank);
                    694:                }
                    695:                sc->lm_sensors[i].refresh(sc, i);
                    696:        }
                    697:        sc->lm_writereg(sc, WB_BANKSEL, banksel);
                    698: }
                    699:
                    700: void
                    701: wb_w83637hf_refresh_vcore(struct lm_softc *sc, int n)
                    702: {
                    703:        struct ksensor *sensor = &sc->sensors[n];
                    704:        int data;
                    705:
                    706:        data = sc->lm_readreg(sc, sc->lm_sensors[n].reg);
                    707:
                    708:        /*
                    709:         * Depending on the voltage detection method,
                    710:         * one of the following formulas is used:
                    711:         *      VRM8 method: value = raw * 0.016V
                    712:         *      VRM9 method: value = raw * 0.00488V + 0.70V
                    713:         */
                    714:        if (sc->vrm9)
                    715:                sensor->value = (data * 4880) + 700000;
                    716:        else
                    717:                sensor->value = (data * 16000);
                    718: }
                    719:
                    720: void
                    721: wb_refresh_nvolt(struct lm_softc *sc, int n)
                    722: {
                    723:        struct ksensor *sensor = &sc->sensors[n];
                    724:        int data;
                    725:
                    726:        data = sc->lm_readreg(sc, sc->lm_sensors[n].reg);
                    727:        sensor->value = ((data << 4) - WB_VREF);
                    728:        sensor->value *= sc->lm_sensors[n].rfact;
                    729:        sensor->value /= 10;
                    730:        sensor->value += WB_VREF * 1000;
                    731: }
                    732:
                    733: void
                    734: wb_w83627ehf_refresh_nvolt(struct lm_softc *sc, int n)
                    735: {
                    736:        struct ksensor *sensor = &sc->sensors[n];
                    737:        int data;
                    738:
                    739:        data = sc->lm_readreg(sc, sc->lm_sensors[n].reg);
                    740:        sensor->value = ((data << 3) - WB_W83627EHF_VREF);
                    741:        sensor->value *= RFACT(232, 10);
                    742:        sensor->value /= 10;
                    743:        sensor->value += WB_W83627EHF_VREF * 1000;
                    744: }
                    745:
                    746: void
                    747: wb_refresh_temp(struct lm_softc *sc, int n)
                    748: {
                    749:        struct ksensor *sensor = &sc->sensors[n];
                    750:        int sdata;
                    751:
                    752:        /*
                    753:         * The data sheet suggests that the range of the temperature
                    754:         * sensor is between -55 degC and +125 degC.  However, values
                    755:         * around -48 degC seem to be a very common bogus values.
                    756:         * Since such values are unreasonably low, we use -45 degC for
                    757:         * the lower limit instead.
                    758:         */
                    759:        sdata = sc->lm_readreg(sc, sc->lm_sensors[n].reg) << 1;
                    760:        sdata += sc->lm_readreg(sc, sc->lm_sensors[n].reg + 1) >> 7;
                    761:        if (sdata > 0x0fa && sdata < 0x1a6) {
                    762:                sensor->flags |= SENSOR_FINVALID;
                    763:                sensor->value = 0;
                    764:        } else {
                    765:                if (sdata & 0x100)
                    766:                        sdata -= 0x200;
                    767:                sensor->flags &= ~SENSOR_FINVALID;
                    768:                sensor->value = sdata * 500000 + 273150000;
                    769:        }
                    770: }
                    771:
                    772: void
                    773: wb_refresh_fanrpm(struct lm_softc *sc, int n)
                    774: {
                    775:        struct ksensor *sensor = &sc->sensors[n];
                    776:        int fan, data, divisor = 0;
                    777:
                    778:        /*
                    779:         * This is madness; the fan divisor bits are scattered all
                    780:         * over the place.
                    781:         */
                    782:
                    783:        if (sc->lm_sensors[n].reg == LM_FAN1 ||
                    784:            sc->lm_sensors[n].reg == LM_FAN2 ||
                    785:            sc->lm_sensors[n].reg == LM_FAN3) {
                    786:                data = sc->lm_readreg(sc, WB_BANK0_VBAT);
                    787:                fan = (sc->lm_sensors[n].reg - LM_FAN1);
                    788:                if ((data >> 5) & (1 << fan))
                    789:                        divisor |= 0x04;
                    790:        }
                    791:
                    792:        if (sc->lm_sensors[n].reg == LM_FAN1 ||
                    793:            sc->lm_sensors[n].reg == LM_FAN2) {
                    794:                data = sc->lm_readreg(sc, LM_VIDFAN);
                    795:                if (sc->lm_sensors[n].reg == LM_FAN1)
                    796:                        divisor |= (data >> 4) & 0x03;
                    797:                else
                    798:                        divisor |= (data >> 6) & 0x03;
                    799:        } else if (sc->lm_sensors[n].reg == LM_FAN3) {
                    800:                data = sc->lm_readreg(sc, WB_PIN);
                    801:                divisor |= (data >> 6) & 0x03;
                    802:        } else if (sc->lm_sensors[n].reg == WB_BANK0_FAN4 ||
                    803:                   sc->lm_sensors[n].reg == WB_BANK0_FAN5) {
                    804:                data = sc->lm_readreg(sc, WB_BANK0_FAN45);
                    805:                if (sc->lm_sensors[n].reg == WB_BANK0_FAN4)
                    806:                        divisor |= (data >> 0) & 0x07;
                    807:                else
                    808:                        divisor |= (data >> 4) & 0x07;
                    809:        }
                    810:
                    811:        data = sc->lm_readreg(sc, sc->lm_sensors[n].reg);
                    812:        if (data == 0xff || data == 0x00) {
                    813:                sensor->flags |= SENSOR_FINVALID;
                    814:                sensor->value = 0;
                    815:        } else {
                    816:                sensor->flags &= ~SENSOR_FINVALID;
                    817:                sensor->value = 1350000 / (data << divisor);
                    818:        }
                    819: }
                    820:
                    821: void
                    822: wb_w83792d_refresh_fanrpm(struct lm_softc *sc, int n)
                    823: {
                    824:        struct ksensor *sensor = &sc->sensors[n];
                    825:        int reg, shift, data, divisor = 1;
                    826:
                    827:        switch (sc->lm_sensors[n].reg) {
                    828:        case 0x28:
                    829:                reg = 0x47; shift = 0;
                    830:                break;
                    831:        case 0x29:
                    832:                reg = 0x47; shift = 4;
                    833:                break;
                    834:        case 0x2a:
                    835:                reg = 0x5b; shift = 0;
                    836:                break;
                    837:        case 0xb8:
                    838:                reg = 0x5b; shift = 4;
                    839:                break;
                    840:        case 0xb9:
                    841:                reg = 0x5c; shift = 0;
                    842:                break;
                    843:        case 0xba:
                    844:                reg = 0x5c; shift = 4;
                    845:                break;
                    846:        case 0xbe:
                    847:                reg = 0x9e; shift = 0;
                    848:                break;
                    849:        default:
                    850:                reg = 0;
                    851:                break;
                    852:        }
                    853:
                    854:        data = sc->lm_readreg(sc, sc->lm_sensors[n].reg);
                    855:        if (data == 0xff || data == 0x00) {
                    856:                sensor->flags |= SENSOR_FINVALID;
                    857:                sensor->value = 0;
                    858:        } else {
                    859:                if (reg != 0)
                    860:                        divisor = (sc->lm_readreg(sc, reg) >> shift) & 0x7;
                    861:                sensor->flags &= ~SENSOR_FINVALID;
                    862:                sensor->value = 1350000 / (data << divisor);
                    863:        }
                    864: }
                    865:
                    866: void
                    867: as_refresh_temp(struct lm_softc *sc, int n)
                    868: {
                    869:        struct ksensor *sensor = &sc->sensors[n];
                    870:        int sdata;
                    871:
                    872:        /*
                    873:         * It seems a shorted temperature diode produces an all-ones
                    874:         * bit pattern.
                    875:         */
                    876:        sdata = sc->lm_readreg(sc, sc->lm_sensors[n].reg) << 1;
                    877:        sdata += sc->lm_readreg(sc, sc->lm_sensors[n].reg + 1) >> 7;
                    878:        if (sdata == 0x1ff) {
                    879:                sensor->flags |= SENSOR_FINVALID;
                    880:                sensor->value = 0;
                    881:        } else {
                    882:                if (sdata & 0x100)
                    883:                        sdata -= 0x200;
                    884:                sensor->flags &= ~SENSOR_FINVALID;
                    885:                sensor->value = sdata * 500000 + 273150000;
                    886:        }
                    887: }

CVSweb