[prev in list] [next in list] [prev in thread] [next in thread] 

List:       openbsd-tech
Subject:    Temperature sensors on Soekris net4826
From:       Matt Dainty <matt () bodgit-n-scarper ! com>
Date:       2006-06-26 23:32:55
Message-ID: 20060626233255.GB2811 () gelf ! bodgit-n-scarper ! com
[Download RAW message or body]

Hi,

Please find attached (inline this time, thanks to some private
suggestions) some patches I have made in order to support the Philips
LM75A chip on my Soekris net4826.

Since I last posted them, I have in addition also corrected a small
error in i2c_scan.c(iic_probe) for masking the address bits before
calling lm75probe(). The mask of 0x7c is correct for LM77's which only
use the two LSB's for possible addresses, (and so match 10010XX).
According to the datasheets, the LM75 & LM75A use the three LSB's for
addresses, so the mask should be 0x78 (to match 1001XXX), otherwise you
may risk ignoring some LM75's on the I2C bus. This makes the code match
the comments ;-)

As before:

I use the following snippet of kernel config:

gpio0 at gscpcib?
gpioiic0 at gpio0 offset 12 mask 0x3
iic0 at gpioiic0
lmtemp* at iic0 addr 0x48

*However*, I needed to use a crude hack to gpioiic.c to reverse the
order of the SDA and SCL pins for the net4826 so that SDA is on pin 13
and SCL is on pin 12 which matches up with the SC1100 datasheet. I've
included the patch to illustrate the change I made. I wasn't sure of the
best way to handle both pin orders in the driver/kernel config.

The LM75A supports better temperature resolution so I patched
i2c_scan.c(lm75probe) to detect the chip as a distinct variant, and
lm75.c contains the extra code/comments regarding the chip. I've also
updated the lmtemp(4) man page.

Because the LM75A supports resolution in 0.125C increments, I found
sysctl only displayed to two decimal places, so the final patch just
tweaks the formatting used by sysctl(8).

Here's the dmesg from my net4826:

gscpcib0 at pci0 dev 18 function 0 "NS SC1100 ISA" rev 0x00
gpio0 at gscpcib0: 64 pins
gpioiic0 at gpio0 pins 12 13: SDA[13] open-drain pull-up, SCL[12] open-drain pull-up
iic0 at gpioiic0
lmtemp0 at iic0 addr 0x48: lm75a

Here's the sysctl output:

# sysctl hw.sensors
hw.sensors.0=lmtemp0, TEMP, temp, 44.500 degC / 112.100 degF
# sysctl hw.sensors
hw.sensors.0=lmtemp0, TEMP, temp, 44.625 degC / 112.325 degF

As before, comments appreciated. If they're okay, should I also raise a
feature request PR?

Matt

--- sys/dev/gpio/gpioiic.c.orig	Wed Oct  5 05:43:27 2005
+++ sys/dev/gpio/gpioiic.c	Wed Oct  5 05:44:39 2005
@@ -30,8 +30,8 @@
 #include <dev/i2c/i2cvar.h>
 #include <dev/i2c/i2c_bitbang.h>
 
-#define GPIOIIC_PIN_SDA		0
-#define GPIOIIC_PIN_SCL		1
+#define GPIOIIC_PIN_SDA		1
+#define GPIOIIC_PIN_SCL		0
 #define GPIOIIC_NPINS		2
 
 #define GPIOIIC_SDA		0x01
--- sys/dev/i2c/i2c_scan.c.orig	Wed Oct  5 06:33:07 2005
+++ sys/dev/i2c/i2c_scan.c	Fri Oct  7 22:42:17 2005
@@ -156,6 +156,7 @@
 lm75probe(void)
 {
 	u_int16_t temp, thyst, tos, tlow, thigh, mask = LM75TMASK;
+	u_int16_t value;
 	u_int8_t conf;
 	int ret = 75, i;
 
@@ -185,9 +186,21 @@
 	/*
 	 * LM77/LM75 registers 6, 7
 	 * echo whatever was read just before them from reg 0, 1, or 2
+	 *
+	 * Philips LM75A doesn't appear to do this, so maybe is a good way
+	 * of detecting such a beast?
 	 */
 	for (i = 6; i <= 7; i++) {
-		if ((iicprobew(LM75TEMP) & mask) != (iicprobew(i) & mask) ||
+		temp = iicprobew(LM75TEMP);
+		value = iicprobew(i);
+
+		/* Cheekily use 76 to mean LM75A */
+		if (value == 0xffff) {
+			ret = 76;
+			break;
+		}
+
+		if ((temp & mask) != (value & mask) ||
 		    (iicprobew(LM75Thyst) & mask) != (iicprobew(i) & mask) ||
 		    (iicprobew(LM75Tos) & mask) != (iicprobew(i) & mask))
 			return (NULL);
@@ -196,8 +209,11 @@
 	/*
 	 * LM75 has no registers 4 or 5, and they will act as echos too
 	 * If we find that 4 and 5 are not echos, then we may have a LM77
+	 *
+	 * Philips LM75A doesn't do this either so if in the above test we
+	 * reckon this might be one, skip this test
 	 */
-	for (i = 4; i <= 5; i++) {
+	for (i = 4; i <= 5 && ret != 76; i++) {
 		if ((iicprobew(LM75TEMP) & mask) == (iicprobew(i) & mask) &&
 		    (iicprobew(LM75Thyst) & mask) == (iicprobew(i) & mask) &&
 		    (iicprobew(LM75Tos) & mask) == (iicprobew(i) & mask))
@@ -213,12 +229,17 @@
 		break;
 	}
 
-	/* a real LM75/LM77 repeats it's registers.... */
+	/* a real LM75/LM75A/LM77 repeats it's registers.... */
 	for (i = 0x08; i <= 0xf8; i += 8) {
 		if (conf != iicprobenc(LM75CONF + i) ||
 		    thyst != (iicprobew(LM75Thyst + i) & mask) ||
 		    tos != (iicprobew(LM75Tos + i) & mask))
 			return (NULL);
+
+		/* LM75A doesn't do any of the following tests so skip */
+		if (ret == 76)
+			continue;
+
 		tos = iicprobew(LM75Tos) & mask;
 		if (tos != (iicprobew(0x06 + i) & mask) ||
 		    tos != (iicprobew(0x07 + i) & mask))
@@ -238,6 +259,8 @@
 	/* We hope */
 	if (ret == 75)
 		return ("lm75");
+	if (ret == 76)
+		return ("lm75a");
 	return ("lm77");
 }
 
@@ -607,7 +630,7 @@
 	      iicprobe(0x16) == 0x41 && ((iicprobe(0x17) & 0xf0) == 0x40)) {
 		name = "adm1026";
 	} else if (name == NULL &&
-		   (addr & 0x7c) == 0x48) {		/* addr 0b1001xxx */
+		   (addr & 0x78) == 0x48) {		/* addr 0b1001xxx */
 		name = lm75probe();
 	}
 #if 0
--- sys/dev/i2c/lm75.c.orig	Wed Oct  5 08:20:35 2005
+++ sys/dev/i2c/lm75.c	Wed Oct  5 09:39:35 2005
@@ -89,6 +89,23 @@
  *	-25C	1 1100 1110	0x1ce
  *	-55C	1 1001 0010	0x192
  *
+ * Temperature on the LM75A is represented by an 11-bit two's complement
+ * integer in steps of 0.125C.  The LM75A can be treated like an LM75 if
+ * the extra precision is not required.  The following examples are
+ * taken from the LM75A data sheet:
+ *
+ *	+127.000C	011 1111 1000	0x3f8
+ *	+126.875C	011 1111 0111	0x3f7
+ *	+126.125C	011 1111 0001	0x3f1
+ *	+125.000C	011 1110 1000	0x3e8
+ *	+25.000C	000 1100 1000	0x0c8
+ *	+0.125C		000 0000 0001	0x001
+ *	0C		000 0000 0000	0x000
+ *	-0.125C		111 1111 1111	0x7ff
+ *	-25.000C	111 0011 1000	0x738
+ *	-54.875C	110 0100 1001	0x649
+ *	-55.000C	110 0100 1000	0x648
+ *
  * Temperature on the LM77 is represented by a 10-bit two's complement
  * integer in steps of 0.5C:
  *
@@ -107,6 +124,12 @@
  * 15  14   13   12   11   10   9    8    7    6 5 4 3 2 1 0
  *
  *
+ * LM75A temperature word:
+ *
+ * MSB Bit9 Bit8 Bit7 Bit6 Bit5 Bit4 Bit3 Bit2 Bit1 Bit0 X X X X X
+ * 15  14   13   12   11   10   9    8    7    6    5    4 3 2 1 0
+ *
+ *
  * LM77 temperature word:
  *
  * Sign Sign Sign Sign MSB Bit7 Bit6 Bit5 Bit4 Bit3 Bit2 Bit1 Bit0 Status bits
@@ -122,6 +145,7 @@
 	struct i2c_attach_args *ia = aux;
 
 	if (strcmp(ia->ia_name, "lm75") == 0 ||
+	    strcmp(ia->ia_name, "lm75a") == 0 ||
 	    strcmp(ia->ia_name, "lm77") == 0 ||
 	    strcmp(ia->ia_name, "ds1775") == 0)
 		return (1);
@@ -162,7 +186,9 @@
 
 	sc->sc_model = LM_MODEL_LM75;
 	sc->sc_bits = 9;
-	if (strcmp(ia->ia_name, "lm77") == 0) {
+	if (strcmp(ia->ia_name, "lm75a") == 0) {
+		sc->sc_bits = 11;
+	} else if (strcmp(ia->ia_name, "lm77") == 0) {
 		sc->sc_model = LM_MODEL_LM77;
 		sc->sc_bits = 13;
 	} else if (strcmp(ia->ia_name, "ds1775") == 0) {
@@ -201,7 +227,6 @@
 	if (buf[0] == 0x00 && buf[1] == 0x00)
 		return (1);
 
-	/* convert to half-degrees C */
 	*valp = ((buf[0] << 8) | buf[1]) / (1 << (16 - sc->sc_bits));
 	return (0);
 }
@@ -223,6 +248,9 @@
 		return;
 	}
 
-	sc->sc_sensor.value = val * 500000 + 273150000;
+	if (sc->sc_model == LM_MODEL_LM75 && sc->sc_bits == 11)
+		sc->sc_sensor.value = val * 125000 + 273150000;
+	else
+		sc->sc_sensor.value = val * 500000 + 273150000;
 	sc->sc_sensor.flags &= ~SENSOR_FINVALID;
 }
--- share/man/man4/lmtemp.4.orig	Fri Oct  7 19:37:52 2005
+++ share/man/man4/lmtemp.4	Fri Oct  7 19:50:12 2005
@@ -30,12 +30,16 @@
 The
 .Nm
 driver provides support for the National Semiconductor LM75,
-National Semiconductor LM77, and Dallas Semiconductor 1775
-temperature sensors.
-The sensor possesses single temperature value that can be accessed
+National Semiconductor LM77, Dallas Semiconductor 1775, and
+Philips Semiconductor LM75A temperature sensors.
+The sensor possesses a single temperature value that can be accessed
 through the
 .Xr sysctl 8
 interface.
+.Pp
+The sensors can report temperatures between -55C and +125C in
+increments of 0.5C with the exception of the LM75A which can do
+0.125C increments.
 .Sh SEE ALSO
 .Xr iic 4 ,
 .Xr intro 4 ,
@@ -61,3 +65,5 @@
 ported it to
 .Ox
 and added support for the LM77 chip.
+.An Matt Dainty Aq matt@bodgit-n-scarper.com
+added support for the LM75A chip.
--- sbin/sysctl/sysctl.c.orig	Fri Oct  7 19:21:07 2005
+++ sbin/sysctl/sysctl.c	Fri Oct  7 19:21:17 2005
@@ -2146,7 +2146,7 @@
 	else {
 		switch (s->type) {
 		case SENSOR_TEMP:
-			printf("temp, %.2f degC / %.2f degF",
+			printf("temp, %.3f degC / %.3f degF",
 			    (s->value - 273150000) / 1000000.0,
 			    (s->value - 273150000) / 1000000.0 * 9 / 5 + 32);
 			break;

[prev in list] [next in list] [prev in thread] [next in thread] 

Configure | About | News | Add a list | Sponsored by KoreLogic