diff options
| author | jdc <jdc@NetBSD.org> | 2016-01-03 17:27:57 +0000 |
|---|---|---|
| committer | jdc <jdc@NetBSD.org> | 2016-01-03 17:27:57 +0000 |
| commit | 3247e3533da6269cb972e58cd099c92c2dee368c (patch) | |
| tree | df0ef6c08913bef6097fa4e92b4b08987d29b94c /sys/dev | |
| parent | e94239d43bfc8fd8f47ffffe7bfe61814864a8a4 (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.c | 221 |
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; |
