Module Name: src
Committed By: pgoyette
Date: Sat May 9 15:04:25 UTC 2009
Modified Files:
src/distrib/sets/lists/man: mi
src/share/man/man4: Makefile
src/sys/arch/i386/conf: ALL
src/sys/dev/i2c: files.i2c
Added Files:
src/share/man/man4: sdtemp.4
src/sys/dev/i2c: sdtemp.c sdtemp_reg.h
Log Message:
Initial implementation of sdtemp(4) driver for on-DIMM temp sensor.
(These optional sensors are specified by JEDEC Standard No. 21-C
Section 4-7 and implemented by multiple vendors. Tested on my
amd64 machine with Kingston KVR1066D3E7S/2G memory which includes
a STMicro STTS424E02 sensor.)
To generate a diff of this commit:
cvs rdiff -u -r1.1135 -r1.1136 src/distrib/sets/lists/man/mi
cvs rdiff -u -r1.490 -r1.491 src/share/man/man4/Makefile
cvs rdiff -u -r0 -r1.1 src/share/man/man4/sdtemp.4
cvs rdiff -u -r1.197 -r1.198 src/sys/arch/i386/conf/ALL
cvs rdiff -u -r1.23 -r1.24 src/sys/dev/i2c/files.i2c
cvs rdiff -u -r0 -r1.1 src/sys/dev/i2c/sdtemp.c src/sys/dev/i2c/sdtemp_reg.h
Please note that diffs are not public domain; they are subject to the
copyright notices on the relevant files.
Modified files:
Index: src/distrib/sets/lists/man/mi
diff -u src/distrib/sets/lists/man/mi:1.1135 src/distrib/sets/lists/man/mi:1.1136
--- src/distrib/sets/lists/man/mi:1.1135 Fri May 1 22:59:53 2009
+++ src/distrib/sets/lists/man/mi Sat May 9 15:04:25 2009
@@ -1,4 +1,4 @@
-# $NetBSD: mi,v 1.1135 2009/05/01 22:59:53 agc Exp $
+# $NetBSD: mi,v 1.1136 2009/05/09 15:04:25 pgoyette Exp $
#
# Note: don't delete entries from here - mark them as "obsolete" instead.
#
@@ -1360,6 +1360,7 @@
./usr/share/man/cat4/scsi.0 man-sys-catman .cat
./usr/share/man/cat4/scsibus.0 man-sys-catman .cat
./usr/share/man/cat4/sd.0 man-sys-catman .cat
+./usr/share/man/cat4/sdtemp.0 man-sys-catman .cat
./usr/share/man/cat4/se.0 man-sys-catman .cat
./usr/share/man/cat4/sea.0 man-sys-catman .cat
./usr/share/man/cat4/sec.0 man-sys-catman .cat
@@ -3888,6 +3889,7 @@
./usr/share/man/html4/scsi.html man-sys-htmlman html
./usr/share/man/html4/scsibus.html man-sys-htmlman html
./usr/share/man/html4/sd.html man-sys-htmlman html
+./usr/share/man/html4/sdtemp.html man-sys-htmlman html
./usr/share/man/html4/se.html man-sys-htmlman html
./usr/share/man/html4/sea.html man-sys-htmlman html
./usr/share/man/html4/sec.html man-sys-htmlman html
@@ -6328,6 +6330,7 @@
./usr/share/man/man4/scsi.4 man-sys-man .man
./usr/share/man/man4/scsibus.4 man-sys-man .man
./usr/share/man/man4/sd.4 man-sys-man .man
+./usr/share/man/man4/sdtemp.4 man-sys-man .man
./usr/share/man/man4/se.4 man-sys-man .man
./usr/share/man/man4/sea.4 man-sys-man .man
./usr/share/man/man4/sec.4 man-sys-man .man
Index: src/share/man/man4/Makefile
diff -u src/share/man/man4/Makefile:1.490 src/share/man/man4/Makefile:1.491
--- src/share/man/man4/Makefile:1.490 Tue Apr 21 21:42:53 2009
+++ src/share/man/man4/Makefile Sat May 9 15:04:25 2009
@@ -1,4 +1,4 @@
-# $NetBSD: Makefile,v 1.490 2009/04/21 21:42:53 pgoyette Exp $
+# $NetBSD: Makefile,v 1.491 2009/05/09 15:04:25 pgoyette Exp $
# @(#)Makefile 8.1 (Berkeley) 6/18/93
MAN= aac.4 ac97.4 acardide.4 aceride.4 acphy.4 acpidalb.4 \
@@ -114,7 +114,7 @@
MAN+= fwohci.4 fwip.4 sbp.4
# machine-independent I2C devices
-MAN+= dbcool.4 lmtemp.4 spdmem.4
+MAN+= dbcool.4 lmtemp.4 sdtemp.4 spdmem.4
# machine-independent SPI devices
MAN += m25p.4 tm121temp.4
Index: src/sys/arch/i386/conf/ALL
diff -u src/sys/arch/i386/conf/ALL:1.197 src/sys/arch/i386/conf/ALL:1.198
--- src/sys/arch/i386/conf/ALL:1.197 Tue Apr 21 22:47:55 2009
+++ src/sys/arch/i386/conf/ALL Sat May 9 15:04:25 2009
@@ -1,4 +1,4 @@
-# $NetBSD: ALL,v 1.197 2009/04/21 22:47:55 nonaka Exp $
+# $NetBSD: ALL,v 1.198 2009/05/09 15:04:25 pgoyette Exp $
# From NetBSD: GENERIC,v 1.787 2006/10/01 18:37:54 bouyer Exp
#
# ALL machine description file
@@ -17,7 +17,7 @@
options INCLUDE_CONFIG_FILE # embed config file in kernel binary
-#ident "ALL-$Revision: 1.197 $"
+#ident "ALL-$Revision: 1.198 $"
maxusers 32 # estimated number of users
@@ -666,8 +666,9 @@
# VIA VT82C686A/VT8231 Hardware Monitor and Power Management Timer
viaenv* at pci? dev ? function ?
-# Serial Presence Detect capable memory modules
+# Serial Presence Detect capable memory modules and optional temp sensors
spdmem* at iic? addr 0x50
+sdtemp* at iic? addr 0x18
# I2O devices
iop* at pci? dev ? function ? # I/O processor
Index: src/sys/dev/i2c/files.i2c
diff -u src/sys/dev/i2c/files.i2c:1.23 src/sys/dev/i2c/files.i2c:1.24
--- src/sys/dev/i2c/files.i2c:1.23 Thu Oct 30 12:52:46 2008
+++ src/sys/dev/i2c/files.i2c Sat May 9 15:04:25 2009
@@ -1,4 +1,4 @@
-# $NetBSD: files.i2c,v 1.23 2008/10/30 12:52:46 nakayama Exp $
+# $NetBSD: files.i2c,v 1.24 2009/05/09 15:04:25 pgoyette Exp $
defflag opt_i2cbus.h I2C_SCAN
define i2cbus { }
@@ -106,6 +106,11 @@
attach spdmem at iic
file dev/i2c/spdmem.c spdmem
+# Memory Temp Sensor
+device sdtemp
+attach sdtemp at iic
+file dev/i2c/sdtemp.c sdtemp
+
# ADM1021
device admtemp: sysmon_envsys
attach admtemp at iic
Added files:
Index: src/share/man/man4/sdtemp.4
diff -u /dev/null src/share/man/man4/sdtemp.4:1.1
--- /dev/null Sat May 9 15:04:26 2009
+++ src/share/man/man4/sdtemp.4 Sat May 9 15:04:25 2009
@@ -0,0 +1,99 @@
+.\" $NetBSD: sdtemp.4,v 1.1 2009/05/09 15:04:25 pgoyette Exp $
+.\"
+.\" Copyright (c) 2008 The NetBSD Foundation, Inc.
+.\" All rights reserved.
+.\"
+.\" This code is derived from software contributed to The NetBSD Foundation
+.\" by Paul Goyette.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
+.\" ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+.\" TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+.\" PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
+.\" BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+.\" CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+.\" SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+.\" INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+.\" CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+.\" ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+.\" POSSIBILITY OF SUCH DAMAGE.
+.\"
+.Dd May 9, 2009
+.Dt SDTEMP 4
+.Os
+.Sh NAME
+.Nm sdtemp
+.Nd Microchip Technology MCP9805/98242 and compatible memory module
+temperature sensors
+.Sh SYNOPSIS
+.Cd "sdtemp0 at iic? addr 0x18"
+.Sh DESCRIPTION
+The
+.Nm
+driver provides support for the
+.Tn Microchip Technology
+MCP9805/98242 and other chips that conform to JEDEC Standard 21-C section
+4.7.
+Memory module temperature sensors are optional on DDR2 and DDR3 SDRAM DIMMs.
+Sensors provided by this driver are accessed through the
+.Xr envsys 4
+API.
+The on-chip thresholds for the Alarm Window and Critical level are
+accessed through the
+.Xr sysctl 8
+utility.
+.Pp
+The
+.Nm
+supports temperature ranges from -256 to +255 degrees C.
+.Sh HARDWARE
+Chips supported by the
+.Nm
+driver include:
+.Pp
+.Bl -item -offset indent
+.It
+.Tn Microchip Technology
+.Em MCP9805
+.It
+.Tn Microchip Technology
+.Em MCP98242
+.It
+.Tn Analog Devices
+.Em ADT7408
+.It
+.Tn NXP Semiconductors
+.Em SE97
+.It
+.Tn NXP Semiconductors
+.Em SE98
+.It
+.Tn STmicroelectronics
+.Em STTS424E02-DA/DN
+.It
+.Tn Catalyst
+.Em CAT34TS02
+.It
+.Tn Catalyst
+.Em CAT6095
+.El
+.Sh SEE ALSO
+.Xr envsys 4 ,
+.Xr envstat 8 ,
+.Xr sysctl 8
+.Sh HISTORY
+The
+.Nm
+device appeared in
+.Nx 6.0 .
+.Sh BUGS
+Interrupt support is unimplemented.
Index: src/sys/dev/i2c/sdtemp.c
diff -u /dev/null src/sys/dev/i2c/sdtemp.c:1.1
--- /dev/null Sat May 9 15:04:26 2009
+++ src/sys/dev/i2c/sdtemp.c Sat May 9 15:04:25 2009
@@ -0,0 +1,589 @@
+/* $NetBSD: sdtemp.c,v 1.1 2009/05/09 15:04:25 pgoyette Exp $ */
+
+/*
+ * Copyright (c) 2009 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to The NetBSD Foundation
+ * by Paul Goyette.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__KERNEL_RCSID(0, "$NetBSD: sdtemp.c,v 1.1 2009/05/09 15:04:25 pgoyette Exp $");
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/kmem.h>
+#include <sys/device.h>
+#include <sys/kernel.h>
+#include <sys/endian.h>
+#include <sys/sysctl.h>
+
+#include <dev/sysmon/sysmonvar.h>
+
+#include <dev/i2c/i2cvar.h>
+#include <dev/i2c/sdtemp_reg.h>
+
+struct sdtemp_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_resolution;
+ uint16_t sc_capability;
+ uint16_t sc_low_lim, sc_high_lim, sc_crit_lim;
+};
+
+static int sdtemp_match(device_t, cfdata_t, void *);
+static void sdtemp_attach(device_t, device_t, void *);
+
+CFATTACH_DECL_NEW(sdtemp, sizeof(struct sdtemp_softc),
+ sdtemp_match, sdtemp_attach, NULL, NULL);
+
+static void sdtemp_refresh(struct sysmon_envsys *, envsys_data_t *);
+#ifdef NOT_YET
+static int sdtemp_read_8(struct sdtemp_softc *, uint8_t, uint8_t *);
+static int sdtemp_write_8(struct sdtemp_softc *, uint8_t, uint8_t);
+#endif /* NOT YET */
+static int sdtemp_read_16(struct sdtemp_softc *, uint8_t, uint16_t *);
+static int sdtemp_write_16(struct sdtemp_softc *, uint8_t, uint16_t);
+static uint32_t sdtemp_decode_temp(struct sdtemp_softc *, uint16_t);
+static void sdtemp_set_thresh(struct sdtemp_softc *, int, uint16_t);
+static bool sdtemp_pmf_suspend(device_t PMF_FN_PROTO);
+static bool sdtemp_pmf_resume(device_t PMF_FN_PROTO);
+
+SYSCTL_SETUP_PROTO(sysctl_sdtemp_setup);
+static int sdtemp_sysctl_helper(SYSCTLFN_PROTO);
+
+struct sdtemp_dev_entry {
+ const uint16_t sdtemp_mfg_id;
+ const uint8_t sdtemp_dev_id;
+ const uint8_t sdtemp_rev_id;
+ const uint8_t sdtemp_resolution;
+ const char *sdtemp_desc;
+};
+
+/* sysctl stuff */
+static int hw_node = CTL_EOL;
+
+/*
+ * List of devices known to conform to JEDEC JC42.4
+ *
+ * NOTE: A non-negative value for resolution indicates that the sensor
+ * resolution is fixed at that number of fractional bits; a negative
+ * value indicates that the sensor needs to be configured. In either
+ * case, trip-point registers are fixed at two-bit (0.25C) resolution.
+ */
+static const struct sdtemp_dev_entry
+sdtemp_dev_table[] = {
+ { MAXIM_MANUFACTURER_ID, MAX_6604_DEVICE_ID, 0xff, 3,
+ "Maxim MAX604" },
+ { MCP_MANUFACTURER_ID, MCP_9805_DEVICE_ID, 0xff, 2,
+ "Microchip Tech MCP9805" },
+ { MCP_MANUFACTURER_ID, MCP_98242_DEVICE_ID, 0xff, -4,
+ "Microchip Tech MCP98242" },
+ { ADT_MANUFACTURER_ID, ADT_7408_DEVICE_ID, 0xff, 4,
+ "Analog Devices ADT7408" },
+ { NXP_MANUFACTURER_ID, NXP_SE97_DEVICE_ID, 0xff, 3,
+ "NXP Semiconductors SE97/SE98" },
+ { STTS_MANUFACTURER_ID, STTS_424E02_DEVICE_ID, 0x00, 2,
+ "STmicroelectronics STTS424E02-DA" },
+ { STTS_MANUFACTURER_ID, STTS_424E02_DEVICE_ID, 0x01, 2,
+ "STmicroelectronics STTS424E02-DN" },
+ { CAT_MANUFACTURER_ID, CAT_34TS02_DEVICE_ID, 0xff, 4,
+ "Catalyst CAT34TS02/CAT6095" },
+ { 0, 0, 0, 2, "Unknown" }
+};
+
+static int
+sdtemp_lookup(uint16_t mfg, uint16_t dev, uint16_t rev)
+{
+ int i;
+
+ for (i = 0; sdtemp_dev_table[i].sdtemp_mfg_id; i++)
+ if (sdtemp_dev_table[i].sdtemp_mfg_id == mfg &&
+ sdtemp_dev_table[i].sdtemp_dev_id == dev &&
+ (sdtemp_dev_table[i].sdtemp_rev_id == 0xff ||
+ sdtemp_dev_table[i].sdtemp_rev_id == rev))
+ break;
+
+ return i;
+}
+
+static int
+sdtemp_match(device_t parent, cfdata_t cf, void *aux)
+{
+ struct i2c_attach_args *ia = aux;
+ uint16_t mfgid, devid;
+ struct sdtemp_softc sc;
+ int i, error;
+
+ sc.sc_tag = ia->ia_tag;
+ sc.sc_address = ia->ia_addr;
+
+ if ((ia->ia_addr & SDTEMP_ADDRMASK) != SDTEMP_ADDR)
+ return 0;
+
+ /* Verify that we can read the manufacturer ID & Device ID */
+ iic_acquire_bus(sc.sc_tag, 0);
+ error = sdtemp_read_16(&sc, SDTEMP_REG_MFG_ID, &mfgid) |
+ sdtemp_read_16(&sc, SDTEMP_REG_DEV_REV, &devid);
+ iic_release_bus(sc.sc_tag, 0);
+
+ if (error)
+ return 0;
+
+ i = sdtemp_lookup(mfgid, devid >> 8, devid & 0xff);
+ if (sdtemp_dev_table[i].sdtemp_mfg_id == 0) {
+ aprint_debug("sdtemp: No match for mfg 0x%04x dev 0x%02x "
+ "rev 0x%02x at address 0x%02x\n", mfgid, devid >> 8,
+ devid & 0xff, sc.sc_address);
+ return 0;
+ }
+
+ return 1;
+}
+
+static void
+sdtemp_attach(device_t parent, device_t self, void *aux)
+{
+ struct sdtemp_softc *sc = device_private(self);
+ struct i2c_attach_args *ia = aux;
+ const struct sysctlnode *node = NULL;
+ uint16_t mfgid, devid;
+ int32_t dev_sysctl_num;
+ int i, error;
+
+ sc->sc_tag = ia->ia_tag;
+ sc->sc_address = ia->ia_addr;
+ sc->sc_dev = self;
+
+ iic_acquire_bus(sc->sc_tag, 0);
+ if ((error = sdtemp_read_16(sc, SDTEMP_REG_MFG_ID, &mfgid)) != 0 ||
+ (error = sdtemp_read_16(sc, SDTEMP_REG_DEV_REV, &devid)) != 0) {
+ iic_release_bus(sc->sc_tag, I2C_F_POLL);
+ aprint_error(": attach error %d\n", error);
+ return;
+ }
+ i = sdtemp_lookup(mfgid, devid >> 8, devid & 0xff);
+ sc->sc_resolution =
+ sdtemp_dev_table[i].sdtemp_resolution;
+
+ aprint_naive(": Temp Sensor\n");
+ aprint_normal(": %s Temp Sensor\n", sdtemp_dev_table[i].sdtemp_desc);
+
+ if (sdtemp_dev_table[i].sdtemp_mfg_id == 0)
+ aprint_debug_dev(self,
+ "mfg 0x%04x dev 0x%02x rev 0x%02x at addr 0x%02x\n",
+ mfgid, devid >> 8, devid & 0xff, ia->ia_addr);
+
+ /*
+ * Alarm capability is required; if not present, this is likely
+ * not a real sdtemp device.
+ */
+ error = sdtemp_read_16(sc, SDTEMP_REG_CAPABILITY, &sc->sc_capability);
+ if (error != 0 || (sc->sc_capability & SDTEMP_CAP_HAS_ALARM) == 0) {
+ iic_release_bus(sc->sc_tag, 0);
+ aprint_error_dev(self,
+ "required alarm capability not present!\n");
+ return;
+ }
+ /* Set the configuration to defaults. */
+ error = sdtemp_write_16(sc, SDTEMP_REG_CONFIG, 0);
+ if (error != 0) {
+ iic_release_bus(sc->sc_tag, 0);
+ aprint_error_dev(self, "error %d writing config register\n",
+ error);
+ return;
+ }
+ /* If variable resolution, set to max */
+ if (sc->sc_resolution < 0) {
+ sc->sc_resolution = ~sc->sc_resolution;
+ error = sdtemp_write_16(sc, SDTEMP_REG_RESOLUTION,
+ sc->sc_resolution & 0x3);
+ if (error != 0) {
+ iic_release_bus(sc->sc_tag, 0);
+ aprint_error_dev(self,
+ "error %d writing resolution register\n", error);
+ return;
+ } else
+ sc->sc_resolution++;
+ }
+ iic_release_bus(sc->sc_tag, 0);
+
+ /* Hook us into the sysmon_envsys subsystem */
+ sc->sc_sme = sysmon_envsys_create();
+ sc->sc_sensor = kmem_zalloc(sizeof(envsys_data_t), KM_NOSLEEP);
+ if (!sc->sc_sensor) {
+ aprint_error_dev(self, "unable to allocate sc_sensor\n");
+ goto bad2;
+ }
+
+ /* Initialize sensor data. */
+ sc->sc_sensor->units = ENVSYS_STEMP;
+ sc->sc_sensor->state = ENVSYS_SINVALID;
+#ifdef ENVSYS_FMONLIMITS
+ sc->sc_sensor->flags |= ENVSYS_FMONLIMITS;
+#else
+ sc->sc_sensor->flags |= ENVSYS_FMONWARNOVER | ENVSYS_FMONWARNUNDER |
+ ENVSYS_FMONCRITOVER;
+#endif
+ (void)strlcpy(sc->sc_sensor->desc, device_xname(self),
+ sizeof(sc->sc_sensor->desc));
+
+ /* Now attach the sensor */
+ if (sysmon_envsys_sensor_attach(sc->sc_sme, sc->sc_sensor)) {
+ aprint_error_dev(self, "unable to attach sensor\n");
+ goto bad;
+ }
+
+ /* Register the device */
+ sc->sc_sme->sme_name = device_xname(self);
+ sc->sc_sme->sme_cookie = sc;
+ sc->sc_sme->sme_refresh = sdtemp_refresh;
+
+ error = sysmon_envsys_register(sc->sc_sme);
+ if (error) {
+ aprint_error_dev(self, "error %d registering with sysmon\n",
+ error);
+ goto bad;
+ }
+
+ if (!pmf_device_register(self, sdtemp_pmf_suspend, sdtemp_pmf_resume))
+ aprint_error_dev(self, "couldn't establish power handler\n");
+
+
+ /* Retrieve and display hardware monitor limits */
+ i = 0;
+ aprint_normal_dev(self, "");
+ iic_acquire_bus(sc->sc_tag, 0);
+ if (sdtemp_read_16(sc, SDTEMP_REG_LOWER_LIM, &sc->sc_low_lim) == 0 &&
+ sc->sc_low_lim != 0) {
+ aprint_normal("low limit %d ", sc->sc_low_lim);
+ i++;
+ }
+ if (sdtemp_read_16(sc, SDTEMP_REG_UPPER_LIM, &sc->sc_high_lim) == 0 &&
+ sc->sc_high_lim != 0) {
+ aprint_normal("high limit %d ", sc->sc_high_lim);
+ i++;
+ }
+ if (sdtemp_read_16(sc, SDTEMP_REG_CRIT_LIM, &sc->sc_crit_lim) == 0 &&
+ sc->sc_crit_lim != 0) {
+ aprint_normal("critical limit %d ", sc->sc_crit_lim);
+ i++;
+ }
+ iic_release_bus(sc->sc_tag, 0);
+ if (i == 0)
+ aprint_normal("no hardware limits set\n");
+ else
+ aprint_normal("\n");
+
+ /* Create our sysctl tree. We just store the softc pointer for
+ * now; the sysctl_helper function will take care of creating
+ * a real string on the fly. We explicitly specify the new nodes'
+ * sysctl_num in order to identify the specific limit rather than
+ * using CTL_CREATE; this is OK since we're the only place that
+ * touches the sysctl tree for the device.
+ */
+
+ if (hw_node != CTL_EOL)
+ sysctl_createv(NULL, 0, NULL, &node, 0,
+ CTLTYPE_NODE, device_xname(self),
+ NULL, NULL, 0, NULL, 0,
+ CTL_HW, CTL_CREATE, CTL_EOL);
+ if (node != NULL) {
+ dev_sysctl_num = node->sysctl_num;
+ sysctl_createv(NULL, 0, NULL, &node, 0,
+ CTLTYPE_NODE, "limits",
+ SYSCTL_DESCR("temperature limits"),
+ NULL, 0, NULL, 0,
+ CTL_HW, node->sysctl_num, CTL_CREATE, CTL_EOL);
+ }
+ if (node != NULL) {
+ sysctl_createv(NULL, 0, NULL, NULL, CTLFLAG_READWRITE,
+ CTLTYPE_INT, "low_limit",
+ SYSCTL_DESCR("alarm window lower limit"),
+ sdtemp_sysctl_helper, 0, sc, sizeof(int),
+ CTL_HW, dev_sysctl_num, node->sysctl_num,
+ SDTEMP_REG_LOWER_LIM, CTL_EOL);
+ sysctl_createv(NULL, 0, NULL, NULL, CTLFLAG_READWRITE,
+ CTLTYPE_INT, "high_limit",
+ SYSCTL_DESCR("alarm window upper limit"),
+ sdtemp_sysctl_helper, 0, sc, sizeof(int),
+ CTL_HW, dev_sysctl_num, node->sysctl_num,
+ SDTEMP_REG_UPPER_LIM, CTL_EOL);
+ sysctl_createv(NULL, 0, NULL, NULL, CTLFLAG_READWRITE,
+ CTLTYPE_INT, "crit_limit",
+ SYSCTL_DESCR("critical alarm limit"),
+ sdtemp_sysctl_helper, 0, sc, sizeof(int),
+ CTL_HW, dev_sysctl_num, node->sysctl_num,
+ SDTEMP_REG_CRIT_LIM, CTL_EOL);
+ }
+ return;
+
+bad:
+ kmem_free(sc->sc_sensor, sizeof(envsys_data_t));
+bad2:
+ sysmon_envsys_destroy(sc->sc_sme);
+}
+
+/* Set up the threshold registers */
+static void
+sdtemp_set_thresh(struct sdtemp_softc *sc, int reg, uint16_t val)
+{
+ int error;
+ uint16_t *valp;
+
+ switch (reg) {
+ case SDTEMP_REG_LOWER_LIM:
+ valp = &sc->sc_low_lim;
+ break;
+ case SDTEMP_REG_UPPER_LIM:
+ valp = &sc->sc_high_lim;
+ break;
+ case SDTEMP_REG_CRIT_LIM:
+ valp = &sc->sc_crit_lim;
+ break;
+ default:
+ return;
+ }
+
+ iic_acquire_bus(sc->sc_tag, 0);
+ error = sdtemp_write_16(sc, reg, (val << 4) & SDTEMP_TEMP_MASK);
+ iic_release_bus(sc->sc_tag, 0);
+
+ if (error == 0)
+ *valp = val;
+}
+
+#ifdef NOT_YET /* All registers on these sensors are 16-bits */
+
+/* Read a 8-bit value from a register */
+static int
+sdtemp_read_8(struct sdtemp_softc *sc, uint8_t reg, uint8_t *valp)
+{
+ int error;
+
+ error = iic_exec(sc->sc_tag, I2C_OP_READ_WITH_STOP,
+ sc->sc_address, ®, 1, valp, sizeof(*valp), 0);
+
+ return error;
+}
+
+static int
+sdtemp_write_8(struct sdtemp_softc *sc, uint8_t reg, uint8_t val)
+{
+ return iic_exec(sc->sc_tag, I2C_OP_WRITE_WITH_STOP,
+ sc->sc_address, ®, 1, &val, sizeof(val), 0);
+}
+#endif /* NOT_YET */
+
+/* Read a 16-bit value from a register */
+static int
+sdtemp_read_16(struct sdtemp_softc *sc, uint8_t reg, uint16_t *valp)
+{
+ int error;
+
+ error = iic_exec(sc->sc_tag, I2C_OP_READ_WITH_STOP,
+ sc->sc_address, ®, 1, valp, sizeof(*valp), 0);
+ if (error)
+ return error;
+
+ *valp = be16toh(*valp);
+
+ return 0;
+}
+
+static int
+sdtemp_write_16(struct sdtemp_softc *sc, uint8_t reg, uint16_t val)
+{
+ uint16_t temp;
+
+ temp = htobe16(val);
+ return iic_exec(sc->sc_tag, I2C_OP_WRITE_WITH_STOP,
+ sc->sc_address, ®, 1, &temp, sizeof(temp), 0);
+}
+
+static uint32_t
+sdtemp_decode_temp(struct sdtemp_softc *sc, uint16_t temp)
+{
+ uint32_t val;
+ int32_t stemp;
+
+ /* Get only the temperature bits */
+ temp &= SDTEMP_TEMP_MASK;
+
+ /* If necessary, extend the sign bit */
+ if ((sc->sc_capability & SDTEMP_CAP_WIDER_RANGE) &&
+ (temp & SDTEMP_TEMP_NEGATIVE))
+ temp |= SDTEMP_TEMP_SIGN_EXT;
+
+ /* Mask off only bits valid within current resolution */
+ temp &= ~(0xf >> sc->sc_resolution);
+
+ /* Treat as signed and extend to 32-bits */
+ stemp = (int16_t)temp;
+
+ /* Now convert from 0.0625 (1/16) deg C increments to microKelvins */
+ val = (stemp * 62500) + 273150000;
+
+ return val;
+}
+
+static void
+sdtemp_refresh(struct sysmon_envsys *sme, envsys_data_t *edata)
+{
+ struct sdtemp_softc *sc = sme->sme_cookie;
+ uint16_t val;
+ int error;
+
+ iic_acquire_bus(sc->sc_tag, 0);
+ error = sdtemp_read_16(sc, SDTEMP_REG_AMBIENT_TEMP, &val);
+ iic_release_bus(sc->sc_tag, 0);
+
+ if (error) {
+ edata->state = ENVSYS_SINVALID;
+ return;
+ }
+
+ edata->value_cur = sdtemp_decode_temp(sc, val);
+
+ /* Now check for limits */
+ if (val & SDTEMP_ABOVE_CRIT)
+ edata->state = ENVSYS_SCRITOVER;
+ else if (val & SDTEMP_ABOVE_UPPER)
+ edata->state = ENVSYS_SWARNOVER;
+ else if (val & SDTEMP_BELOW_LOWER)
+ edata->state = ENVSYS_SWARNUNDER;
+ else
+ edata->state = ENVSYS_SVALID;
+}
+
+SYSCTL_SETUP(sysctl_sdtemp_setup, "sysctl hw.sdtemp subtree setup")
+{
+ const struct sysctlnode *node;
+
+ if (sysctl_createv(clog, 0, NULL, &node,
+ CTLFLAG_PERMANENT,
+ CTLTYPE_NODE, "hw", NULL,
+ NULL, 0, NULL, 0,
+ CTL_HW, CTL_EOL) != 0)
+ return;
+
+ hw_node = node->sysctl_num;
+}
+
+/*
+ * The sysctl node actually contains just a pointer to our softc. We
+ * extract the individual limits on the fly, and if necessary replace
+ * the value with the new value specified by the user.
+ *
+ * Inspired by similar code in sys/net/if_tap.c
+ */
+static int
+sdtemp_sysctl_helper(SYSCTLFN_ARGS)
+{
+ struct sdtemp_softc *sc;
+ struct sysctlnode node;
+ int error, reg;
+ uint16_t reg_value;
+ int lim_value;
+
+ node = *rnode;
+ sc = node.sysctl_data;
+ reg = node.sysctl_num;
+
+ iic_acquire_bus(sc->sc_tag, 0);
+ error = sdtemp_read_16(sc, reg, ®_value);
+ iic_release_bus(sc->sc_tag, 0);
+
+#ifdef DEBUG
+ aprint_verbose_dev(sc->sc_dev, "(%s) sc %p reg %d val 0x%04x err %d\n",
+ __func__, sc, reg, reg_value, error);
+#endif
+
+ if (error == 0) {
+ lim_value = reg_value >> 4;
+ node.sysctl_data = &lim_value;
+ error = sysctl_lookup(SYSCTLFN_CALL(&node));
+ }
+ if (error || newp == NULL)
+ return (error);
+
+ /*
+ * We're being asked to update the sysctl value, so retrieve
+ * the new value and check for valid range
+ */
+ lim_value = *(int *)node.sysctl_data;
+ if (lim_value < -256 || lim_value > 255)
+ return (EINVAL);
+
+ sdtemp_set_thresh(sc, reg, (uint16_t)lim_value);
+
+ return (0);
+}
+
+/*
+ * power management functions
+ *
+ * We go into "shutdown" mode at suspend time, and return to normal
+ * mode upon resume. This reduces power consumption by disabling
+ * the A/D converter.
+ */
+
+static bool
+sdtemp_pmf_suspend(device_t dev PMF_FN_ARGS)
+{
+ struct sdtemp_softc *sc = device_private(dev);
+ int error;
+ uint16_t config;
+
+ iic_acquire_bus(sc->sc_tag, 0);
+ error = sdtemp_read_16(sc, SDTEMP_REG_CONFIG, &config);
+ if (error == 0) {
+ config |= SDTEMP_CONFIG_SHUTDOWN_MODE;
+ error = sdtemp_write_16(sc, SDTEMP_REG_CONFIG, config);
+ }
+ iic_release_bus(sc->sc_tag, 0);
+ return (error == 0);
+}
+
+static bool
+sdtemp_pmf_resume(device_t dev PMF_FN_ARGS)
+{
+ struct sdtemp_softc *sc = device_private(dev);
+ int error;
+ uint16_t config;
+
+ iic_acquire_bus(sc->sc_tag, 0);
+ error = sdtemp_read_16(sc, SDTEMP_REG_CONFIG, &config);
+ if (error == 0) {
+ config &= ~SDTEMP_CONFIG_SHUTDOWN_MODE;
+ error = sdtemp_write_16(sc, SDTEMP_REG_CONFIG, config);
+ }
+ iic_release_bus(sc->sc_tag, 0);
+ return (error == 0);
+}
Index: src/sys/dev/i2c/sdtemp_reg.h
diff -u /dev/null src/sys/dev/i2c/sdtemp_reg.h:1.1
--- /dev/null Sat May 9 15:04:26 2009
+++ src/sys/dev/i2c/sdtemp_reg.h Sat May 9 15:04:25 2009
@@ -0,0 +1,117 @@
+/* $NetBSD: sdtemp_reg.h,v 1.1 2009/05/09 15:04:25 pgoyette Exp $ */
+
+/*
+ * Copyright (c) 2009 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to The NetBSD Foundation
+ * by Paul Goyette.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef _DEV_I2C_SDTEMPREG_H
+#define _DEV_I2C_SDTEMPREG_H
+
+/*
+ * Following definitions derived from JEDEC Standard 21-C section 4.7
+ * available at http://www.jedec.org/download/search/4_07R15.pdf
+ */
+#define SDTEMP_ADDRMASK 0x78
+#define SDTEMP_ADDR 0x18 /* I2C address 001 1xxx */
+
+#define SDTEMP_REG_CAPABILITY 0x00
+#define SDTEMP_REG_CONFIG 0x01
+#define SDTEMP_REG_UPPER_LIM 0x02
+#define SDTEMP_REG_LOWER_LIM 0x03
+#define SDTEMP_REG_CRIT_LIM 0x04
+#define SDTEMP_REG_AMBIENT_TEMP 0x05
+#define SDTEMP_REG_MFG_ID 0x06
+#define SDTEMP_REG_DEV_REV 0x07
+#define SDTEMP_REG_RESOLUTION 0x08
+
+#define SDTEMP_CAP_HAS_ALARM 0x0001
+#define SDTEMP_CAP_ACCURACY_1C 0x0002
+#define SDTEMP_CAP_WIDER_RANGE 0x0004
+#define SDTEMP_CAP_RESOLUTION 0x0018
+#define SDTEMP_CAP_RES_SHIFT 3
+
+#define SDTEMP_CONFIG_EVENT_MODE 0x0001
+#define SDTEMP_CONFIG_EVENT_POL_AH 0x0002
+#define SDTEMP_CONFIG_EVENT_CRIT_ONLY 0x0004
+#define SDTEMP_CONFIG_EVENT_ENABLED 0x0008
+#define SDTEMP_CONFIG_EVENT_STATUS 0x0010
+#define SDTEMP_CONFIG_INT_CLEAR 0x0020
+#define SDTEMP_CONFIG_WINDOW_LOCKED 0x0040
+#define SDTEMP_CONFIG_CRITICAL_LOCKED 0x0080
+#define SDTEMP_CONFIG_SHUTDOWN_MODE 0x0100
+#define SDTEMP_CONFIG_HYSTERESIS 0x0600
+
+#define SDTEMP_HYSTERESIS_NONE 0x0000
+#define SDTEMP_HYSTERESIS_15 0x0200
+#define SDTEMP_HYSTERESIS_30 0x0400
+#define SDTEMP_HYSTERESIS_60 0x0600
+
+/*
+ * Temperature is a 12-bit value in the range of -256 <= x < +256 degrees.
+ * Maximum resolution is 0.0625C (1/16th degree, 4 bits), but some devices
+ * may have only 0.2500C or 0.1250C (1 or 2 bits), and some devices may not
+ * be able to represent negative values (not that we'd expect them, anyway).
+ */
+#define SDTEMP_TEMP_MASK 0x0FFF
+#define SDTEMP_TEMP_NEGATIVE 0x1000
+#define SDTEMP_TEMP_SIGN_EXT 0xF000
+
+/*
+ * Status bits set in MCP98XX_REG_AMBIENT_TEMP only
+ */
+#define SDTEMP_ABOVE_CRIT 0x8000
+#define SDTEMP_ABOVE_UPPER 0x4000
+#define SDTEMP_BELOW_LOWER 0x2000
+
+/*
+ * Devices known to conform to JEDEC JC42.4
+ */
+#define MAXIM_MANUFACTURER_ID 0x004D
+#define MAX_6604_DEVICE_ID 0x3E
+
+#define MCP_MANUFACTURER_ID 0x0054
+#define MCP_9805_DEVICE_ID 0x00
+#define MCP_98242_DEVICE_ID 0x20
+
+/* According to datasheets, SE97 and SE98 have same ID */
+
+#define NXP_MANUFACTURER_ID 0x1131
+#define NXP_SE97_DEVICE_ID 0xA1
+
+#define ADT_MANUFACTURER_ID 0x11D4
+#define ADT_7408_DEVICE_ID 0x80
+
+#define STTS_MANUFACTURER_ID 0x104A
+#define STTS_424E02_DEVICE_ID 0x00
+
+/* According to datasheets, both the CAT6095 and CAT34TS02 have the same ID */
+
+#define CAT_MANUFACTURER_ID 0x1B09
+#define CAT_34TS02_DEVICE_ID 0x08
+
+#endif /* _DEV_I2C_SDTEMPREG_H */