summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTheo de Raadt <deraadt@cvs.openbsd.org>2005-11-17 00:37:15 +0000
committerTheo de Raadt <deraadt@cvs.openbsd.org>2005-11-17 00:37:15 +0000
commitbf447ef0b54396c400135c7dd0c4525a76b9295c (patch)
treec51ec0cae025fbadfe0f62315f615623885891f5
parentbe565acad91e72381f56d463724e5d0962ee3a25 (diff)
basic driver for adt7460 found in some machines
-rw-r--r--sys/dev/i2c/adt7460.c239
-rw-r--r--sys/dev/i2c/files.i2c7
2 files changed, 245 insertions, 1 deletions
diff --git a/sys/dev/i2c/adt7460.c b/sys/dev/i2c/adt7460.c
new file mode 100644
index 00000000000..d7fd38637d7
--- /dev/null
+++ b/sys/dev/i2c/adt7460.c
@@ -0,0 +1,239 @@
+/* $OpenBSD: adt7460.c,v 1.1 2005/11/17 00:37:14 deraadt Exp $ */
+
+/*
+ * Copyright (c) 2005 Mark Kettenis
+ *
+ * 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
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/device.h>
+#include <sys/sensors.h>
+
+#include <dev/i2c/i2cvar.h>
+
+/* ADT7460 registers */
+#define ADT7460_2_5V 0x20
+#define ADT7460_VCCP1 0x22
+#define ADT7460_REM1_TEMP 0x25
+#define ADT7460_LOCAL_TEMP 0x26
+#define ADT7460_REM2_TEMP 0x27
+#define ADT7460_TACH1L 0x28
+#define ADT7460_TACH1H 0x29
+#define ADT7460_TACH2L 0x2a
+#define ADT7460_TACH2H 0x2b
+#define ADT7460_TACH3L 0x2c
+#define ADT7460_TACH3H 0x2d
+#define ADT7460_TACH4L 0x2e
+#define ADT7460_TACH4H 0x2f
+#define ADT7460_REVISION 0x3f
+
+/* Sensors */
+#define ADT_2_5V 0
+#define ADT_VCCP1 1
+#define ADT_REM1_TEMP 2
+#define ADT_LOCAL_TEMP 3
+#define ADT_REM2_TEMP 4
+#define ADT_TACH1 5
+#define ADT_TACH2 6
+#define ADT_TACH3 7
+#define ADT_TACH4 8
+#define ADT_NUM_SENSORS 9
+
+struct adt_softc {
+ struct device sc_dev;
+ i2c_tag_t sc_tag;
+ i2c_addr_t sc_addr;
+
+ struct sensor sc_sensor[ADT_NUM_SENSORS];
+};
+
+int adt_match(struct device *, void *, void *);
+void adt_attach(struct device *, struct device *, void *);
+
+void adt_refresh(void *);
+
+struct cfattach adt_ca = {
+ sizeof(struct adt_softc), adt_match, adt_attach
+};
+
+struct cfdriver adt_cd = {
+ NULL, "adt", DV_DULL
+};
+
+int
+adt_match(struct device *parent, void *match, void *aux)
+{
+ struct i2c_attach_args *ia = aux;
+
+ if (ia->ia_compat) {
+ if (strcmp(ia->ia_compat, "adt7460") == 0)
+ return (1);
+ return (0);
+ }
+ return (1); /* accept the address given */
+}
+
+void
+adt_attach(struct device *parent, struct device *self, void *aux)
+{
+ struct adt_softc *sc = (struct adt_softc *)self;
+ struct i2c_attach_args *ia = aux;
+ u_int8_t cmd, rev;
+ int i;
+
+ sc->sc_tag = ia->ia_tag;
+ sc->sc_addr = ia->ia_addr;
+
+ iic_acquire_bus(sc->sc_tag, 0);
+
+ cmd = ADT7460_REVISION;
+ if (iic_exec(sc->sc_tag, I2C_OP_READ_WITH_STOP,
+ sc->sc_addr, &cmd, sizeof cmd, &rev, sizeof rev, 0)) {
+ iic_release_bus(sc->sc_tag, 0);
+ printf(": cannot read REV register\n");
+ return;
+ }
+
+ iic_release_bus(sc->sc_tag, 0);
+
+ printf(": ADT7460 rev %x", rev);
+
+ /* Initialize sensor data. */
+ for (i = 0; i < ADT_NUM_SENSORS; i++)
+ strlcpy(sc->sc_sensor[i].device, sc->sc_dev.dv_xname,
+ sizeof(sc->sc_sensor[i].device));
+
+ sc->sc_sensor[ADT_2_5V].type = SENSOR_VOLTS_DC;
+ strlcpy(sc->sc_sensor[ADT_2_5V].desc, "+2.5Vin",
+ sizeof(sc->sc_sensor[ADT_2_5V].desc));
+
+ sc->sc_sensor[ADT_VCCP1].type = SENSOR_VOLTS_DC;
+ strlcpy(sc->sc_sensor[ADT_VCCP1].desc, "Vccp1",
+ sizeof(sc->sc_sensor[ADT_VCCP1].desc));
+
+ sc->sc_sensor[ADT_REM1_TEMP].type = SENSOR_TEMP;
+ strlcpy(sc->sc_sensor[ADT_REM1_TEMP].desc, "Rem1 Temp.",
+ sizeof(sc->sc_sensor[ADT_REM1_TEMP].desc));
+
+ sc->sc_sensor[ADT_LOCAL_TEMP].type = SENSOR_TEMP;
+ strlcpy(sc->sc_sensor[ADT_LOCAL_TEMP].desc, "Int. Temp.",
+ sizeof(sc->sc_sensor[ADT_LOCAL_TEMP].desc));
+
+ sc->sc_sensor[ADT_REM2_TEMP].type = SENSOR_TEMP;
+ strlcpy(sc->sc_sensor[ADT_REM2_TEMP].desc, "Rem1 Temp.",
+ sizeof(sc->sc_sensor[ADT_REM2_TEMP].desc));
+
+ sc->sc_sensor[ADT_TACH1].type = SENSOR_FANRPM;
+ strlcpy(sc->sc_sensor[ADT_TACH1].desc, "TACH1",
+ sizeof(sc->sc_sensor[ADT_TACH1].desc));
+
+ sc->sc_sensor[ADT_TACH2].type = SENSOR_FANRPM;
+ strlcpy(sc->sc_sensor[ADT_TACH2].desc, "TACH1",
+ sizeof(sc->sc_sensor[ADT_TACH2].desc));
+
+ sc->sc_sensor[ADT_TACH3].type = SENSOR_FANRPM;
+ strlcpy(sc->sc_sensor[ADT_TACH3].desc, "TACH1",
+ sizeof(sc->sc_sensor[ADT_TACH3].desc));
+
+ sc->sc_sensor[ADT_TACH4].type = SENSOR_FANRPM;
+ strlcpy(sc->sc_sensor[ADT_TACH4].desc, "TACH1",
+ sizeof(sc->sc_sensor[ADT_TACH4].desc));
+
+ if (sensor_task_register(sc, adt_refresh, 5)) {
+ printf(", unable to register update task\n");
+ return;
+ }
+
+ for (i = 0; i < ADT_NUM_SENSORS; i++)
+ SENSOR_ADD(&sc->sc_sensor[i]);
+
+ printf("\n");
+}
+
+struct {
+ char sensor;
+ u_int8_t cmd;
+} worklist[] = {
+ { ADT_2_5V, ADT7460_2_5V },
+ { ADT_VCCP1, ADT7460_VCCP1 },
+ { ADT_REM1_TEMP, ADT7460_REM1_TEMP },
+ { ADT_LOCAL_TEMP, ADT7460_LOCAL_TEMP },
+ { ADT_REM2_TEMP, ADT7460_REM2_TEMP },
+ { ADT_TACH1, ADT7460_TACH1L },
+ { ADT_TACH2, ADT7460_TACH2L },
+ { ADT_TACH3, ADT7460_TACH3L },
+ { ADT_TACH4, ADT7460_TACH4L },
+};
+
+void
+adt_refresh(void *arg)
+{
+ struct adt_softc *sc = arg;
+ u_int8_t cmd, data, data2;
+ u_int16_t fan;
+ int i;
+
+ iic_acquire_bus(sc->sc_tag, 0);
+
+ for (i = 0; i < sizeof worklist / sizeof(worklist[0]); i++) {
+ cmd = worklist[i].cmd;
+ if (iic_exec(sc->sc_tag, I2C_OP_READ_WITH_STOP,
+ sc->sc_addr, &cmd, sizeof cmd, &data, sizeof data, 0)) {
+ sc->sc_sensor[i].flags |= SENSOR_FINVALID;
+ continue;
+ }
+
+ sc->sc_sensor[i].flags &= ~SENSOR_FINVALID;
+ switch (worklist[i].sensor) {
+ case ADT_2_5V:
+ sc->sc_sensor[i].value = 2500000 * data / 192;
+ break;
+ case ADT_VCCP1:
+ sc->sc_sensor[i].value = 2700000 * data / 192;
+ break;
+ case ADT_LOCAL_TEMP:
+ case ADT_REM1_TEMP:
+ case ADT_REM2_TEMP:
+ if (data == 0x80)
+ sc->sc_sensor[i].flags |= SENSOR_FINVALID;
+ else
+ sc->sc_sensor[i].value =
+ (int8_t)data * 1000000 + 273150000;
+ break;
+ case ADT_TACH1:
+ case ADT_TACH2:
+ case ADT_TACH3:
+ case ADT_TACH4:
+ cmd = worklist[i].cmd + 1; /* TACHnH follows TACHnL */
+ if (iic_exec(sc->sc_tag, I2C_OP_READ_WITH_STOP,
+ sc->sc_addr, &cmd, sizeof cmd, &data2, sizeof data2, 0)) {
+ sc->sc_sensor[i].flags |= SENSOR_FINVALID;
+ continue;
+ }
+
+ fan = data + (data2 << 8);
+ if (fan == 0)
+ sc->sc_sensor[i].flags |= SENSOR_FINVALID;
+ else
+ sc->sc_sensor[i].value = (90000 * 60) / fan;
+ break;
+ default:
+ sc->sc_sensor[i].flags |= SENSOR_FINVALID;
+ break;
+ }
+ }
+
+ iic_release_bus(sc->sc_tag, 0);
+}
diff --git a/sys/dev/i2c/files.i2c b/sys/dev/i2c/files.i2c
index 84ba3ced648..fc936229452 100644
--- a/sys/dev/i2c/files.i2c
+++ b/sys/dev/i2c/files.i2c
@@ -1,4 +1,4 @@
-# $OpenBSD: files.i2c,v 1.14 2005/11/16 18:51:45 deraadt Exp $
+# $OpenBSD: files.i2c,v 1.15 2005/11/17 00:37:14 deraadt Exp $
# $NetBSD: files.i2c,v 1.3 2003/10/20 16:24:10 briggs Exp $
define i2c {[addr = -1], [size = -1]}
@@ -58,3 +58,8 @@ file dev/i2c/ds1631.c maxds
device fcu: gpiobus
attach fcu at i2c
file dev/i2c/fcu.c fcu
+
+# Apple ADT
+device adt: gpiobus
+attach adt at i2c
+file dev/i2c/adt7460.c adt