[PATCH] fanctl: AsiaBSDCon 2010 DragonFly sysctl hw.sensors lm(4) fan control similar to BSDCan 2009 OpenBSD
Constantine A. Murenin
cnst+dfly at bugmail.mojo.ru
Fri Mar 12 00:21:14 PST 2010
* This is a ported version of the sysctl hw.sensors lm(4)
fan-controlling prototype/hack as posted to the tech at openbsd.org
mailing list on 2009-05-08.
* DragonFly functionality regarding all aspects of fan control
is the same as discussed for OpenBSD.
* Details were presented at BSDCan 2009 and AsiaBSDCon 2010.
* Presentation and other materials are available at
http://sensors.cnst.su/fanctl/
---
sys/sys/sensors.h | 11 +
sys/kern/kern_sensors.c | 14 +-
sbin/sysctl/sysctl.c | 8 +
sys/dev/powermng/lm/lm78var.h | 2 +-
sys/dev/powermng/lm/lm78.c | 753 +++++++++++++++++++++++++++++++++++++++--
5 files changed, 761 insertions(+), 27 deletions(-)
diff --git a/sys/sys/sensors.h b/sys/sys/sensors.h
index 554cfc2..ca1e46d 100644
--- a/sys/sys/sensors.h
+++ b/sys/sys/sensors.h
@@ -97,18 +97,28 @@ enum sensor_status {
struct sensor {
char desc[32]; /* sensor description, may be empty */
struct timeval tv; /* sensor value last change time */
int64_t value; /* current value */
enum sensor_type type; /* sensor type */
enum sensor_status status; /* sensor status */
int numt; /* sensor number of .type type */
int flags; /* sensor flags */
+ /*int64_t upvalue;*/ /* new value */
+ /*
+ * The upvalue is commented out from the userland structure
+ * to avoid increasing sizeof(struct sensor), such as to
+ * preserve the ABI of C/C++ sysctl(3) HW_SENSORS users,
+ * since otherwise recompilation of all sensor tools would
+ * have been required to avoid [ENOMEM] from sysctl(3).
+ */
#define SENSOR_FINVALID 0x0001 /* sensor is invalid */
#define SENSOR_FUNKNOWN 0x0002 /* sensor value is unknown */
+#define SENSOR_FCONTROLLABLE 0x0004 /* sensor value could be altered */
+#define SENSOR_FNEWVALUE 0x0008 /* upvalue contains update inf. */
};
/* Sensor device data:
* New fields should be added at the end to encourage backwards compat
*/
struct sensordev {
int num; /* sensordev number */
char xname[16]; /* unix device name */
@@ -129,16 +139,17 @@ struct ksensor {
SLIST_ENTRY(ksensor) list; /* device-scope list */
char desc[32]; /* sensor description, may be empty */
struct timeval tv; /* sensor value last change time */
int64_t value; /* current value */
enum sensor_type type; /* sensor type */
enum sensor_status status; /* sensor status */
int numt; /* sensor number of .type type */
int flags; /* sensor flags, ie. SENSOR_FINVALID */
+ int64_t upvalue; /* new value */
};
SLIST_HEAD(ksensors_head, ksensor);
/* Sensor device data */
struct ksensordev {
SLIST_ENTRY(ksensordev) list;
int num; /* sensordev number */
char xname[16]; /* unix device name */
diff --git a/sys/kern/kern_sensors.c b/sys/kern/kern_sensors.c
index b8794a1..8cb6c7a 100644
--- a/sys/kern/kern_sensors.c
+++ b/sys/kern/kern_sensors.c
@@ -317,17 +317,18 @@ sensor_sysctl8magic_install(struct ksensordev *sensdev)
sysctl_ctx_init(cl);
ol = SYSCTL_CHILDREN(SYSCTL_ADD_NODE(cl, (&SYSCTL_NODE_CHILDREN(_hw,
sensors)), sensdev->num, sensdev->xname, CTLFLAG_RD, NULL, ""));
SLIST_FOREACH(s, sh, list) {
char n[32];
ksnprintf(n, sizeof(n), "%s%d", sensor_type_s[s->type], s->numt);
SYSCTL_ADD_PROC(cl, ol, OID_AUTO, n, CTLTYPE_STRUCT |
- CTLFLAG_RD, s, 0, sysctl_handle_sensor, "S,sensor", "");
+ (s->flags & SENSOR_FCONTROLLABLE ? CTLFLAG_RW : CTLFLAG_RD),
+ s, 0, sysctl_handle_sensor, "S,sensor", "");
}
}
void
sensor_sysctl8magic_deinstall(struct ksensordev *sensdev)
{
struct sysctl_ctx_list *cl = &sensdev->clist;
@@ -363,28 +364,35 @@ sysctl_handle_sensordev(SYSCTL_HANDLER_ARGS)
int
sysctl_handle_sensor(SYSCTL_HANDLER_ARGS)
{
struct ksensor *ks = arg1;
struct sensor *us;
int error;
- if (req->newptr)
- return (EPERM);
+ if (req->newptr) {
+ if (req->newlen != sizeof(int))
+ return EINVAL;
+ if (!(ks->flags & SENSOR_FCONTROLLABLE))
+ return EPERM;
+ ks->upvalue = *(int *)req->newptr;
+ ks->flags |= SENSOR_FNEWVALUE;
+ }
/* Grab a copy, to clear the kernel pointers */
us = kmalloc(sizeof(*us), M_TEMP, M_WAITOK | M_ZERO);
memcpy(us->desc, ks->desc, sizeof(ks->desc));
us->tv = ks->tv;
us->value = ks->value;
us->type = ks->type;
us->status = ks->status;
us->numt = ks->numt;
us->flags = ks->flags;
+ /*us->upvalue = ks->upvalue;*/
error = SYSCTL_OUT(req, us, sizeof(struct sensor));
kfree(us, M_TEMP);
return (error);
}
int
diff --git a/sbin/sysctl/sysctl.c b/sbin/sysctl/sysctl.c
index f26613f..18e82f5 100644
--- a/sbin/sysctl/sysctl.c
+++ b/sbin/sysctl/sysctl.c
@@ -245,16 +245,21 @@ parse(const char *string)
break;
case CTLTYPE_OPAQUE:
if (strcmp(fmt, "T,dev_t") == 0 ||
strcmp(fmt, "T,udev_t") == 0
) {
set_T_dev_t((char*)newval, &newval,
&newsize);
break;
+ } else if (strcmp(fmt, "S,sensor") == 0) {
+ intval = (int)strtol(newval, NULL, 0);
+ newval = &intval;
+ newsize = sizeof(intval);
+ break;
}
/* FALLTHROUGH */
default:
errx(1, "oid '%s' is type %d,"
" cannot set that", name,
kind & CTLTYPE);
}
@@ -459,16 +464,19 @@ S_sensor(int l2, void *p)
case SENSOR_TIMEDELTA:
printf("%.6f secs", s->value / 1000000000.0);
break;
default:
printf("unknown");
}
}
+ if (s->flags & SENSOR_FNEWVALUE)
+ printf(" {updating}");
+
if (s->desc[0] != '\0')
printf(" (%s)", s->desc);
switch (s->status) {
case SENSOR_S_UNSPEC:
break;
case SENSOR_S_OK:
printf(", OK");
diff --git a/sys/dev/powermng/lm/lm78var.h b/sys/dev/powermng/lm/lm78var.h
index 67438ee..648feca 100644
--- a/sys/dev/powermng/lm/lm78var.h
+++ b/sys/dev/powermng/lm/lm78var.h
@@ -118,17 +118,17 @@
/* Config bits */
#define WB_CONFIG_VMR9 0x01
/* Reference voltage (mV) */
#define WB_VREF 3600
#define WB_W83627EHF_VREF 2048
-#define WB_MAX_SENSORS 19
+#define WB_MAX_SENSORS 96
struct lm_softc;
struct lm_sensor {
char *desc;
enum sensor_type type;
u_int8_t bank;
u_int8_t reg;
diff --git a/sys/dev/powermng/lm/lm78.c b/sys/dev/powermng/lm/lm78.c
index af74d9e..dc348ba 100644
--- a/sys/dev/powermng/lm/lm78.c
+++ b/sys/dev/powermng/lm/lm78.c
@@ -1,11 +1,11 @@
/*
* Copyright (c) 2005, 2006 Mark Kettenis
- * Copyright (c) 2006, 2007 Constantine A. Murenin
+ * Copyright (c) 2006, 2007, 2009, 2010 Constantine A. Murenin <cnst>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
@@ -19,16 +19,20 @@
#include <sys/param.h>
#include <sys/systm.h>
#include <sys/bus.h>
#include <sys/sensors.h>
#include "lm78var.h"
+//#define LMFANCTLRAW
+#define LMFANDUTYHINTS
+/* or use `rm lm78.o; env DEBUG="-DLMFANCTLRAW -DLMFANDUTYHINTS" make lm78.o` */
+
#if defined(LMDEBUG)
#define DPRINTF(x) do { printf x; } while (0)
#else
#define DPRINTF(x)
#endif
/*
* LM78-compatible chips can typically measure voltages up to 4.096 V.
@@ -49,16 +53,24 @@ void lm_setup_sensors(struct lm_softc *, struct lm_sensor *);
void lm_refresh(void *);
void lm_refresh_sensor_data(struct lm_softc *);
void lm_refresh_volt(struct lm_softc *, int);
void lm_refresh_temp(struct lm_softc *, int);
void lm_refresh_fanrpm(struct lm_softc *, int);
void wb_refresh_sensor_data(struct lm_softc *);
+void wb_refresh_raw_rw(struct lm_softc *, int);
+void w83627hf_refresh_pwm_rw(struct lm_softc *, int);
+void w83627ehf_refresh_fanvolt_rw(struct lm_softc *, int);
+void w83627ehf_refresh_fanvolt_thermal_rw(struct lm_softc *, int);
+void w83627ehf_refresh_indicator_rw(struct lm_softc *, int);
+void w83627ehf_refresh_temptarget_rw(struct lm_softc *, int);
+void w83627ehf_refresh_temptargettol_rw(struct lm_softc *, int);
+void w83627thf_refresh_fanvolt_rw(struct lm_softc *, int);
void wb_w83637hf_refresh_vcore(struct lm_softc *, int);
void wb_refresh_nvolt(struct lm_softc *, int);
void wb_w83627ehf_refresh_nvolt(struct lm_softc *, int);
void wb_refresh_temp(struct lm_softc *, int);
void wb_refresh_fanrpm(struct lm_softc *, int);
void wb_w83792d_refresh_fanrpm(struct lm_softc *, int);
void as_refresh_temp(struct lm_softc *, int);
@@ -89,17 +101,23 @@ struct lm_sensor lm78_sensors[] = {
/* Fans */
{ "", SENSOR_FANRPM, 0, 0x28, lm_refresh_fanrpm },
{ "", SENSOR_FANRPM, 0, 0x29, lm_refresh_fanrpm },
{ "", SENSOR_FANRPM, 0, 0x2a, lm_refresh_fanrpm },
{ NULL }
};
+
struct lm_sensor w83627hf_sensors[] = {
+ /* The W83627HG only support the manual PWM fan speed control. */
+ { "PWM", SENSOR_PERCENT, 0, 0x5a, w83627hf_refresh_pwm_rw },
+ { "PWM", SENSOR_PERCENT, 0, 0x5b, w83627hf_refresh_pwm_rw },
+ { "PWM 0/1 Clock Freq", SENSOR_INTEGER, 0, 0x5c, wb_refresh_raw_rw },
+
/* Voltage */
{ "VCore A", SENSOR_VOLTS_DC, 0, 0x20, lm_refresh_volt, RFACT_NONE },
{ "VCore B", SENSOR_VOLTS_DC, 0, 0x21, lm_refresh_volt, RFACT_NONE },
{ "+3.3V", SENSOR_VOLTS_DC, 0, 0x22, lm_refresh_volt, RFACT_NONE },
{ "+5V", SENSOR_VOLTS_DC, 0, 0x23, lm_refresh_volt, RFACT(34, 50) },
{ "+12V", SENSOR_VOLTS_DC, 0, 0x24, lm_refresh_volt, RFACT(28, 10) },
{ "-12V", SENSOR_VOLTS_DC, 0, 0x25, wb_refresh_nvolt, RFACT(232, 56) },
{ "-5V", SENSOR_VOLTS_DC, 0, 0x26, wb_refresh_nvolt, RFACT(120, 56) },
@@ -122,93 +140,342 @@ struct lm_sensor w83627hf_sensors[] = {
/*
* The W83627EHF can measure voltages up to 2.048 V instead of the
* traditional 4.096 V. For measuring positive voltages, this can be
* accounted for by halving the resistor factor. Negative voltages
* need special treatment, also because the reference voltage is 2.048 V
* instead of the traditional 3.6 V.
*/
struct lm_sensor w83627ehf_sensors[] = {
+ /* Controlling parts: Duty Cycle */
+ { "Sys Fan Volt Control", SENSOR_PERCENT, 0, 0x01, w83627ehf_refresh_fanvolt_rw },
+ { "CPU Fan Volt Control", SENSOR_PERCENT, 0, 0x03, w83627ehf_refresh_fanvolt_rw },
+ { "Aux Fan Volt Control", SENSOR_PERCENT, 0, 0x11, w83627ehf_refresh_fanvolt_rw },
+ { "CPU Fan Volt Control", SENSOR_PERCENT, 0, 0x61, w83627ehf_refresh_fanvolt_rw },
+ /* Start-up Values */
+ { "Sys Fan Start-up Value", SENSOR_PERCENT, 0, 0x0a, w83627ehf_refresh_fanvolt_thermal_rw, 0 },
+ { "CPU Fan Start-up Value", SENSOR_PERCENT, 0, 0x0b, w83627ehf_refresh_fanvolt_thermal_rw, 0 },
+ { "Aux Fan Start-up Value", SENSOR_PERCENT, 0, 0x16, w83627ehf_refresh_fanvolt_thermal_rw, 0 },
+ { "CPU Fan Start-up Value", SENSOR_PERCENT, 0, 0x65, w83627ehf_refresh_fanvolt_thermal_rw, 0 },
+ /* Stop Values */
+ { "Sys Fan Stop Value", SENSOR_PERCENT, 0, 0x08, w83627ehf_refresh_fanvolt_thermal_rw, 1 },
+ { "CPU Fan Stop Value", SENSOR_PERCENT, 0, 0x09, w83627ehf_refresh_fanvolt_thermal_rw, 1 },
+ { "Aux Fan Stop Value", SENSOR_PERCENT, 0, 0x15, w83627ehf_refresh_fanvolt_thermal_rw, 1 },
+ { "CPU Fan Stop Value", SENSOR_PERCENT, 0, 0x64, w83627ehf_refresh_fanvolt_thermal_rw, 1 },
+
+ /* Controlling parts: PWM/DC */
+ { "Sys Fan Volt Control", SENSOR_INDICATOR, 0, 0x01, w83627ehf_refresh_indicator_rw },
+ { "CPU Fan Volt Control", SENSOR_INDICATOR, 0, 0x03, w83627ehf_refresh_indicator_rw },
+ { "Aux Fan Volt Control", SENSOR_INDICATOR, 0, 0x11, w83627ehf_refresh_indicator_rw },
+ { "CPU Fan Volt Control", SENSOR_INDICATOR, 0, 0x61, w83627ehf_refresh_indicator_rw },
+
+#ifdef LMFANCTLRAW
+ /* Smart Fan Configuration Registers, 00h--1Fh */
+ { "0x00: SysFanOut PWM Output Freq", SENSOR_INTEGER, 0, 0x00, wb_refresh_raw_rw },
+ { "0x01: SysFanOut", SENSOR_INTEGER, 0, 0x01, wb_refresh_raw_rw },
+ { "0x02: CPUFanOut0 PWM Output Freq", SENSOR_INTEGER, 0, 0x02, wb_refresh_raw_rw },
+ { "0x03: CPUFanOut0", SENSOR_INTEGER, 0, 0x03, wb_refresh_raw_rw },
+ { "0x04: Fan Configuration Reg I", SENSOR_INTEGER, 0, 0x04, wb_refresh_raw_rw },
+ { "0x05: Sys Target Temp/RPM", SENSOR_INTEGER, 0, 0x05, wb_refresh_raw_rw },
+ { "0x06: CPU Target Temp/RPM0", SENSOR_INTEGER, 0, 0x06, wb_refresh_raw_rw },
+ { "0x07: Sys/CPU Target Tolerance", SENSOR_INTEGER, 0, 0x07, wb_refresh_raw_rw },
+ { "0x08: SysFanOut Stop Value", SENSOR_INTEGER, 0, 0x08, wb_refresh_raw_rw },
+ { "0x09: CPUFanOut0 Stop Value", SENSOR_INTEGER, 0, 0x09, wb_refresh_raw_rw },
+ { "0x0a: SysFanOut Start-up Value", SENSOR_INTEGER, 0, 0x0a, wb_refresh_raw_rw },
+ { "0x0b: CPUFanOut0 Start-up Value", SENSOR_INTEGER, 0, 0x0b, wb_refresh_raw_rw },
+ { "0x0c: SysFanOut Stop Time", SENSOR_INTEGER, 0, 0x0c, wb_refresh_raw_rw },
+ { "0x0d: CPUFanOut0 Stop Time", SENSOR_INTEGER, 0, 0x0d, wb_refresh_raw_rw },
+ { "0x0e: Fan Output Step-down Time", SENSOR_INTEGER, 0, 0x0e, wb_refresh_raw_rw },
+ { "0x0f: Fan Output Step-up Time", SENSOR_INTEGER, 0, 0x0f, wb_refresh_raw_rw },
+ { "0x10: AuxFanOut PWM Output Freq", SENSOR_INTEGER, 0, 0x10, wb_refresh_raw_rw },
+ { "0x11: AuxFanOut", SENSOR_INTEGER, 0, 0x11, wb_refresh_raw_rw },
+ { "0x12: Fan Configuration Reg II", SENSOR_INTEGER, 0, 0x12, wb_refresh_raw_rw },
+ { "0x13: Aux Target Temp/RPM", SENSOR_INTEGER, 0, 0x13, wb_refresh_raw_rw },
+ { "0x14: Aux Target Tolerance", SENSOR_INTEGER, 0, 0x14, wb_refresh_raw_rw },
+ { "0x15: AuxFanOut Stop Value", SENSOR_INTEGER, 0, 0x15, wb_refresh_raw_rw },
+ { "0x16: AuxFanOut Start-up Value", SENSOR_INTEGER, 0, 0x16, wb_refresh_raw_rw },
+ { "0x17: AuxFanOut Stop Time", SENSOR_INTEGER, 0, 0x17, wb_refresh_raw_rw },
+ { "0x18: OVT", SENSOR_INTEGER, 0, 0x18, wb_refresh_raw_rw },
+ { "0x19: reserved", SENSOR_INTEGER, 0, 0x19, wb_refresh_raw_rw },
+ { "0x1a: reserved", SENSOR_INTEGER, 0, 0x1a, wb_refresh_raw_rw },
+ { "0x1b: reserved", SENSOR_INTEGER, 0, 0x1b, wb_refresh_raw_rw },
+ { "0x1c: reserved", SENSOR_INTEGER, 0, 0x1c, wb_refresh_raw_rw },
+ { "0x1d: reserved", SENSOR_INTEGER, 0, 0x1d, wb_refresh_raw_rw },
+ { "0x1e: reserved", SENSOR_INTEGER, 0, 0x1e, wb_refresh_raw_rw },
+ { "0x1f: reserved", SENSOR_INTEGER, 0, 0x1f, wb_refresh_raw_rw },
+
+ { "0x47: Fan Divisor Reg I", SENSOR_INTEGER, 0, 0x47, wb_refresh_raw_rw },
+ { "0x4a: CPUFanOut1 Temp Source Select", SENSOR_INTEGER, 0, 0x4a, wb_refresh_raw_rw },
+ { "0x4b: Fan Divisor Reg II", SENSOR_INTEGER, 0, 0x4b, wb_refresh_raw_rw },
+ { "0x59: Diode Selection", SENSOR_INTEGER, 0, 0x59, wb_refresh_raw_rw },
+ { "0x5d: VBat Monitor Control", SENSOR_INTEGER, 0, 0x5d, wb_refresh_raw_rw },
+
+ { "0x60: CPUFanOut1 PWM Output Freq", SENSOR_INTEGER, 0, 0x60, wb_refresh_raw_rw },
+ { "0x61: CPUFanOut1", SENSOR_INTEGER, 0, 0x61, wb_refresh_raw_rw },
+ { "0x62: Fan Configuration Reg III", SENSOR_INTEGER, 0, 0x62, wb_refresh_raw_rw },
+ { "0x63: CPU Target Temp/RPM1", SENSOR_INTEGER, 0, 0x63, wb_refresh_raw_rw },
+ { "0x64: CPUFanOut1 Stop Value", SENSOR_INTEGER, 0, 0x64, wb_refresh_raw_rw },
+ { "0x65: CPUFanOut1 Start-up Value", SENSOR_INTEGER, 0, 0x65, wb_refresh_raw_rw },
+ { "0x66: CPUFanOut1 Stop Time", SENSOR_INTEGER, 0, 0x66, wb_refresh_raw_rw },
+ { "0x67: CPUFanOut0 Max Output Value", SENSOR_INTEGER, 0, 0x67, wb_refresh_raw_rw },
+ { "0x68: CPUFanOut0 Output Step Value", SENSOR_INTEGER, 0, 0x68, wb_refresh_raw_rw },
+ { "0x69: CPUFanOut1 Max Output Value", SENSOR_INTEGER, 0, 0x69, wb_refresh_raw_rw },
+ { "0x6a: CPUFanOut1 Output Step Value", SENSOR_INTEGER, 0, 0x6a, wb_refresh_raw_rw },
+#endif /* LMFANCTLRAW */
+
/* Voltage */
{ "VCore", SENSOR_VOLTS_DC, 0, 0x20, lm_refresh_volt, RFACT_NONE / 2},
{ "+12V", SENSOR_VOLTS_DC, 0, 0x21, lm_refresh_volt, RFACT(56, 10) / 2 },
{ "+3.3V", SENSOR_VOLTS_DC, 0, 0x22, lm_refresh_volt, RFACT(34, 34) / 2 },
{ "+3.3V", SENSOR_VOLTS_DC, 0, 0x23, lm_refresh_volt, RFACT(34, 34) / 2 },
{ "-12V", SENSOR_VOLTS_DC, 0, 0x24, wb_w83627ehf_refresh_nvolt },
{ "", SENSOR_VOLTS_DC, 0, 0x25, lm_refresh_volt, RFACT_NONE / 2 },
{ "", SENSOR_VOLTS_DC, 0, 0x26, lm_refresh_volt, RFACT_NONE / 2 },
{ "3.3VSB", SENSOR_VOLTS_DC, 5, 0x50, lm_refresh_volt, RFACT(34, 34) / 2 },
{ "VBAT", SENSOR_VOLTS_DC, 5, 0x51, lm_refresh_volt, RFACT_NONE / 2 },
{ "", SENSOR_VOLTS_DC, 5, 0x52, lm_refresh_volt, RFACT_NONE / 2 },
/* Temperature */
- { "", SENSOR_TEMP, 0, 0x27, lm_refresh_temp },
- { "", SENSOR_TEMP, 1, 0x50, wb_refresh_temp },
- { "", SENSOR_TEMP, 2, 0x50, wb_refresh_temp },
+ { "Sys", SENSOR_TEMP, 0, 0x27, lm_refresh_temp },
+ { "CPU", SENSOR_TEMP, 1, 0x50, wb_refresh_temp },
+ { "Aux", SENSOR_TEMP, 2, 0x50, wb_refresh_temp },
+
+ /* search for Relative Registers in the datasheet for a nice table */
+ /* Controlling parts: Target Temperature */
+ { "Sys Target", SENSOR_TEMP, 0, 0x05, w83627ehf_refresh_temptarget_rw },
+ { "CPU Target", SENSOR_TEMP, 0, 0x06, w83627ehf_refresh_temptarget_rw },
+ { "Aux Target", SENSOR_TEMP, 0, 0x13, w83627ehf_refresh_temptarget_rw },
+ { "CPU Target", SENSOR_TEMP, 0, 0x63, w83627ehf_refresh_temptarget_rw },
+ /* Controlling parts: Target Temperature Tolerance */
+ { "Sys Tolerance", SENSOR_TEMP, 0, 0x05, w83627ehf_refresh_temptargettol_rw },
+ { "CPU Tolerance", SENSOR_TEMP, 0, 0x06, w83627ehf_refresh_temptargettol_rw },
+ { "Aux Tolerance", SENSOR_TEMP, 0, 0x13, w83627ehf_refresh_temptargettol_rw },
+ { "CPU Tolerance", SENSOR_TEMP, 0, 0x63, w83627ehf_refresh_temptargettol_rw },
/* Fans */
- { "", SENSOR_FANRPM, 0, 0x28, wb_refresh_fanrpm },
- { "", SENSOR_FANRPM, 0, 0x29, wb_refresh_fanrpm },
- { "", SENSOR_FANRPM, 0, 0x2a, wb_refresh_fanrpm },
+ { "Sys", SENSOR_FANRPM, 0, 0x28, wb_refresh_fanrpm },
+ { "CPU", SENSOR_FANRPM, 0, 0x29, wb_refresh_fanrpm },
+ { "Aux", SENSOR_FANRPM, 0, 0x2a, wb_refresh_fanrpm },
+/* { "CPU", SENSOR_FANRPM, 0, 0x3f, w83627ehf_refresh_fanrpm },
+ { "Aux", SENSOR_FANRPM, 0, 0x53, w83627ehf_refresh_fanrpm },*/
{ NULL }
};
/*
* w83627dhg is almost identical to w83627ehf, except that
* it has 9 instead of 10 voltage sensors
*/
struct lm_sensor w83627dhg_sensors[] = {
+ /* Controlling parts: Duty Cycle */
+ { "Sys Fan Volt Control", SENSOR_PERCENT, 0, 0x01, w83627ehf_refresh_fanvolt_rw },
+ { "CPU Fan Volt Control", SENSOR_PERCENT, 0, 0x03, w83627ehf_refresh_fanvolt_rw },
+ { "Aux Fan Volt Control", SENSOR_PERCENT, 0, 0x11, w83627ehf_refresh_fanvolt_rw },
+ { "CPU Fan Volt Control", SENSOR_PERCENT, 0, 0x61, w83627ehf_refresh_fanvolt_rw },
+ /* Start-up Values */
+ { "Sys Fan Start-up Value", SENSOR_PERCENT, 0, 0x0a, w83627ehf_refresh_fanvolt_thermal_rw, 0 },
+ { "CPU Fan Start-up Value", SENSOR_PERCENT, 0, 0x0b, w83627ehf_refresh_fanvolt_thermal_rw, 0 },
+ { "Aux Fan Start-up Value", SENSOR_PERCENT, 0, 0x16, w83627ehf_refresh_fanvolt_thermal_rw, 0 },
+ { "CPU Fan Start-up Value", SENSOR_PERCENT, 0, 0x65, w83627ehf_refresh_fanvolt_thermal_rw, 0 },
+ /* Stop Values */
+ { "Sys Fan Stop Value", SENSOR_PERCENT, 0, 0x08, w83627ehf_refresh_fanvolt_thermal_rw, 1 },
+ { "CPU Fan Stop Value", SENSOR_PERCENT, 0, 0x09, w83627ehf_refresh_fanvolt_thermal_rw, 1 },
+ { "Aux Fan Stop Value", SENSOR_PERCENT, 0, 0x15, w83627ehf_refresh_fanvolt_thermal_rw, 1 },
+ { "CPU Fan Stop Value", SENSOR_PERCENT, 0, 0x64, w83627ehf_refresh_fanvolt_thermal_rw, 1 },
+
+ /* Controlling parts: PWM/DC */
+ { "Sys Fan Volt Control", SENSOR_INDICATOR, 0, 0x01, w83627ehf_refresh_indicator_rw },
+ { "CPU Fan Volt Control", SENSOR_INDICATOR, 0, 0x03, w83627ehf_refresh_indicator_rw },
+ { "Aux Fan Volt Control", SENSOR_INDICATOR, 0, 0x11, w83627ehf_refresh_indicator_rw },
+ { "CPU Fan Volt Control", SENSOR_INDICATOR, 0, 0x61, w83627ehf_refresh_indicator_rw },
+
+#ifdef LMFANCTLRAW
+ /* Smart Fan Configuration Registers, 00h--1Fh */
+ { "0x00: SysFanOut PWM Output Freq", SENSOR_INTEGER, 0, 0x00, wb_refresh_raw_rw },
+ { "0x01: SysFanOut", SENSOR_INTEGER, 0, 0x01, wb_refresh_raw_rw },
+ { "0x02: CPUFanOut0 PWM Output Freq", SENSOR_INTEGER, 0, 0x02, wb_refresh_raw_rw },
+ { "0x03: CPUFanOut0", SENSOR_INTEGER, 0, 0x03, wb_refresh_raw_rw },
+ { "0x04: Fan Configuration Reg I", SENSOR_INTEGER, 0, 0x04, wb_refresh_raw_rw },
+ { "0x05: Sys Target Temp/RPM", SENSOR_INTEGER, 0, 0x05, wb_refresh_raw_rw },
+ { "0x06: CPU Target Temp/RPM0", SENSOR_INTEGER, 0, 0x06, wb_refresh_raw_rw },
+ { "0x07: Sys/CPU Target Tolerance", SENSOR_INTEGER, 0, 0x07, wb_refresh_raw_rw },
+ { "0x08: SysFanOut Stop Value", SENSOR_INTEGER, 0, 0x08, wb_refresh_raw_rw },
+ { "0x09: CPUFanOut0 Stop Value", SENSOR_INTEGER, 0, 0x09, wb_refresh_raw_rw },
+ { "0x0a: SysFanOut Start-up Value", SENSOR_INTEGER, 0, 0x0a, wb_refresh_raw_rw },
+ { "0x0b: CPUFanOut0 Start-up Value", SENSOR_INTEGER, 0, 0x0b, wb_refresh_raw_rw },
+ { "0x0c: SysFanOut Stop Time", SENSOR_INTEGER, 0, 0x0c, wb_refresh_raw_rw },
+ { "0x0d: CPUFanOut0 Stop Time", SENSOR_INTEGER, 0, 0x0d, wb_refresh_raw_rw },
+ { "0x0e: Fan Output Step-down Time", SENSOR_INTEGER, 0, 0x0e, wb_refresh_raw_rw },
+ { "0x0f: Fan Output Step-up Time", SENSOR_INTEGER, 0, 0x0f, wb_refresh_raw_rw },
+ { "0x10: AuxFanOut PWM Output Freq", SENSOR_INTEGER, 0, 0x10, wb_refresh_raw_rw },
+ { "0x11: AuxFanOut", SENSOR_INTEGER, 0, 0x11, wb_refresh_raw_rw },
+ { "0x12: Fan Configuration Reg II", SENSOR_INTEGER, 0, 0x12, wb_refresh_raw_rw },
+ { "0x13: Aux Target Temp/RPM", SENSOR_INTEGER, 0, 0x13, wb_refresh_raw_rw },
+ { "0x14: Aux Target Tolerance", SENSOR_INTEGER, 0, 0x14, wb_refresh_raw_rw },
+ { "0x15: AuxFanOut Stop Value", SENSOR_INTEGER, 0, 0x15, wb_refresh_raw_rw },
+ { "0x16: AuxFanOut Start-up Value", SENSOR_INTEGER, 0, 0x16, wb_refresh_raw_rw },
+ { "0x17: AuxFanOut Stop Time", SENSOR_INTEGER, 0, 0x17, wb_refresh_raw_rw },
+ { "0x18: OVT", SENSOR_INTEGER, 0, 0x18, wb_refresh_raw_rw },
+ { "0x19: reserved", SENSOR_INTEGER, 0, 0x19, wb_refresh_raw_rw },
+ { "0x1a: reserved", SENSOR_INTEGER, 0, 0x1a, wb_refresh_raw_rw },
+ { "0x1b: reserved", SENSOR_INTEGER, 0, 0x1b, wb_refresh_raw_rw },
+ { "0x1c: reserved", SENSOR_INTEGER, 0, 0x1c, wb_refresh_raw_rw },
+ { "0x1d: reserved", SENSOR_INTEGER, 0, 0x1d, wb_refresh_raw_rw },
+ { "0x1e: reserved", SENSOR_INTEGER, 0, 0x1e, wb_refresh_raw_rw },
+ { "0x1f: reserved", SENSOR_INTEGER, 0, 0x1f, wb_refresh_raw_rw },
+
+ { "0x47: Fan Divisor Reg I", SENSOR_INTEGER, 0, 0x47, wb_refresh_raw_rw },
+ { "0x49: CPUFanOut0/Aux Temp Source Select", SENSOR_INTEGER, 0, 0x49, wb_refresh_raw_rw }, /*dhg only, not on ehf*/
+ { "0x4a: CPUFanOut1 Temp Source Select", SENSOR_INTEGER, 0, 0x4a, wb_refresh_raw_rw },
+ { "0x4b: Fan Divisor Reg II", SENSOR_INTEGER, 0, 0x4b, wb_refresh_raw_rw },
+ { "0x59: Diode Selection", SENSOR_INTEGER, 0, 0x59, wb_refresh_raw_rw },
+ { "0x5d: VBat Monitor Control", SENSOR_INTEGER, 0, 0x5d, wb_refresh_raw_rw },
+
+ { "0x60: CPUFanOut1 PWM Output Freq", SENSOR_INTEGER, 0, 0x60, wb_refresh_raw_rw },
+ { "0x61: CPUFanOut1", SENSOR_INTEGER, 0, 0x61, wb_refresh_raw_rw },
+ { "0x62: Fan Configuration Reg III", SENSOR_INTEGER, 0, 0x62, wb_refresh_raw_rw },
+ { "0x63: CPU Target Temp/RPM1", SENSOR_INTEGER, 0, 0x63, wb_refresh_raw_rw },
+ { "0x64: CPUFanOut1 Stop Value", SENSOR_INTEGER, 0, 0x64, wb_refresh_raw_rw },
+ { "0x65: CPUFanOut1 Start-up Value", SENSOR_INTEGER, 0, 0x65, wb_refresh_raw_rw },
+ { "0x66: CPUFanOut1 Stop Time", SENSOR_INTEGER, 0, 0x66, wb_refresh_raw_rw },
+ { "0x67: CPUFanOut0 Max Output Value", SENSOR_INTEGER, 0, 0x67, wb_refresh_raw_rw },
+ { "0x68: CPUFanOut0 Output Step Value", SENSOR_INTEGER, 0, 0x68, wb_refresh_raw_rw },
+ { "0x69: CPUFanOut1 Max Output Value", SENSOR_INTEGER, 0, 0x69, wb_refresh_raw_rw },
+ { "0x6a: CPUFanOut1 Output Step Value", SENSOR_INTEGER, 0, 0x6a, wb_refresh_raw_rw },
+#endif /* LMFANCTLRAW */
+
/* Voltage */
{ "VCore", SENSOR_VOLTS_DC, 0, 0x20, lm_refresh_volt, RFACT_NONE / 2},
{ "+12V", SENSOR_VOLTS_DC, 0, 0x21, lm_refresh_volt, RFACT(56, 10) / 2 },
{ "+3.3V", SENSOR_VOLTS_DC, 0, 0x22, lm_refresh_volt, RFACT(34, 34) / 2 },
{ "+3.3V", SENSOR_VOLTS_DC, 0, 0x23, lm_refresh_volt, RFACT(34, 34) / 2 },
{ "-12V", SENSOR_VOLTS_DC, 0, 0x24, wb_w83627ehf_refresh_nvolt },
{ "", SENSOR_VOLTS_DC, 0, 0x25, lm_refresh_volt, RFACT_NONE / 2 },
{ "", SENSOR_VOLTS_DC, 0, 0x26, lm_refresh_volt, RFACT_NONE / 2 },
{ "3.3VSB", SENSOR_VOLTS_DC, 5, 0x50, lm_refresh_volt, RFACT(34, 34) / 2 },
{ "VBAT", SENSOR_VOLTS_DC, 5, 0x51, lm_refresh_volt, RFACT_NONE / 2 },
/* Temperature */
- { "", SENSOR_TEMP, 0, 0x27, lm_refresh_temp },
- { "", SENSOR_TEMP, 1, 0x50, wb_refresh_temp },
- { "", SENSOR_TEMP, 2, 0x50, wb_refresh_temp },
+ { "Sys", SENSOR_TEMP, 0, 0x27, lm_refresh_temp },
+ { "CPU", SENSOR_TEMP, 1, 0x50, wb_refresh_temp },
+ { "Aux", SENSOR_TEMP, 2, 0x50, wb_refresh_temp },
+
+ /* search for Relative Registers in the datasheet for a nice table */
+ /* Controlling parts: Target Temperature */
+ { "Sys Target", SENSOR_TEMP, 0, 0x05, w83627ehf_refresh_temptarget_rw },
+ { "CPU Target", SENSOR_TEMP, 0, 0x06, w83627ehf_refresh_temptarget_rw },
+ { "Aux Target", SENSOR_TEMP, 0, 0x13, w83627ehf_refresh_temptarget_rw },
+ { "CPU Target", SENSOR_TEMP, 0, 0x63, w83627ehf_refresh_temptarget_rw },
+ /* Controlling parts: Target Temperature Tolerance */
+ { "Sys Tolerance", SENSOR_TEMP, 0, 0x05, w83627ehf_refresh_temptargettol_rw },
+ { "CPU Tolerance", SENSOR_TEMP, 0, 0x06, w83627ehf_refresh_temptargettol_rw },
+ { "Aux Tolerance", SENSOR_TEMP, 0, 0x13, w83627ehf_refresh_temptargettol_rw },
+ { "CPU Tolerance", SENSOR_TEMP, 0, 0x63, w83627ehf_refresh_temptargettol_rw },
/* Fans */
- { "", SENSOR_FANRPM, 0, 0x28, wb_refresh_fanrpm },
- { "", SENSOR_FANRPM, 0, 0x29, wb_refresh_fanrpm },
- { "", SENSOR_FANRPM, 0, 0x2a, wb_refresh_fanrpm },
+ { "Sys", SENSOR_FANRPM, 0, 0x28, wb_refresh_fanrpm },
+ { "CPU", SENSOR_FANRPM, 0, 0x29, wb_refresh_fanrpm },
+ { "Aux", SENSOR_FANRPM, 0, 0x2a, wb_refresh_fanrpm },
+/* { "CPU", SENSOR_FANRPM, 0, 0x3f, w83627ehf_refresh_fanrpm },*/
{ NULL }
};
-struct lm_sensor w83637hf_sensors[] = {
+struct lm_sensor w83627thf_sensors[] = {
+ /* Controlling parts: Duty Cycle */
+ { "Sys Fan Volt Control", SENSOR_PERCENT, 0, 0x01, w83627thf_refresh_fanvolt_rw },
+ { "CPU Fan Volt Control", SENSOR_PERCENT, 0, 0x03, w83627thf_refresh_fanvolt_rw },
+ { "Aux Fan Volt Control", SENSOR_PERCENT, 0, 0x11, w83627thf_refresh_fanvolt_rw },
+ /* Start-up Values */
+ { "Sys Fan Start-up Value", SENSOR_PERCENT, 0, 0x0a, w83627ehf_refresh_fanvolt_thermal_rw, 0 },
+ { "CPU Fan Start-up Value", SENSOR_PERCENT, 0, 0x0b, w83627ehf_refresh_fanvolt_thermal_rw, 0 },
+ { "Aux Fan Start-up Value", SENSOR_PERCENT, 0, 0x16, w83627ehf_refresh_fanvolt_thermal_rw, 0 },
+ /* Stop Values */
+ { "Sys Fan Stop Value", SENSOR_PERCENT, 0, 0x08, w83627ehf_refresh_fanvolt_thermal_rw, 1 },
+ { "CPU Fan Stop Value", SENSOR_PERCENT, 0, 0x09, w83627ehf_refresh_fanvolt_thermal_rw, 1 },
+ { "Aux Fan Stop Value", SENSOR_PERCENT, 0, 0x15, w83627ehf_refresh_fanvolt_thermal_rw, 1 },
+
+#ifdef LMFANCTLRAW
+ /* Smart Fan Configuration Registers, 00h--1Fh */
+ { "0x00: reserved", SENSOR_INTEGER, 0, 0x00, wb_refresh_raw_rw },
+ { "0x01: SysFanOut", SENSOR_INTEGER, 0, 0x01, wb_refresh_raw_rw },
+ { "0x02: reserved", SENSOR_INTEGER, 0, 0x02, wb_refresh_raw_rw },
+ { "0x03: CPUFanOut", SENSOR_INTEGER, 0, 0x03, wb_refresh_raw_rw },
+ { "0x04: Fan Conguration Reg I", SENSOR_INTEGER, 0, 0x04, wb_refresh_raw_rw },
+ { "0x05: Sys Target Temp/RPM", SENSOR_INTEGER, 0, 0x05, wb_refresh_raw_rw },
+ { "0x06: CPU Target Temp/RPM", SENSOR_INTEGER, 0, 0x06, wb_refresh_raw_rw },
+ { "0x07: Sys/CPU Target Tolerance", SENSOR_INTEGER, 0, 0x07, wb_refresh_raw_rw },
+ { "0x08: SysFanOut Stop Value", SENSOR_INTEGER, 0, 0x08, wb_refresh_raw_rw },
+ { "0x09: CPUFanOut Stop Value", SENSOR_INTEGER, 0, 0x09, wb_refresh_raw_rw },
+ { "0x0a: SysFanOut Start-up Value", SENSOR_INTEGER, 0, 0x0a, wb_refresh_raw_rw },
+ { "0x0b: CPUFanOut Start-up Value", SENSOR_INTEGER, 0, 0x0b, wb_refresh_raw_rw },
+ { "0x0c: SysFanOut Stop Time", SENSOR_INTEGER, 0, 0x0c, wb_refresh_raw_rw },
+ { "0x0d: CPUFanOut Stop Time", SENSOR_INTEGER, 0, 0x0d, wb_refresh_raw_rw },
+ { "0x0e: Fan Output Step-down Time", SENSOR_INTEGER, 0, 0x0e, wb_refresh_raw_rw },
+ { "0x0f: Fan Output Step-up Time", SENSOR_INTEGER, 0, 0x0f, wb_refresh_raw_rw },
+ { "0x10: reserved", SENSOR_INTEGER, 0, 0x10, wb_refresh_raw_rw },
+ { "0x11: AuxFanOut", SENSOR_INTEGER, 0, 0x11, wb_refresh_raw_rw },
+ { "0x12: Fan Configuration Reg II", SENSOR_INTEGER, 0, 0x12, wb_refresh_raw_rw },
+ { "0x13: Aux Target Temp/RPM", SENSOR_INTEGER, 0, 0x13, wb_refresh_raw_rw },
+ { "0x14: Aux Target Tolerance", SENSOR_INTEGER, 0, 0x14, wb_refresh_raw_rw },
+ { "0x15: AuxFanOut Stop Value", SENSOR_INTEGER, 0, 0x15, wb_refresh_raw_rw },
+ { "0x16: AuxFanOut Start-up Value", SENSOR_INTEGER, 0, 0x16, wb_refresh_raw_rw },
+ { "0x17: AuxFanOut Stop Time", SENSOR_INTEGER, 0, 0x17, wb_refresh_raw_rw },
+ { "0x18: VRM and OVT", SENSOR_INTEGER, 0, 0x18, wb_refresh_raw_rw },
+ { "0x19: reserved", SENSOR_INTEGER, 0, 0x19, wb_refresh_raw_rw },
+ { "0x1a: user-defined", SENSOR_INTEGER, 0, 0x1a, wb_refresh_raw_rw },
+ { "0x1b: user-defined", SENSOR_INTEGER, 0, 0x1b, wb_refresh_raw_rw },
+ { "0x1c: reserved", SENSOR_INTEGER, 0, 0x1c, wb_refresh_raw_rw },
+ { "0x1d: reserved", SENSOR_INTEGER, 0, 0x1d, wb_refresh_raw_rw },
+ { "0x1e: reserved", SENSOR_INTEGER, 0, 0x1e, wb_refresh_raw_rw },
+ { "0x1f: reserved", SENSOR_INTEGER, 0, 0x1f, wb_refresh_raw_rw },
+
+ { "0x47: Fan Divisor Reg I", SENSOR_INTEGER, 0, 0x47, wb_refresh_raw_rw },
+#endif /* LMFANCTLRAW */
+
/* Voltage */
{ "VCore", SENSOR_VOLTS_DC, 0, 0x20, wb_w83637hf_refresh_vcore },
{ "+12V", SENSOR_VOLTS_DC, 0, 0x21, lm_refresh_volt, RFACT(28, 10) },
{ "+3.3V", SENSOR_VOLTS_DC, 0, 0x22, lm_refresh_volt, RFACT_NONE },
{ "+5V", SENSOR_VOLTS_DC, 0, 0x23, lm_refresh_volt, RFACT(34, 51) },
{ "-12V", SENSOR_VOLTS_DC, 0, 0x24, wb_refresh_nvolt, RFACT(232, 56) },
{ "5VSB", SENSOR_VOLTS_DC, 5, 0x50, lm_refresh_volt, RFACT(34, 51) },
{ "VBAT", SENSOR_VOLTS_DC, 5, 0x51, lm_refresh_volt, RFACT_NONE },
/* Temperature */
- { "", SENSOR_TEMP, 0, 0x27, lm_refresh_temp },
- { "", SENSOR_TEMP, 1, 0x50, wb_refresh_temp },
- { "", SENSOR_TEMP, 2, 0x50, wb_refresh_temp },
+ { "Sys", SENSOR_TEMP, 0, 0x27, lm_refresh_temp },
+ { "CPU", SENSOR_TEMP, 1, 0x50, wb_refresh_temp },
+ { "Aux", SENSOR_TEMP, 2, 0x50, wb_refresh_temp },
+
+ /* Controlling parts: Target Temperature */
+ { "Sys Target", SENSOR_TEMP, 0, 0x05, w83627ehf_refresh_temptarget_rw },
+ { "CPU Target", SENSOR_TEMP, 0, 0x06, w83627ehf_refresh_temptarget_rw },
+ { "Aux Target", SENSOR_TEMP, 0, 0x13, w83627ehf_refresh_temptarget_rw },
+ /* Controlling parts: Target Temperature Tolerance */
+ { "Sys Tolerance", SENSOR_TEMP, 0, 0x05, w83627ehf_refresh_temptargettol_rw },
+ { "CPU Tolerance", SENSOR_TEMP, 0, 0x06, w83627ehf_refresh_temptargettol_rw },
+ { "Aux Tolerance", SENSOR_TEMP, 0, 0x13, w83627ehf_refresh_temptargettol_rw },
/* Fans */
- { "", SENSOR_FANRPM, 0, 0x28, wb_refresh_fanrpm },
- { "", SENSOR_FANRPM, 0, 0x29, wb_refresh_fanrpm },
- { "", SENSOR_FANRPM, 0, 0x2a, wb_refresh_fanrpm },
+ { "Sys", SENSOR_FANRPM, 0, 0x28, wb_refresh_fanrpm },
+ { "CPU", SENSOR_FANRPM, 0, 0x29, wb_refresh_fanrpm },
+ { "Aux", SENSOR_FANRPM, 0, 0x2a, wb_refresh_fanrpm },
{ NULL }
};
+/*
+ * With regard to fan control, W83697HF documentation appears to be
+ * contradictory, as section 6.4.2 "Fan speed control" suggests
+ * using CR5A and CR5B, like in W83627HG, for PWM duty cycle,
+ * whereas other sections define these registers differently,
+ * and suggest registers similar to the other chips that implement
+ * the Smart Fan control system.
+ * Support for fan-controlling with this chip might be added later.
+ */
struct lm_sensor w83697hf_sensors[] = {
/* Voltage */
{ "VCore", SENSOR_VOLTS_DC, 0, 0x20, lm_refresh_volt, RFACT_NONE },
{ "+3.3V", SENSOR_VOLTS_DC, 0, 0x22, lm_refresh_volt, RFACT_NONE },
{ "+5V", SENSOR_VOLTS_DC, 0, 0x23, lm_refresh_volt, RFACT(34, 50) },
{ "+12V", SENSOR_VOLTS_DC, 0, 0x24, lm_refresh_volt, RFACT(28, 10) },
{ "-12V", SENSOR_VOLTS_DC, 0, 0x25, wb_refresh_nvolt, RFACT(232, 56) },
{ "-5V", SENSOR_VOLTS_DC, 0, 0x26, wb_refresh_nvolt, RFACT(120, 56) },
@@ -394,17 +661,17 @@ void
lm_attach(struct lm_softc *sc)
{
u_int i, config;
/* No point in doing anything if we don't have any sensors. */
if (sc->numsensors == 0)
return;
- if (sensor_task_register(sc, lm_refresh, 5)) {
+ if (sensor_task_register(sc, lm_refresh, 3)) {
device_printf(sc->sc_dev, "unable to register update task\n");
return;
}
/* Start the monitoring loop */
config = sc->lm_readreg(sc, LM_CONFIG);
sc->lm_writereg(sc, LM_CONFIG, config | 0x01);
@@ -508,33 +775,37 @@ wb_match(struct lm_softc *sc)
DPRINTF((" winbond chip id 0x%x\n", sc->chipid));
switch(sc->chipid) {
case WB_CHIPID_W83627HF:
cdesc = "W83627HF";
lm_setup_sensors(sc, w83627hf_sensors);
break;
case WB_CHIPID_W83627THF:
cdesc = "W83627THF";
- lm_setup_sensors(sc, w83637hf_sensors);
+ sc->lm_writereg(sc, WB_BANKSEL, WB_BANKSEL_B0);
+ if (sc->lm_readreg(sc, WB_BANK0_CONFIG) & WB_CONFIG_VMR9)
+ sc->vrm9 = 1;
+ sc->lm_writereg(sc, WB_BANKSEL, banksel);
+ lm_setup_sensors(sc, w83627thf_sensors);
break;
case WB_CHIPID_W83627EHF:
cdesc = "W83627EHF";
lm_setup_sensors(sc, w83627ehf_sensors);
break;
case WB_CHIPID_W83627DHG:
cdesc = "W83627DHG";
lm_setup_sensors(sc, w83627dhg_sensors);
break;
case WB_CHIPID_W83637HF:
cdesc = "W83637HF";
sc->lm_writereg(sc, WB_BANKSEL, WB_BANKSEL_B0);
if (sc->lm_readreg(sc, WB_BANK0_CONFIG) & WB_CONFIG_VMR9)
sc->vrm9 = 1;
sc->lm_writereg(sc, WB_BANKSEL, banksel);
- lm_setup_sensors(sc, w83637hf_sensors);
+ lm_setup_sensors(sc, w83627thf_sensors);
break;
case WB_CHIPID_W83697HF:
cdesc = "W83697HF";
lm_setup_sensors(sc, w83697hf_sensors);
break;
case WB_CHIPID_W83781D:
case WB_CHIPID_W83781D_2:
cdesc = "W83781D";
@@ -601,16 +872,22 @@ void
lm_setup_sensors(struct lm_softc *sc, struct lm_sensor *sensors)
{
int i;
for (i = 0; sensors[i].desc; i++) {
sc->sensors[i].type = sensors[i].type;
strlcpy(sc->sensors[i].desc, sensors[i].desc,
sizeof(sc->sensors[i].desc));
+ if (sc->sensors[i].type == SENSOR_PERCENT ||
+ sc->sensors[i].type == SENSOR_INDICATOR ||
+ sc->sensors[i].type == SENSOR_INTEGER ||
+ (sc->sensors[i].type == SENSOR_TEMP &&
+ sc->sensors[i].desc[4] != '\0'))
+ sc->sensors[i].flags = SENSOR_FCONTROLLABLE;
sc->numsensors++;
}
sc->lm_sensors = sensors;
}
void
lm_refresh(void *arg)
{
@@ -710,16 +987,446 @@ wb_refresh_sensor_data(struct lm_softc *sc)
sc->lm_writereg(sc, WB_BANKSEL, bank);
}
sc->lm_sensors[i].refresh(sc, i);
}
sc->lm_writereg(sc, WB_BANKSEL, banksel);
}
void
+wb_refresh_raw_rw(struct lm_softc *sc, int n)
+{
+ struct ksensor *sensor = &sc->sensors[n];
+ int nv, data;
+
+ if (sensor->flags & SENSOR_FNEWVALUE) {
+ sensor->flags &= ~SENSOR_FNEWVALUE;
+ nv = sensor->upvalue;
+ if (nv >= 0x00 && nv <= 0xff)
+ sc->lm_writereg(sc, sc->lm_sensors[n].reg, nv);
+ }
+ data = sc->lm_readreg(sc, sc->lm_sensors[n].reg);
+ sensor->value = data;
+}
+
+void
+w83627hf_refresh_pwm_rw(struct lm_softc *sc, int n)
+{
+ struct ksensor *sensor = &sc->sensors[n];
+ int nv, data;
+
+ if (sensor->flags & SENSOR_FNEWVALUE) {
+ sensor->flags &= ~SENSOR_FNEWVALUE;
+ nv = sensor->upvalue;
+ if (nv < 0 || nv > 100)
+ nv = 100; /* ramp it up! */
+ nv = 255 * nv / 100;
+ sc->lm_writereg(sc, sc->lm_sensors[n].reg, nv);
+ }
+ data = sc->lm_readreg(sc, sc->lm_sensors[n].reg);
+ /* 1000 is the factor to convert from percentage to SENSOR_PERCENT */
+ sensor->value = 1000 * 100 * data / 255;
+}
+
+void
+w83627ehf_refresh_fanvolt_rw(struct lm_softc *sc, int n)
+{
+ struct ksensor *sensor = &sc->sensors[n];
+ int nv, data;
+ int confreg, selshift, modeshift, conf, sel, mode;
+ const char* const sels[2] =
+ { "PWM", "DC" };
+ const char* const modes[4] =
+ { "Manual", "Thermal", "Speed", "SmartIII" };
+
+ /* get the right Fan Configuration Register */
+ switch (sc->lm_sensors[n].reg) {
+ case 0x01: /* Sys */
+ confreg = 0x04; selshift = 0; modeshift = 2;
+ break;
+ case 0x03: /* CPU */
+ confreg = 0x04; selshift = 1; modeshift = 4;
+ break;
+ case 0x11: /* Aux */
+ confreg = 0x12; selshift = 0; modeshift = 1;
+ break;
+ case 0x61: /* CPU */
+ confreg = 0x5b; selshift = 6; modeshift = 4;
+ break;
+ default:
+ return;
+ }
+
+ if (sensor->flags & SENSOR_FNEWVALUE) {
+ sensor->flags &= ~SENSOR_FNEWVALUE;
+ nv = sensor->upvalue;
+ if (nv < 0 || nv > 100)
+ nv = 100; /* ramp it up! */
+ nv = 255 * nv / 100;
+ /*
+ * Since we got an explicit request to affect the speed,
+ * we need to go into manual mode first.
+ */
+ conf = sc->lm_readreg(sc, confreg);
+ mode = (conf >> modeshift) & 0x3;
+ if (mode != 0) {
+ conf &= ~(0x3 << modeshift);
+ sc->lm_writereg(sc, confreg, conf);
+ }
+ sc->lm_writereg(sc, sc->lm_sensors[n].reg, nv);
+ }
+
+ /* now populate our struct ksensor */
+
+ conf = sc->lm_readreg(sc, confreg);
+ sel = (conf >> selshift) & 0x1;
+ mode = (conf >> modeshift) & 0x3;
+ ksnprintf(sensor->desc + 8, sizeof(sensor->desc) - 8,
+ "%s %s", sels[sel], modes[mode]);
+
+ /* 1000 is the factor to convert from percentage to SENSOR_PERCENT */
+ sensor->value = 1000 * 100 * data / 255;
+#ifdef LMFANDUTYHINTS
+ if (data > 148)
+ sensor->status = SENSOR_S_OK; /* at least 7V */
+ else if (data > 106)
+ sensor->status = SENSOR_S_WARN; /* at least 5V */
+ else
+ sensor->status = SENSOR_S_CRIT; /* less than 5V */
+#endif /* LMFANDUTYHINTS */
+}
+
+/*
+ * Fan Start-up and Stop Values are only used in Thermal Cruise mode.
+ * The documentation is ambiguous of whether they are used in other
+ * modes, too.
+ */
+void
+w83627ehf_refresh_fanvolt_thermal_rw(struct lm_softc *sc, int n)
+{
+ struct ksensor *sensor = &sc->sensors[n];
+ int nv, data;
+ int confreg, selshift, modeshift, conf, mode, minfanbit, minfan;
+
+ /*
+ * Get the right Fan Configuration Register.
+ * Register 0x12 has the "Keep Min. Fan Output Value" bools indicating
+ * whether the output should or should not go below the stop value.
+ */
+ switch (sc->lm_sensors[n].reg) {
+ case 0x0a:
+ case 0x08:
+ /* Sys */
+ confreg = 0x04; selshift = 0; modeshift = 2;
+ minfanbit = 5;
+ break;
+ case 0x0b:
+ case 0x09:
+ /* CPU */
+ confreg = 0x04; selshift = 1; modeshift = 4;
+ minfanbit = 4;
+ break;
+ case 0x16:
+ case 0x15:
+ /* Aux */
+ confreg = 0x12; selshift = 0; modeshift = 1;
+ minfanbit = 3;
+ break;
+ case 0x65:
+ case 0x64:
+ /* CPU */
+ confreg = 0x5b; selshift = 6; modeshift = 4;
+ minfanbit = 6;
+ break;
+ default:
+ return;
+ }
+
+ if (sensor->flags & SENSOR_FNEWVALUE) {
+ sensor->flags &= ~SENSOR_FNEWVALUE;
+ nv = sensor->upvalue;
+ if (!(nv < 0 || nv > 100)) {
+ if (sc->lm_sensors[n].rfact == 1) {
+ conf = sc->lm_readreg(sc, 0x12);
+ minfan = (conf >> minfanbit) & 0x1;
+ if (minfan != 1) {
+ conf |= (0x1 << minfanbit);
+ sc->lm_writereg(sc, 0x12, conf);
+ }
+ }
+ nv = 255 * nv / 100;
+ sc->lm_writereg(sc, sc->lm_sensors[n].reg, nv);
+ }
+ }
+
+ /* now populate our struct ksensor */
+
+ data = sc->lm_readreg(sc, sc->lm_sensors[n].reg);
+ /* 1000 is the factor to convert from percentage to SENSOR_PERCENT */
+ sensor->value = 1000 * 100 * data / 255;
+
+ conf = sc->lm_readreg(sc, confreg);
+ mode = (conf >> modeshift) & 0x3;
+ if (sc->lm_sensors[n].rfact == 1) {
+ conf = sc->lm_readreg(sc, 0x12);
+ minfan = (conf >> minfanbit) & 0x1;
+ } else
+ minfan = 1;
+
+ if (mode == 0x1 && minfan == 1)
+ sensor->flags &= ~SENSOR_FUNKNOWN;
+ else
+ sensor->flags |= SENSOR_FUNKNOWN;
+
+#ifdef LMFANDUTYHINTS
+ if (sensor->flags & SENSOR_FUNKNOWN)
+ sensor->status = SENSOR_S_UNSPEC;
+ else if (data > 148)
+ sensor->status = SENSOR_S_OK; /* at least 7V */
+ else if (data > 106)
+ sensor->status = SENSOR_S_WARN; /* at least 5V */
+ else
+ sensor->status = SENSOR_S_CRIT; /* less than 5V */
+#endif /* LMFANDUTYHINTS */
+}
+
+void
+w83627ehf_refresh_indicator_rw(struct lm_softc *sc, int n)
+{
+ struct ksensor *sensor = &sc->sensors[n];
+ int nv;
+ int confreg, selshift, modeshift, conf, sel;
+ const char* const sels[2] =
+ { "PWM", "DC" };
+
+ /* get the right Fan Configuration Register */
+ switch (sc->lm_sensors[n].reg) {
+ case 0x01: /* Sys */
+ confreg = 0x04; selshift = 0; modeshift = 2;
+ break;
+ case 0x03: /* CPU */
+ confreg = 0x04; selshift = 1; modeshift = 4;
+ break;
+ case 0x11: /* Aux */
+ confreg = 0x12; selshift = 0; modeshift = 1;
+ break;
+ case 0x61: /* CPU */
+ confreg = 0x5b; selshift = 6; modeshift = 4;
+ break;
+ default:
+ return;
+ }
+
+ if (sensor->flags & SENSOR_FNEWVALUE) {
+ sensor->flags &= ~SENSOR_FNEWVALUE;
+ nv = sensor->upvalue;
+ if (nv == 0 || nv == 1) {
+ conf = sc->lm_readreg(sc, confreg);
+ sel = (conf >> selshift) & 0x1;
+ if (sel != nv) {
+ if (nv == 0)
+ conf &= ~(0x1 << selshift);
+ else
+ conf |= (0x1 << selshift);
+ sc->lm_writereg(sc, confreg, conf);
+ }
+ }
+ }
+
+ conf = sc->lm_readreg(sc, confreg);
+ sel = (conf >> selshift) & 0x1;
+ sensor->value = sel;
+ ksnprintf(sensor->desc + 8, sizeof(sensor->desc) - 8,
+ "%s/%s: %s", sels[0], sels[1], sels[sel]);
+}
+
+void
+w83627ehf_refresh_temptarget_rw(struct lm_softc *sc, int n)
+{
+ struct ksensor *sensor = &sc->sensors[n];
+ int nv, data;
+ int confreg, modeshift, tolreg, tolsh, conf, mode;
+
+ /* get the right Fan Configuration Register and Tolerance */
+ /* search for Relative Registers in the datasheet for a nice table */
+ /* .reg in this switch is the target cruise register */
+ switch (sc->lm_sensors[n].reg) {
+ case 0x05: /* Sys */
+ confreg = 0x04; modeshift = 2; tolreg = 0x07; tolsh = 0;
+ break;
+ case 0x06: /* CPU */
+ confreg = 0x04; modeshift = 4; tolreg = 0x07; tolsh = 4;
+ break;
+ case 0x13: /* Aux */
+ confreg = 0x12; modeshift = 1; tolreg = 0x14; tolsh = 0;
+ break;
+ case 0x63: /* CPU */
+ confreg = 0x5b; modeshift = 4; tolreg = 0x62; tolsh = 0;
+ break;
+ default:
+ return;
+ }
+
+ if (sensor->flags & SENSOR_FNEWVALUE) {
+ sensor->flags &= ~SENSOR_FNEWVALUE;
+ nv = sensor->upvalue;
+ /*
+ * If the new value is invalid, assume 'panic',
+ * and make 36 degC the new target temp.
+ */
+ if (nv < 0 || nv > 127)
+ nv = 36;
+ /*
+ * Since we got an explicit request to affect the speed,
+ * we need to go into Temperature Cruise mode first.
+ */
+ conf = sc->lm_readreg(sc, confreg);
+ mode = (conf >> modeshift) & 0x3;
+ if (mode != 0x1) {
+ conf &= ~(0x3 << modeshift);
+ conf |= (0x1 << modeshift);
+ sc->lm_writereg(sc, confreg, conf);
+ }
+ sc->lm_writereg(sc, sc->lm_sensors[n].reg, nv);
+ }
+
+ /* now populate our struct ksensor */
+
+ data = sc->lm_readreg(sc, sc->lm_sensors[n].reg);
+ sensor->value = data * 1000000 + 273150000;
+
+ conf = sc->lm_readreg(sc, confreg);
+ mode = (conf >> modeshift) & 0x3;
+ if (mode != 0x1)
+ sensor->flags |= SENSOR_FUNKNOWN;
+ else
+ sensor->flags &= ~SENSOR_FUNKNOWN;
+}
+
+void
+w83627ehf_refresh_temptargettol_rw(struct lm_softc *sc, int n)
+{
+ struct ksensor *sensor = &sc->sensors[n];
+ int nv, data;
+ int confreg, modeshift, tolreg, tolsh, conf, mode;
+
+ /* get the right Fan Configuration Register and Tolerance */
+ /* search for Relative Registers in the datasheet for a nice table */
+ /* .reg in this switch is the target cruise register */
+ switch (sc->lm_sensors[n].reg) {
+ case 0x05: /* Sys */
+ confreg = 0x04; modeshift = 2; tolreg = 0x07; tolsh = 0;
+ break;
+ case 0x06: /* CPU */
+ confreg = 0x04; modeshift = 4; tolreg = 0x07; tolsh = 4;
+ break;
+ case 0x13: /* Aux */
+ confreg = 0x12; modeshift = 1; tolreg = 0x14; tolsh = 0;
+ break;
+ case 0x63: /* CPU */
+ confreg = 0x5b; modeshift = 4; tolreg = 0x62; tolsh = 0;
+ break;
+ default:
+ return;
+ }
+
+ if (sensor->flags & SENSOR_FNEWVALUE) {
+ sensor->flags &= ~SENSOR_FNEWVALUE;
+ nv = sensor->upvalue;
+ if (!(nv < 0 || nv > 16)) {
+ data = sc->lm_readreg(sc, tolreg);
+ data &= ~(0xf << tolsh);
+ data |= (nv << tolsh);
+ sc->lm_writereg(sc, tolreg, data);
+ }
+ }
+
+ /* now populate our struct ksensor */
+
+ data = sc->lm_readreg(sc, tolreg);
+ data &= (0xf << tolsh);
+ data >>= tolsh;
+ sensor->value = data * 1000000 + 273150000;
+
+ conf = sc->lm_readreg(sc, confreg);
+ mode = (conf >> modeshift) & 0x3;
+ if (mode != 0x1)
+ sensor->flags |= SENSOR_FUNKNOWN;
+ else
+ sensor->flags &= ~SENSOR_FUNKNOWN;
+}
+
+void
+w83627thf_refresh_fanvolt_rw(struct lm_softc *sc, int n)
+{
+ struct ksensor *sensor = &sc->sensors[n];
+ int nv, data;
+ int confreg, modeshift, conf, mode;
+ const char* const modes[4] =
+ { "Manual", "Thermal", "Speed", "" };
+
+ /* get the right Fan Configuration Register */
+ switch (sc->lm_sensors[n].reg) {
+ case 0x01: /* Sys */
+ confreg = 0x04; modeshift = 2;
+ break;
+ case 0x03: /* CPU */
+ confreg = 0x04; modeshift = 4;
+ break;
+ case 0x11: /* Aux */
+ confreg = 0x12; modeshift = 1;
+ break;
+ default:
+ return;
+ }
+
+ if (sensor->flags & SENSOR_FNEWVALUE) {
+ sensor->flags &= ~SENSOR_FNEWVALUE;
+ nv = sensor->upvalue;
+ if (nv < 0 || nv > 100)
+ nv = 100; /* ramp it up! */
+ /* only 4 out of 8 bits are used to control voltage */
+ nv = 0xf * nv / 100;
+ nv <<= 4;
+ /*
+ * Since we got an explicit request to affect the speed,
+ * we need to go into manual mode first.
+ */
+ conf = sc->lm_readreg(sc, confreg);
+ mode = (conf >> modeshift) & 0x3;
+ if (mode != 0) {
+ conf &= ~(0x3 << modeshift);
+ sc->lm_writereg(sc, confreg, conf);
+ }
+ sc->lm_writereg(sc, sc->lm_sensors[n].reg, nv);
+ }
+
+ /* now populate our struct ksensor */
+
+ conf = sc->lm_readreg(sc, confreg);
+ mode = (conf >> modeshift) & 0x3;
+ ksnprintf(sensor->desc + 8, sizeof(sensor->desc) - 8,
+ "Ctl %s", modes[mode]);
+
+ data = sc->lm_readreg(sc, sc->lm_sensors[n].reg);
+ data >>= 4;
+ /* 1000 is the factor to convert from percentage to SENSOR_PERCENT */
+ sensor->value = 1000 * 100 * data / 0xf;
+#ifdef LMFANDUTYHINTS
+ if (data > 0x8)
+ sensor->status = SENSOR_S_OK; /* at least 7.2V */
+ else if (data > 0x5)
+ sensor->status = SENSOR_S_WARN; /* at least 4.8V */
+ else
+ sensor->status = SENSOR_S_CRIT; /* 4.0V and less */
+#endif /* LMFANDUTYHINTS */
+}
+
+void
wb_w83637hf_refresh_vcore(struct lm_softc *sc, int n)
{
struct ksensor *sensor = &sc->sensors[n];
int data;
data = sc->lm_readreg(sc, sc->lm_sensors[n].reg);
/*
--
1.6.6
--opJtzjQTFsWo+cga--
More information about the Kernel
mailing list