summaryrefslogtreecommitdiff
path: root/sys/dev/i2c
diff options
context:
space:
mode:
authorMark Kettenis <kettenis@cvs.openbsd.org>2006-01-24 21:35:07 +0000
committerMark Kettenis <kettenis@cvs.openbsd.org>2006-01-24 21:35:07 +0000
commitdcae423edeaacfec4890a5bc8bf6ff966c277b33 (patch)
tree9212417217f4e48cd44d9dc098ae7d5b78d07c94 /sys/dev/i2c
parent92fe8e3940480d8f185a1a7464aa35f796dee6c5 (diff)
Initial stab at glenv(4), a driver for the GL518SM.
Diffstat (limited to 'sys/dev/i2c')
-rw-r--r--sys/dev/i2c/files.i2c7
-rw-r--r--sys/dev/i2c/gl518sm.c222
2 files changed, 228 insertions, 1 deletions
diff --git a/sys/dev/i2c/files.i2c b/sys/dev/i2c/files.i2c
index e0edbb27ffa..2e4f7d17d73 100644
--- a/sys/dev/i2c/files.i2c
+++ b/sys/dev/i2c/files.i2c
@@ -1,4 +1,4 @@
-# $OpenBSD: files.i2c,v 1.29 2006/01/15 12:20:14 kettenis Exp $
+# $OpenBSD: files.i2c,v 1.30 2006/01/24 21:35:06 kettenis Exp $
# $NetBSD: files.i2c,v 1.3 2003/10/20 16:24:10 briggs Exp $
define i2c {[addr = -1], [size = -1]}
@@ -102,3 +102,8 @@ file dev/i2c/asb100.c asbtm
device wbenv
attach wbenv at i2c
file dev/i2c/w83l784r.c wbenv
+
+# Genesys Logic GL518SM
+device glenv
+attach glenv at i2c
+file dev/i2c/gl518sm.c glenv
diff --git a/sys/dev/i2c/gl518sm.c b/sys/dev/i2c/gl518sm.c
new file mode 100644
index 00000000000..f2c556a998b
--- /dev/null
+++ b/sys/dev/i2c/gl518sm.c
@@ -0,0 +1,222 @@
+/* $OpenBSD: gl518sm.c,v 1.1 2006/01/24 21:35:06 kettenis Exp $ */
+
+/*
+ * Copyright (c) 2006 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>
+
+/* GL518SM registers */
+#define GL518SM_CHIPID 0x00
+#define GL518SM_REVISION 0x01
+#define GL518SM_VENDORID 0x02
+#define GL518SM_CONFIG 0x03
+#define GL518SM_CONFIG_START 0x40
+#define GL518SM_CONFIG_CLEARST 0x20
+#define GL518SM_CONFIG_NOFAN2 0x10
+#define GL518SM_TEMP 0x04
+#define GL518SM_TEMP_OVER 0x05
+#define GL518SM_TEMP_HYST 0x06
+#define GL518SM_FAN_COUNT 0x07
+#define GL518SM_FAN_LIMIT 0x08
+#define GL518SM_VIN1_LIMIT 0x09
+#define GL518SM_VIN2_LIMIT 0x0a
+#define GL518SM_VIN3_LIMIT 0x0b
+#define GL518SM_VDD_LIMIT 0x0c
+#define GL518SM_VOLTMETER 0x0d
+#define GL518SM_MISC 0x0f
+#define GL518SM_ALARM 0x10
+#define GL518SM_MASK 0x11
+#define GL518SM_INTSTAT 0x12
+
+/* Sensors */
+#define GLENV_VIN3 0
+#define GLENV_TEMP 1
+#define GLENV_FAN1 2
+#define GLENV_FAN2 3
+#define GLENV_NUM_SENSORS 4
+
+struct glenv_softc {
+ struct device sc_dev;
+
+ i2c_tag_t sc_tag;
+ i2c_addr_t sc_addr;
+
+ struct sensor sc_sensor[GLENV_NUM_SENSORS];
+ int sc_fan1_div, sc_fan2_div;
+};
+
+int glenv_match(struct device *, void *, void *);
+void glenv_attach(struct device *, struct device *, void *);
+
+void glenv_refresh(void *);
+
+struct cfattach glenv_ca = {
+ sizeof(struct glenv_softc), glenv_match, glenv_attach
+};
+
+struct cfdriver glenv_cd = {
+ NULL, "glenv", DV_DULL
+};
+
+int
+glenv_match(struct device *parent, void *match, void *aux)
+{
+ struct i2c_attach_args *ia = aux;
+
+ if (strcmp(ia->ia_name, "gl518sm") == 0)
+ return (1);
+ return (0);
+}
+
+void
+glenv_attach(struct device *parent, struct device *self, void *aux)
+{
+ struct glenv_softc *sc = (struct glenv_softc *)self;
+ struct i2c_attach_args *ia = aux;
+ u_int8_t cmd, data;
+ int i;
+
+ sc->sc_tag = ia->ia_tag;
+ sc->sc_addr = ia->ia_addr;
+
+ iic_acquire_bus(sc->sc_tag, 0);
+
+ cmd = GL518SM_REVISION;
+ if (iic_exec(sc->sc_tag, I2C_OP_READ_WITH_STOP,
+ sc->sc_addr, &cmd, sizeof cmd, &data, sizeof data, 0)) {
+ iic_release_bus(sc->sc_tag, 0);
+ printf(": cannot read revision register\n");
+ return;
+ }
+
+ printf("GL518SM rev 0x%2x", data);
+
+ cmd = GL518SM_MISC;
+ if (iic_exec(sc->sc_tag, I2C_OP_READ_WITH_STOP,
+ sc->sc_addr, &cmd, sizeof cmd, &data, sizeof data, 0)) {
+ iic_release_bus(sc->sc_tag, 0);
+ printf(", cannot read misc register\n");
+ return;
+ }
+ sc->sc_fan1_div = 1 << ((data >> 6) & 0x03);
+ sc->sc_fan2_div = 1 << ((data >> 4) & 0x03);
+
+ cmd = GL518SM_CONFIG;
+ if (iic_exec(sc->sc_tag, I2C_OP_READ_WITH_STOP,
+ sc->sc_addr, &cmd, sizeof cmd, &data, sizeof data, 0)) {
+ iic_release_bus(sc->sc_tag, 0);
+ printf(", cannot read configuration register\n");
+ return;
+ }
+ if (data & GL518SM_CONFIG_NOFAN2)
+ sc->sc_fan2_div = -1;
+
+ /* Start monitoring and clear interrupt status. */
+ data = (data | GL518SM_CONFIG_START | GL518SM_CONFIG_CLEARST);
+ if (iic_exec(sc->sc_tag, I2C_OP_WRITE_WITH_STOP,
+ sc->sc_addr, &cmd, sizeof cmd, &data, sizeof data, 0)) {
+ iic_release_bus(sc->sc_tag, 0);
+ printf(", cannot write configuration register\n");
+ return;
+ }
+
+ iic_release_bus(sc->sc_tag, 0);
+
+ /* Initialize sensor data. */
+ for (i = 0; i < GLENV_NUM_SENSORS; i++)
+ strlcpy(sc->sc_sensor[i].device, sc->sc_dev.dv_xname,
+ sizeof(sc->sc_sensor[i].device));
+
+ sc->sc_sensor[GLENV_VIN3].type = SENSOR_VOLTS_DC;
+ strlcpy(sc->sc_sensor[GLENV_VIN3].desc, "Vin3",
+ sizeof(sc->sc_sensor[GLENV_VIN3].desc));
+
+ sc->sc_sensor[GLENV_TEMP].type = SENSOR_TEMP;
+ strlcpy(sc->sc_sensor[GLENV_TEMP].desc, "Temp",
+ sizeof(sc->sc_sensor[GLENV_TEMP].desc));
+
+ sc->sc_sensor[GLENV_FAN1].type = SENSOR_FANRPM;
+ strlcpy(sc->sc_sensor[GLENV_FAN1].desc, "Fan1",
+ sizeof(sc->sc_sensor[GLENV_FAN1].desc));
+
+ sc->sc_sensor[GLENV_FAN2].type = SENSOR_FANRPM;
+ strlcpy(sc->sc_sensor[GLENV_FAN2].desc, "Fan2",
+ sizeof(sc->sc_sensor[GLENV_FAN2].desc));
+ if (sc->sc_fan2_div == -1)
+ sc->sc_sensor[GLENV_FAN2].flags |= SENSOR_FINVALID;
+
+ if (sensor_task_register(sc, glenv_refresh, 5)) {
+ printf(", unable to register update task\n");
+ return;
+ }
+
+ for (i = 0; i < GLENV_NUM_SENSORS; i++)
+ sensor_add(&sc->sc_sensor[i]);
+
+ printf("\n");
+}
+
+void
+glenv_refresh(void *arg)
+{
+ struct glenv_softc *sc = arg;
+ u_int8_t cmd, data, data2[2];
+ u_int tmp;
+
+ iic_acquire_bus(sc->sc_tag, 0);
+
+ cmd = GL518SM_VOLTMETER;
+ if (iic_exec(sc->sc_tag, I2C_OP_READ_WITH_STOP,
+ sc->sc_addr, &cmd, sizeof cmd, &data, sizeof data, 0)) {
+ sc->sc_sensor[GLENV_VIN3].flags |= SENSOR_FINVALID;
+ } else {
+ sc->sc_sensor[GLENV_VIN3].flags &= ~SENSOR_FINVALID;
+ sc->sc_sensor[GLENV_VIN3].value = data * 19000;
+ }
+
+ cmd = GL518SM_TEMP;
+ if (iic_exec(sc->sc_tag, I2C_OP_READ_WITH_STOP,
+ sc->sc_addr, &cmd, sizeof cmd, &data, sizeof data, 0)) {
+ sc->sc_sensor[GLENV_TEMP].flags |= SENSOR_FINVALID;
+ } else {
+ sc->sc_sensor[GLENV_TEMP].flags &= ~SENSOR_FINVALID;
+ sc->sc_sensor[GLENV_TEMP].value =
+ (data - 119) * 1000000 + 273150000;
+ }
+
+ cmd = GL518SM_FAN_COUNT;
+ if (iic_exec(sc->sc_tag, I2C_OP_READ_WITH_STOP,
+ sc->sc_addr, &cmd, sizeof cmd, &data2, sizeof data2, 0)) {
+ sc->sc_sensor[GLENV_FAN1].flags |= SENSOR_FINVALID;
+ sc->sc_sensor[GLENV_FAN2].flags |= SENSOR_FINVALID;
+ } else {
+ sc->sc_sensor[GLENV_FAN1].flags &= ~SENSOR_FINVALID;
+ tmp = data2[0] * sc->sc_fan1_div * 2;
+ sc->sc_sensor[GLENV_TEMP].value = 960000 / tmp;
+ if (sc->sc_fan2_div != -1) {
+ sc->sc_sensor[GLENV_FAN2].flags &= ~SENSOR_FINVALID;
+ tmp = data2[0] * sc->sc_fan2_div * 2;
+ sc->sc_sensor[GLENV_TEMP].value = 960000 / tmp;
+ }
+ }
+
+ iic_release_bus(sc->sc_tag, 0);
+}