summaryrefslogtreecommitdiff
path: root/sys/dev
diff options
context:
space:
mode:
authorjdc <jdc@NetBSD.org>2016-01-03 17:27:57 +0000
committerjdc <jdc@NetBSD.org>2016-01-03 17:27:57 +0000
commit3247e3533da6269cb972e58cd099c92c2dee368c (patch)
treedf0ef6c08913bef6097fa4e92b4b08987d29b94c /sys/dev
parente94239d43bfc8fd8f47ffffe7bfe61814864a8a4 (diff)
Add display and setting of chip temperature limit(s) for envsys(4).
Diffstat (limited to 'sys/dev')
-rw-r--r--sys/dev/i2c/lm75.c221
1 files changed, 201 insertions, 20 deletions
diff --git a/sys/dev/i2c/lm75.c b/sys/dev/i2c/lm75.c
index ffc646ad57c..a66e271a32b 100644
--- a/sys/dev/i2c/lm75.c
+++ b/sys/dev/i2c/lm75.c
@@ -1,4 +1,4 @@
-/* $NetBSD: lm75.c,v 1.27 2016/01/01 20:13:50 jdc Exp $ */
+/* $NetBSD: lm75.c,v 1.28 2016/01/03 17:27:57 jdc Exp $ */
/*
* Copyright (c) 2003 Wasabi Systems, Inc.
@@ -36,7 +36,7 @@
*/
#include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: lm75.c,v 1.27 2016/01/01 20:13:50 jdc Exp $");
+__KERNEL_RCSID(0, "$NetBSD: lm75.c,v 1.28 2016/01/03 17:27:57 jdc Exp $");
#include <sys/param.h>
#include <sys/systm.h>
@@ -57,8 +57,10 @@ struct lmtemp_softc {
struct sysmon_envsys *sc_sme;
envsys_data_t sc_sensor;
int sc_tmax;
+ uint32_t sc_smax, sc_smin, sc_scrit;
uint32_t (*sc_lmtemp_decode)(const uint8_t *, int);
+ void (*sc_lmtemp_encode)(const uint32_t, uint8_t *, int);
};
static int lmtemp_match(device_t, cfdata_t, void *);
@@ -68,14 +70,25 @@ CFATTACH_DECL_NEW(lmtemp, sizeof(struct lmtemp_softc),
lmtemp_match, lmtemp_attach, NULL, NULL);
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 int lmtemp_temp_write(struct lmtemp_softc *, uint8_t, uint32_t,
+ int);
static int lmtemp_temp_read(struct lmtemp_softc *, uint8_t, uint32_t *,
int);
static uint32_t lmtemp_decode_lm75(const uint8_t *, int);
static uint32_t lmtemp_decode_ds75(const uint8_t *, int);
static uint32_t lmtemp_decode_lm77(const uint8_t *, int);
+static void lmtemp_encode_lm75(const uint32_t, uint8_t *, int);
+static void lmtemp_encode_ds75(const uint32_t, uint8_t *, int);
+static void lmtemp_encode_lm77(const uint32_t, uint8_t *, int);
+static void lmtemp_getlim_lm75(struct sysmon_envsys *, envsys_data_t *,
+ sysmon_envsys_lim_t *, uint32_t *);
+static void lmtemp_getlim_lm77(struct sysmon_envsys *, envsys_data_t *,
+ sysmon_envsys_lim_t *, uint32_t *);
+static void lmtemp_setlim_lm75(struct sysmon_envsys *, envsys_data_t *,
+ sysmon_envsys_lim_t *, uint32_t *);
+static void lmtemp_setlim_lm77(struct sysmon_envsys *, envsys_data_t *,
+ sysmon_envsys_lim_t *, uint32_t *);
static void lmtemp_setup_sysctl(struct lmtemp_softc *);
static int sysctl_lm75_temp(SYSCTLFN_ARGS);
@@ -100,16 +113,24 @@ static const struct {
int lmtemp_addrmask;
int lmtemp_addr;
uint32_t (*lmtemp_decode)(const uint8_t *, int);
+ void (*lmtemp_encode)(const uint32_t, uint8_t *, int);
+ void (*lmtemp_getlim)(struct sysmon_envsys *, envsys_data_t *,
+ sysmon_envsys_lim_t *, uint32_t *);
+ void (*lmtemp_setlim)(struct sysmon_envsys *, envsys_data_t *,
+ sysmon_envsys_lim_t *, uint32_t *);
} lmtemptbl[] = {
- { lmtemp_lm75, "LM75",
- LM75_ADDRMASK, LM75_ADDR, lmtemp_decode_lm75 },
- { lmtemp_ds75, "DS75",
- LM75_ADDRMASK, LM75_ADDR, lmtemp_decode_ds75 },
- { lmtemp_lm77, "LM77",
- LM77_ADDRMASK, LM77_ADDR, lmtemp_decode_lm77 },
-
- { -1, NULL,
- 0, 0, NULL }
+ { lmtemp_lm75, "LM75", LM75_ADDRMASK, LM75_ADDR,
+ lmtemp_decode_lm75, lmtemp_encode_lm75,
+ lmtemp_getlim_lm75, lmtemp_setlim_lm75 },
+ { lmtemp_ds75, "DS75", LM75_ADDRMASK, LM75_ADDR,
+ lmtemp_decode_ds75, lmtemp_encode_ds75,
+ lmtemp_getlim_lm75, lmtemp_setlim_lm75 },
+ { lmtemp_lm77, "LM77", LM77_ADDRMASK, LM77_ADDR,
+ lmtemp_decode_lm77, lmtemp_encode_lm77,
+ lmtemp_getlim_lm77, lmtemp_setlim_lm77 },
+ { -1, NULL, 0, 0,
+ NULL, NULL,
+ NULL, NULL }
};
static int
@@ -180,15 +201,34 @@ lmtemp_attach(device_t parent, device_t self, void *aux)
}
sc->sc_lmtemp_decode = lmtemptbl[i].lmtemp_decode;
+ sc->sc_lmtemp_encode = lmtemptbl[i].lmtemp_encode;
iic_acquire_bus(sc->sc_tag, I2C_F_POLL);
- /* Read temperature limit and remember initial value. */
- if (lmtemp_temp_read(sc, LM75_REG_TOS_SET_POINT, &sc->sc_tmax, 1)
+ /* Read temperature limit(s) and remember initial value(s). */
+ if (lmtemp_temp_read(sc, LM75_REG_TOS_SET_POINT, &sc->sc_smax, 1)
!= 0) {
+ aprint_error_dev(self, "unable to read Tos register\n");
iic_release_bus(sc->sc_tag, I2C_F_POLL);
return;
}
+ sc->sc_tmax = sc->sc_smax;
+ if (i == lmtemp_lm77) {
+ if (lmtemp_temp_read(sc, LM77_REG_TLOW_SET_POINT,
+ &sc->sc_smax, 1) != 0) {
+ aprint_error_dev(self,
+ "unable to read low register\n");
+ iic_release_bus(sc->sc_tag, I2C_F_POLL);
+ return;
+ }
+ if (lmtemp_temp_read(sc, LM77_REG_THIGH_SET_POINT,
+ &sc->sc_smax, 1) != 0) {
+ aprint_error_dev(self,
+ "unable to read high register\n");
+ iic_release_bus(sc->sc_tag, I2C_F_POLL);
+ return;
+ }
+ }
if (i == lmtemp_lm75)
lmtemp_setup_sysctl(sc);
@@ -205,6 +245,7 @@ lmtemp_attach(device_t parent, device_t self, void *aux)
/* Initialize sensor data. */
sc->sc_sensor.units = ENVSYS_STEMP;
sc->sc_sensor.state = ENVSYS_SINVALID;
+ sc->sc_sensor.flags = ENVSYS_FMONLIMITS;
(void)strlcpy(sc->sc_sensor.desc,
ia->ia_name? ia->ia_name : device_xname(self),
sizeof(sc->sc_sensor.desc));
@@ -217,6 +258,8 @@ lmtemp_attach(device_t parent, device_t self, void *aux)
sc->sc_sme->sme_name = device_xname(self);
sc->sc_sme->sme_cookie = sc;
sc->sc_sme->sme_refresh = lmtemp_refresh;
+ sc->sc_sme->sme_get_limits = lmtemptbl[i].lmtemp_getlim;
+ sc->sc_sme->sme_set_limits = lmtemptbl[i].lmtemp_setlim;
if (sysmon_envsys_register(sc->sc_sme)) {
aprint_error_dev(self, "unable to register with sysmon\n");
@@ -237,13 +280,12 @@ lmtemp_config_write(struct lmtemp_softc *sc, uint8_t val)
}
static int
-lmtemp_temp_write(struct lmtemp_softc *sc, int reg, uint16_t val)
+lmtemp_temp_write(struct lmtemp_softc *sc, uint8_t reg, uint32_t val, int degc)
{
uint8_t cmdbuf[3];
cmdbuf[0] = reg;
- cmdbuf[1] = (val >> 1) & 0xff;
- cmdbuf[2] = (val & 1) << 7;
+ sc->sc_lmtemp_encode(val, &cmdbuf[1], degc);
return iic_exec(sc->sc_tag, I2C_OP_WRITE_WITH_STOP,
sc->sc_address, cmdbuf, 1, &cmdbuf[1], 2, I2C_F_POLL);
@@ -298,6 +340,103 @@ lmtemp_refresh(struct sysmon_envsys *sme, envsys_data_t *edata)
iic_release_bus(sc->sc_tag, 0); /* also unlocks our instance */
}
+static void
+lmtemp_getlim_lm75(struct sysmon_envsys *sme, envsys_data_t *edata,
+ sysmon_envsys_lim_t *limits, uint32_t *props)
+{
+ struct lmtemp_softc *sc = sme->sme_cookie;
+ uint32_t val;
+
+ *props &= ~(PROP_CRITMAX);
+
+ iic_acquire_bus(sc->sc_tag, I2C_F_POLL);
+ if (lmtemp_temp_read(sc, LM75_REG_TOS_SET_POINT, &val, 0) == 0) {
+ limits->sel_critmax = val;
+ *props |= PROP_CRITMAX;
+ }
+ iic_release_bus(sc->sc_tag, I2C_F_POLL);
+}
+
+static void
+lmtemp_getlim_lm77(struct sysmon_envsys *sme, envsys_data_t *edata,
+ sysmon_envsys_lim_t *limits, uint32_t *props)
+{
+ struct lmtemp_softc *sc = sme->sme_cookie;
+ uint32_t val;
+
+ *props &= ~(PROP_CRITMAX | PROP_WARNMAX | PROP_WARNMIN);
+
+ iic_acquire_bus(sc->sc_tag, I2C_F_POLL);
+ if (lmtemp_temp_read(sc, LM77_REG_TCRIT_SET_POINT, &val, 0) == 0) {
+ limits->sel_critmax = val;
+ *props |= PROP_CRITMAX;
+ }
+ if (lmtemp_temp_read(sc, LM77_REG_THIGH_SET_POINT, &val, 0) == 0) {
+ limits->sel_warnmax = val;
+ *props |= PROP_WARNMAX;
+ }
+ if (lmtemp_temp_read(sc, LM77_REG_TLOW_SET_POINT, &val, 0) == 0) {
+ limits->sel_warnmin = val;
+ *props |= PROP_WARNMIN;
+ }
+ iic_release_bus(sc->sc_tag, I2C_F_POLL);
+}
+
+static void
+lmtemp_setlim_lm75(struct sysmon_envsys *sme, envsys_data_t *edata,
+ sysmon_envsys_lim_t *limits, uint32_t *props)
+{
+ struct lmtemp_softc *sc = sme->sme_cookie;
+ int32_t limit;
+
+ if (*props & PROP_CRITMAX) {
+ if (limits == NULL) /* Restore defaults */
+ limit = sc->sc_smax;
+ else
+ limit = limits->sel_critmax;
+ iic_acquire_bus(sc->sc_tag, I2C_F_POLL);
+ lmtemp_temp_write(sc, LM75_REG_THYST_SET_POINT,
+ limit - 5000000, 0);
+ lmtemp_temp_write(sc, LM75_REG_TOS_SET_POINT, limit, 0);
+ iic_release_bus(sc->sc_tag, I2C_F_POLL);
+
+ /* Synchronise sysctl */
+ sc->sc_tmax = (limit - 273150000) / 1000000;
+ }
+}
+
+static void
+lmtemp_setlim_lm77(struct sysmon_envsys *sme, envsys_data_t *edata,
+ sysmon_envsys_lim_t *limits, uint32_t *props)
+{
+ struct lmtemp_softc *sc = sme->sme_cookie;
+ int32_t limit;
+
+ iic_acquire_bus(sc->sc_tag, I2C_F_POLL);
+ if (*props & PROP_CRITMAX) {
+ if (limits == NULL) /* Restore defaults */
+ limit = sc->sc_smax;
+ else
+ limit = limits->sel_critmax;
+ lmtemp_temp_write(sc, LM77_REG_TCRIT_SET_POINT, limit, 0);
+ }
+ if (*props & PROP_WARNMAX) {
+ if (limits == NULL) /* Restore defaults */
+ limit = sc->sc_smax;
+ else
+ limit = limits->sel_warnmax;
+ lmtemp_temp_write(sc, LM77_REG_THIGH_SET_POINT, limit, 0);
+ }
+ if (*props & PROP_WARNMIN) {
+ if (limits == NULL) /* Restore defaults */
+ limit = sc->sc_smax;
+ else
+ limit = limits->sel_warnmin;
+ lmtemp_temp_write(sc, LM77_REG_TLOW_SET_POINT, limit, 0);
+ }
+ iic_release_bus(sc->sc_tag, I2C_F_POLL);
+}
+
static uint32_t
lmtemp_decode_lm75(const uint8_t *buf, int degc)
{
@@ -364,6 +503,45 @@ lmtemp_decode_lm77(const uint8_t *buf, int degc)
return val;
}
+static void lmtemp_encode_lm75(const uint32_t val, uint8_t *buf, int degc)
+{
+ int temp;
+
+ /* Convert from C or uK to register format */
+ if (degc)
+ temp = val * 2;
+ else
+ temp = (val - 273150000) / 500000;
+ buf[0] = (temp >> 1) & 0xff;
+ buf[1] = (temp & 1) << 7;
+}
+
+static void lmtemp_encode_ds75(const uint32_t val, uint8_t *buf, int degc)
+{
+ int temp;
+
+ /* Convert from C or uK to register format */
+ if (degc)
+ temp = val * 16;
+ else
+ temp = (val - 273150000) / 62500;
+ buf[0] = (temp >> 4) & 0xff;
+ buf[1] = (temp & 0xf) << 4;
+}
+
+static void lmtemp_encode_lm77(const uint32_t val, uint8_t *buf, int degc)
+{
+ int temp;
+
+ /* Convert from C or uK to register format */
+ if (degc)
+ temp = val * 2;
+ else
+ temp = (val - 273150000) / 500000;
+ buf[0] = (temp >> 5) & 0xff;
+ buf[1] = (temp & 0x1f) << 3;
+}
+
static void
lmtemp_setup_sysctl(struct lmtemp_softc *sc)
{
@@ -399,10 +577,13 @@ sysctl_lm75_temp(SYSCTLFN_ARGS)
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);
+ sc->sc_tmax - 5, 1);
lmtemp_temp_write(sc, LM75_REG_TOS_SET_POINT,
- sc->sc_tmax * 2);
+ sc->sc_tmax, 1);
iic_release_bus(sc->sc_tag, I2C_F_POLL);
+
+ /* Synchronise envsys - calls lmtemp_getlim_lm75() */
+ sysmon_envsys_update_limits(sc->sc_sme, &sc->sc_sensor);
return 0;
}
return EINVAL;