Source-Changes-HG archive

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]

[src/trunk]: src/sys/dev/i2c Add display and setting of chip temperature limi...



details:   https://anonhg.NetBSD.org/src/rev/c22486e6a446
branches:  trunk
changeset: 342651:c22486e6a446
user:      jdc <jdc%NetBSD.org@localhost>
date:      Sun Jan 03 17:27:26 2016 +0000

description:
Add display and setting of chip temperature limits for envsys(4).
Different chips are recognised where possible, and the appropriate limits
are displayed/settable.

diffstat:

 sys/dev/i2c/adm1021.c |  682 ++++++++++++++++++++++++++++++++++++++++++++++++-
 1 files changed, 662 insertions(+), 20 deletions(-)

diffs (truncated from 786 to 300 lines):

diff -r d681501e4e89 -r c22486e6a446 sys/dev/i2c/adm1021.c
--- a/sys/dev/i2c/adm1021.c     Sun Jan 03 15:38:29 2016 +0000
+++ b/sys/dev/i2c/adm1021.c     Sun Jan 03 17:27:26 2016 +0000
@@ -1,4 +1,4 @@
-/*     $NetBSD: adm1021.c,v 1.10 2015/12/07 20:59:44 jdc Exp $ */
+/*     $NetBSD: adm1021.c,v 1.11 2016/01/03 17:27:26 jdc Exp $ */
 /*     $OpenBSD: adm1021.c,v 1.27 2007/06/24 05:34:35 dlg Exp $        */
 
 /*
@@ -17,8 +17,28 @@
  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  */
 
+/*
+ * Driver for ADM1021 and compatible temperature sensors, including ADM1021,
+ * ADM1021A, ADM1023, ADM1032, GL523SM, G781, LM84, MAX1617, MAX1617A,
+ * NE1617A, and Xeon embedded temperature sensors.
+ *
+ * Some sensors differ from the ADM1021/MAX1617/NE1617A:
+ *                         ADM1021A ADM1023 ADM1032 G781 LM84 MAX1617A
+ *   company/revision reg  X        X       X       X         X
+ *   no negative temps     X        X       X       X
+ *   11-bit remote temp             X       X       X
+ *   no low limits                                       X
+ *   therm (high) limits                    X       X
+ *
+ * Registers 0x00 to 0x0f have separate read/write addresses, but
+ * registers 0x10 and above have the same read/write address.
+ * The 11-bit (extended) temperature consists of a separate register with
+ * 3 valid bits that are always added to the external temperature (even if
+ * the temperature is negative).
+ */
+
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: adm1021.c,v 1.10 2015/12/07 20:59:44 jdc Exp $");
+__KERNEL_RCSID(0, "$NetBSD: adm1021.c,v 1.11 2016/01/03 17:27:26 jdc Exp $");
 
 #include <sys/param.h>
 #include <sys/systm.h>
@@ -27,40 +47,102 @@
 
 #include <dev/i2c/i2cvar.h>
 
+/* Registers */
+#define ADM1021_INT_TEMP       0x00    /* Internal temperature value */
+#define ADM1021_EXT_TEMP       0x01    /* External temperature value */
+#define ADM1021_STATUS         0x02    /* Status */
+#define ADM1021_CONFIG_READ    0x03    /* Read configuration */
+#define ADM1021_CONV_RATE_READ 0x04    /* Read conversion rate */
+#define ADM1021_INT_HIGH_READ  0x05    /* Read internal high limit */
+#define ADM1021_INT_LOW_READ   0x06    /* Read internal low limit */
+#define ADM1021_EXT_HIGH_READ  0x07    /* Read external high limit */
+#define ADM1021_EXT_LOW_READ   0x08    /* Read external low limit */
+#define ADM1021_CONFIG_WRITE   0x09    /* Write configuration */
+#define ADM1021_CONV_RATE_WRITE 0x0a   /* Write conversion rate */
+#define ADM1021_INT_HIGH_WRITE 0x0b    /* Write internal high limit */
+#define ADM1021_INT_LOW_WRITE  0x0c    /* Write internal low limit */
+#define ADM1021_EXT_HIGH_WRITE 0x0d    /* Write external high limit */
+#define ADM1021_EXT_LOW_WRITE  0x0e    /* Write external low limit */
+#define ADM1021_ONE_SHOT       0x0f    /* One shot command */
+#define ADM1023_EXT_TEMP2      0x10    /* R/W external temp low byte */
+#define ADM1023_EXT_TEMP_OFF   0x11    /* R/W external temp offset */
+#define ADM1023_EXT_TEMP_OFF2  0x12    /* R/W external temp off low byte */
+#define ADM1023_EXT_HIGH2      0x13    /* R/W external high lim low byte */
+#define ADM1023_EXT_LOW2       0x14    /* R/W external low lim low byte */
+#define ADM1032_EXT_THERM      0x19    /* R/W external Therm (high) limit */
+#define ADM1032_INT_THERM      0x20    /* R/W internal Therm (high) limit */
+#define ADM1032_THERM_HYST     0x21    /* R/W Therm hysteris */
+#define ADM1032_ALERT_QUEUE    0x22    /* R/W consecutive alert queue */
+#define ADM1021_COMPANY                0xfe    /* Company ID */
+#define ADM1021_DIE_REVISION   0xff    /* Die revision code */
 
-/* ADM 1021 registers */
-#define ADM1021_INT_TEMP       0x00
-#define ADM1021_EXT_TEMP       0x01
-#define ADM1021_STATUS         0x02
+/* Register values */
+#define ADM1021_CONFIG_RUN     0x40
+
 #define ADM1021_STATUS_INVAL   0x7f
-#define ADM1021_STATUS_NOEXT   0x40
-#define ADM1021_CONFIG_READ    0x03
-#define ADM1021_CONFIG_WRITE   0x09
-#define ADM1021_CONFIG_RUN     0x40
-#define ADM1021_COMPANY                0xfe    /* contains 0x41 */
-#define ADM1021_DIE_REVISION   0xff
+#define ADM1021_STATUS_NOEXT   0x40    /* External diode is open-circuit */
+
+#define ADM1023_EXT2_SHIFT     5
+#define ADM1023_EXT2_MASK      0x07
+
+#define ADM1021_COMPANY_ADM    0x41    /* 'A' */
+#define ADM1021_COMPANY_GMT    0x47    /* 'G' */
+#define ADM1021_COMPANY_MAXIM  0x4d    /* 'M' */
+
+#define ADM1021_REV_1021       0x00
+#define ADM1021_REV_1021A      0x30
+#define ADM1021_REV_MASK       0xf0
 
 /* Sensors */
 #define ADMTEMP_INT            0
 #define ADMTEMP_EXT            1
 #define ADMTEMP_NUM_SENSORS    2
 
+#define ADMTEMP_MAX_NEG                -65
+#define ADMTEMP_MAX_POS                127
+#define ADMTEMP_LOW_DEFAULT    0xc9    /* (-55)        */
+
+/* Limit registers might read 0xff, so we ignore them if they do */
+#define ADMTEMP_LIM_INVAL      -1      /* 0xff */
+
+#define ADMTEMP_NAMELEN                9       /* Maximum name length + 1 */
+
 struct admtemp_softc {
        i2c_tag_t       sc_tag;
        i2c_addr_t      sc_addr;
 
-       int             sc_noexternal;
+       int             sc_flags;
+       int             sc_noexternal, sc_noneg, sc_nolow;
+       int             sc_ext11, sc_therm;
        struct sysmon_envsys *sc_sme;
        envsys_data_t sc_sensor[ADMTEMP_NUM_SENSORS];
+       int sc_setdef[ADMTEMP_NUM_SENSORS];
+       u_int8_t sc_highlim[ADMTEMP_NUM_SENSORS];
+       u_int8_t sc_lowlim[ADMTEMP_NUM_SENSORS];
+       u_int8_t sc_highlim2, sc_lowlim2;
+       u_int8_t sc_thermlim[ADMTEMP_NUM_SENSORS];
 };
 
 int    admtemp_match(device_t, cfdata_t, void *);
 void   admtemp_attach(device_t, device_t, void *);
 void   admtemp_refresh(struct sysmon_envsys *, envsys_data_t *);
+void   admtemp_getlim_1021(struct sysmon_envsys *, envsys_data_t *,
+                       sysmon_envsys_lim_t *, uint32_t *);
+void   admtemp_getlim_1023(struct sysmon_envsys *, envsys_data_t *,
+                       sysmon_envsys_lim_t *, uint32_t *);
+void   admtemp_getlim_1032(struct sysmon_envsys *, envsys_data_t *,
+                       sysmon_envsys_lim_t *, uint32_t *);
+void   admtemp_setlim_1021(struct sysmon_envsys *, envsys_data_t *,
+                       sysmon_envsys_lim_t *, uint32_t *);
+void   admtemp_setlim_1023(struct sysmon_envsys *, envsys_data_t *,
+                       sysmon_envsys_lim_t *, uint32_t *);
+void   admtemp_setlim_1032(struct sysmon_envsys *, envsys_data_t *,
+                       sysmon_envsys_lim_t *, uint32_t *);
 
 CFATTACH_DECL_NEW(admtemp, sizeof(struct admtemp_softc),
        admtemp_match, admtemp_attach, NULL, NULL);
 
+/* XXX: add flags for compats to admtemp_setflags() */
 static const char * admtemp_compats[] = {
        "i2c-max1617",
        NULL
@@ -97,20 +179,127 @@
        return 0;
 }
 
+/*
+ * Set flags based on chip type for direct config, or by testing for
+ * indirect config.
+ *
+ * LM84, MAX1617, and NE1617A don't have company/revision registers.
+ * If we can't read the company register, we'll check the 
+ * internal low limit to see if we have an LM84.
+ *
+ * To check if an ADM chip has 11-bit sensors, we'll write 0.125
+ * to the external temperature limit low byte register and read it
+ * back (because we can't tell from the id/rev).
+ *
+ * To check if an ADM chip has a Therm output, we check that we
+ * read 0x55 (default value) from the external therm limit.
+ *
+ * If an ADM chip doesn't have 11-bit sensors, check the revision to
+ * determine if it handles negative temperatures.
+ */
+static void
+admtemp_setflags(struct admtemp_softc *sc, struct i2c_attach_args *ia,
+    u_int8_t* comp, u_int8_t *rev, char* name)
+{
+       u_int8_t cmd, data, tmp;
+       int i;
+
+       *comp = 0;
+       *rev = 0;
+
+       cmd = ADM1021_COMPANY;
+       iic_exec(sc->sc_tag, I2C_OP_READ_WITH_STOP,
+           sc->sc_addr, &cmd, sizeof cmd, comp, sizeof comp, 0);
+
+       cmd = ADM1021_DIE_REVISION;
+       iic_exec(sc->sc_tag, I2C_OP_READ_WITH_STOP,
+           sc->sc_addr, &cmd, sizeof cmd, rev, sizeof rev, 0);
+
+       sc->sc_noneg = 1;
+       sc->sc_nolow = 0;
+       sc->sc_ext11 = 0;
+       sc->sc_therm = 0;
+
+       /* Direct config */
+       for (i = 0; i < ia->ia_ncompat; i++) {
+               if (strcmp("i2c-max1617", ia->ia_compat[i]) == 0) {
+                       sc->sc_noneg = 0;
+                       strlcpy(name, "MAX1617A", ADMTEMP_NAMELEN);
+                       return;
+               }
+       }
+
+       /* Indirect config */
+       if (*comp == 0) {
+               sc->sc_noneg = 0;
+               cmd = ADM1021_INT_LOW_READ;
+               if (iic_exec(sc->sc_tag, I2C_OP_READ_WITH_STOP, sc->sc_addr,
+                   &cmd, sizeof cmd, &comp, sizeof comp, 0) == 0 &&
+                   data != ADMTEMP_LOW_DEFAULT) {
+                       sc->sc_nolow = 1;
+                       strlcpy(name, "LM84", ADMTEMP_NAMELEN);
+               } else
+                       strlcpy(name, "MAX1617", ADMTEMP_NAMELEN);
+       }
+
+       if (*comp == ADM1021_COMPANY_MAXIM) {
+               sc->sc_noneg = 0;
+               strlcpy(name, "MAX1617A", ADMTEMP_NAMELEN);
+       }
+
+       if (*comp == ADM1021_COMPANY_GMT) {
+               sc->sc_ext11 = 1;
+               sc->sc_therm = 1;
+               strlcpy(name, "G781", ADMTEMP_NAMELEN);
+       }
+
+       if (*comp == ADM1021_COMPANY_ADM) {
+               cmd = ADM1023_EXT_HIGH2;
+               if (iic_exec(sc->sc_tag, I2C_OP_READ_WITH_STOP, sc->sc_addr,
+                   &cmd, sizeof cmd, &data, sizeof data, 0) == 0) {
+                       tmp = 1 << ADM1023_EXT2_SHIFT;
+                       iic_exec(sc->sc_tag, I2C_OP_WRITE_WITH_STOP,
+                           sc->sc_addr, &cmd, sizeof cmd,
+                           &tmp, sizeof tmp, 0);
+                       if (iic_exec(sc->sc_tag, I2C_OP_READ_WITH_STOP,
+                           sc->sc_addr, &cmd, sizeof cmd,
+                           &tmp, sizeof tmp, 0) == 0 &&
+                           tmp == 1 << ADM1023_EXT2_SHIFT) {
+                               sc->sc_ext11 = 1;
+                               strlcpy(name, "ADM1023", ADMTEMP_NAMELEN);
+                       }
+                       iic_exec(sc->sc_tag, I2C_OP_WRITE_WITH_STOP,
+                           sc->sc_addr, &cmd, sizeof cmd,
+                           &data, sizeof data, 0);
+               }
+               cmd = ADM1032_EXT_THERM;
+               if (sc->sc_ext11 &&
+                   iic_exec(sc->sc_tag, I2C_OP_READ_WITH_STOP, sc->sc_addr,
+                   &cmd, sizeof cmd, &data, sizeof data, 0) == 0 &&
+                   data == 0x55) {
+                       sc->sc_therm = 1;
+                       strlcpy(name, "ADM1032", ADMTEMP_NAMELEN);
+               }
+               if (!sc->sc_ext11 &&
+                   (*rev & ADM1021_REV_MASK) == ADM1021_REV_1021A) {
+                       sc->sc_noneg = 0;
+                       strlcpy(name, "ADM1021A", ADMTEMP_NAMELEN);
+               } else
+                       strlcpy(name, "ADM1021", ADMTEMP_NAMELEN);
+       }
+}
 
 void
 admtemp_attach(device_t parent, device_t self, void *aux)
 {
        struct admtemp_softc *sc = device_private(self);
        struct i2c_attach_args *ia = aux;
-       u_int8_t cmd, data, stat;
+       u_int8_t cmd, data, stat, comp, rev;
+       char name[ADMTEMP_NAMELEN];
 
        sc->sc_tag = ia->ia_tag;
        sc->sc_addr = ia->ia_addr;
 
-       aprint_normal(": ADM1021 or compatible environmental sensor\n");
-       aprint_naive(": Environmental sensor\n");
-
        iic_acquire_bus(sc->sc_tag, 0);
        cmd = ADM1021_CONFIG_READ;
        if (iic_exec(sc->sc_tag, I2C_OP_READ_WITH_STOP,
@@ -154,15 +343,25 @@
                        return;
                }
        }
+
+       admtemp_setflags(sc, ia, &comp, &rev, name);
+
        iic_release_bus(sc->sc_tag, 0);
 
+       aprint_normal(": %s temperature sensor", name);
+       if (comp)
+               aprint_normal(": id. 0x%02x, rev. 0x%02x\n", comp, rev);
+       else
+               aprint_normal("\n");
+       aprint_naive(": Temperature sensor\n");



Home | Main Index | Thread Index | Old Index