Module Name:    src
Committed By:   macallan
Date:           Wed Nov  9 05:47:54 UTC 2011

Modified Files:
        src/sys/dev/i2c: lm75.c

Log Message:
Support setting the temperature threshold for the LM75's alarm/interrupt
output. Some hardware ( I'm looking at you, Gdium ) abuses it to control
a fan.


To generate a diff of this commit:
cvs rdiff -u -r1.22 -r1.23 src/sys/dev/i2c/lm75.c

Please note that diffs are not public domain; they are subject to the
copyright notices on the relevant files.

Modified files:

Index: src/sys/dev/i2c/lm75.c
diff -u src/sys/dev/i2c/lm75.c:1.22 src/sys/dev/i2c/lm75.c:1.23
--- src/sys/dev/i2c/lm75.c:1.22	Mon Jun 20 20:16:19 2011
+++ src/sys/dev/i2c/lm75.c	Wed Nov  9 05:47:54 2011
@@ -1,4 +1,4 @@
-/*	$NetBSD: lm75.c,v 1.22 2011/06/20 20:16:19 pgoyette Exp $	*/
+/*	$NetBSD: lm75.c,v 1.23 2011/11/09 05:47:54 macallan Exp $	*/
 
 /*
  * Copyright (c) 2003 Wasabi Systems, Inc.
@@ -36,12 +36,13 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: lm75.c,v 1.22 2011/06/20 20:16:19 pgoyette Exp $");
+__KERNEL_RCSID(0, "$NetBSD: lm75.c,v 1.23 2011/11/09 05:47:54 macallan Exp $");
 
 #include <sys/param.h>
 #include <sys/systm.h>
 #include <sys/device.h>
 #include <sys/kernel.h>
+#include <sys/sysctl.h>
 
 #include <dev/sysmon/sysmonvar.h>
 
@@ -49,11 +50,13 @@ __KERNEL_RCSID(0, "$NetBSD: lm75.c,v 1.2
 #include <dev/i2c/lm75reg.h>
 
 struct lmtemp_softc {
+	device_t sc_dev;
 	i2c_tag_t sc_tag;
 	int sc_address;
 
 	struct sysmon_envsys *sc_sme;
 	envsys_data_t sc_sensor;
+	int sc_tmax;
 
 	uint32_t (*sc_lmtemp_decode)(const uint8_t *);
 };
@@ -67,10 +70,13 @@ CFATTACH_DECL_NEW(lmtemp, sizeof(struct 
 static void	lmtemp_refresh(struct sysmon_envsys *, envsys_data_t *);
 
 static int	lmtemp_config_write(struct lmtemp_softc *, uint8_t);
+static int	lmtemp_temp_write(struct lmtemp_softc *, int, uint16_t);
 static uint32_t lmtemp_decode_lm75(const uint8_t *);
 static uint32_t lmtemp_decode_ds75(const uint8_t *);
 static uint32_t lmtemp_decode_lm77(const uint8_t *);
 
+static void	lmtemp_setup_sysctl(struct lmtemp_softc *);
+static int	sysctl_lm75_temp(SYSCTLFN_ARGS);
 
 static const char * lmtemp_compats[] = {
 	"i2c-lm75",
@@ -143,6 +149,7 @@ lmtemp_attach(device_t parent, device_t 
 	struct i2c_attach_args *ia = aux;
 	int i;
 
+	sc->sc_dev = self;
 	if (ia->ia_name == NULL) {
 		for (i = 0; lmtemptbl[i].lmtemp_type != -1 ; i++)
 			if (lmtemptbl[i].lmtemp_type ==
@@ -165,9 +172,17 @@ lmtemp_attach(device_t parent, device_t 
 			lmtemptbl[i].lmtemp_name);
 	}
 
+	/*
+	 * according to the LM75 data sheet 80C is the default, so leave it
+	 * there to avoid unexpected behaviour
+	 */
+	sc->sc_tmax = 80;
+	if (i == lmtemp_lm75)
+		lmtemp_setup_sysctl(sc);
+
 	/* Set the configuration of the LM75 to defaults. */
 	iic_acquire_bus(sc->sc_tag, I2C_F_POLL);
-	if (lmtemp_config_write(sc, 0) != 0) {
+	if (lmtemp_config_write(sc, LM75_CONFIG_FAULT_QUEUE_4) != 0) {
 		aprint_error_dev(self, "unable to write config register\n");
 		iic_release_bus(sc->sc_tag, I2C_F_POLL);
 		return;
@@ -212,6 +227,19 @@ lmtemp_config_write(struct lmtemp_softc 
 }
 
 static int
+lmtemp_temp_write(struct lmtemp_softc *sc, int reg, uint16_t val)
+{
+	uint8_t cmdbuf[3];
+
+	cmdbuf[0] = reg;
+	cmdbuf[1] = (val >> 1) & 0xff;
+	cmdbuf[2] = (val & 1) << 7;
+
+	return iic_exec(sc->sc_tag, I2C_OP_WRITE_WITH_STOP,
+	    sc->sc_address, cmdbuf, 1, &cmdbuf[1], 2, I2C_F_POLL);
+}
+
+static int
 lmtemp_temp_read(struct lmtemp_softc *sc, uint8_t which, uint32_t *valp)
 {
 	int error;
@@ -316,3 +344,71 @@ lmtemp_decode_lm77(const uint8_t *buf)
 	return val;
 }
 
+static void
+lmtemp_setup_sysctl(struct lmtemp_softc *sc)
+{
+	const struct sysctlnode *me = NULL, *node = NULL;
+
+	iic_acquire_bus(sc->sc_tag, I2C_F_POLL);
+	lmtemp_temp_write(sc, LM75_REG_THYST_SET_POINT, (sc->sc_tmax - 5) * 2);
+	lmtemp_temp_write(sc, LM75_REG_TOS_SET_POINT, sc->sc_tmax * 2);
+	iic_release_bus(sc->sc_tag, I2C_F_POLL);
+
+	sysctl_createv(NULL, 0, NULL, &me,
+	    CTLFLAG_READWRITE,
+	    CTLTYPE_NODE, device_xname(sc->sc_dev), NULL,
+	    NULL, 0, NULL, 0,
+	    CTL_MACHDEP, CTL_CREATE, CTL_EOL);
+
+	sysctl_createv(NULL, 0, NULL, &node,
+	    CTLFLAG_READWRITE | CTLFLAG_OWNDESC,
+	    CTLTYPE_INT, "temp", "Threshold temperature",
+	    sysctl_lm75_temp, 1, sc, 0,
+	    CTL_MACHDEP, me->sysctl_num, CTL_CREATE, CTL_EOL);
+}
+
+static int
+sysctl_lm75_temp(SYSCTLFN_ARGS)
+{
+	struct sysctlnode node = *rnode;
+	struct lmtemp_softc *sc = node.sysctl_data;
+	int temp;
+
+	if (newp) {
+
+		/* we're asked to write */	
+		node.sysctl_data = &sc->sc_tmax;
+		if (sysctl_lookup(SYSCTLFN_CALL(&node)) == 0) {
+
+			temp = *(int *)node.sysctl_data;
+			sc->sc_tmax = temp;
+			iic_acquire_bus(sc->sc_tag, I2C_F_POLL);
+			lmtemp_temp_write(sc, LM75_REG_THYST_SET_POINT,
+			    (sc->sc_tmax - 5) * 2);
+			lmtemp_temp_write(sc, LM75_REG_TOS_SET_POINT,
+			    sc->sc_tmax * 2);
+			iic_release_bus(sc->sc_tag, I2C_F_POLL);
+			return 0;
+		}
+		return EINVAL;
+	} else {
+
+		node.sysctl_data = &sc->sc_tmax;
+		node.sysctl_size = 4;
+		return (sysctl_lookup(SYSCTLFN_CALL(&node)));
+	}
+
+	return 0;
+}
+
+SYSCTL_SETUP(sysctl_lmtemp_setup, "sysctl lmtemp subtree setup")
+{
+
+	sysctl_createv(NULL, 0, NULL, NULL,
+		       CTLFLAG_PERMANENT,
+		       CTLTYPE_NODE, "machdep", NULL,
+		       NULL, 0, NULL, 0,
+		       CTL_MACHDEP, CTL_EOL);
+}
+
+

Reply via email to