123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259 |
- /* $OpenBSD: lm75.c,v 1.20 2015/05/30 08:39:05 kettenis Exp $ */
- /* $NetBSD: lm75.c,v 1.1 2003/09/30 00:35:31 thorpej Exp $ */
- /*
- * Copyright (c) 2006 Theo de Raadt <deraadt@openbsd.org>
- * Copyright (c) 2004 Alexander Yurchenko <grange@openbsd.org>
- *
- * Permission to use, copy, modify, and distribute this software for any
- * purpose with or without fee is hereby granted, provided that the above
- * copyright notice and this permission notice appear in all copies.
- *
- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
- * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
- * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
- * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
- * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
- * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
- */
- /*
- * National Semiconductor LM75/LM76/LM77 temperature sensor.
- */
- #include <sys/param.h>
- #include <sys/systm.h>
- #include <sys/device.h>
- #include <sys/sensors.h>
- #include <dev/i2c/i2cvar.h>
- #define LM_MODEL_LM75 1
- #define LM_MODEL_LM77 2
- #define LM_MODEL_DS1775 3
- #define LM_MODEL_LM75A 4
- #define LM_MODEL_LM76 5
- #define LM_POLLTIME 3 /* 3s */
- #define LM75_REG_TEMP 0x00
- #define LM75_REG_CONFIG 0x01
- #define LM75_CONFIG_SHUTDOWN 0x01
- #define LM75_CONFIG_CMPINT 0x02
- #define LM75_CONFIG_OSPOLARITY 0x04
- #define LM75_CONFIG_FAULT_QUEUE_MASK 0x18
- #define LM75_CONFIG_FAULT_QUEUE_1 (0 << 3)
- #define LM75_CONFIG_FAULT_QUEUE_2 (1 << 3)
- #define LM75_CONFIG_FAULT_QUEUE_4 (2 << 3)
- #define LM75_CONFIG_FAULT_QUEUE_6 (3 << 3)
- #define LM77_CONFIG_INTPOLARITY 0x08
- #define LM77_CONFIG_FAULT_QUEUE_4 0x10
- #define DS1755_CONFIG_RESOLUTION(i) (9 + (((i) >> 5) & 3))
- #define LM75_REG_THYST_SET_POINT 0x02
- #define LM75_REG_TOS_SET_POINT 0x03
- #define LM77_REG_TLOW 0x04
- #define LM77_REG_THIGH 0x05
- struct lmtemp_softc {
- struct device sc_dev;
- i2c_tag_t sc_tag;
- int sc_addr;
- int sc_model;
- int sc_bits;
- int sc_ratio;
- struct ksensor sc_sensor;
- struct ksensordev sc_sensordev;
- };
- int lmtemp_match(struct device *, void *, void *);
- void lmtemp_attach(struct device *, struct device *, void *);
- struct cfattach lmtemp_ca = {
- sizeof(struct lmtemp_softc),
- lmtemp_match,
- lmtemp_attach
- };
- struct cfdriver lmtemp_cd = {
- NULL, "lmtemp", DV_DULL
- };
- /*
- * Temperature on the LM75 is represented by a 9-bit two's complement
- * integer in steps of 0.5C. The following examples are taken from
- * the LM75 data sheet:
- *
- * +125C 0 1111 1010 0x0fa
- * +25C 0 0011 0010 0x032
- * +0.5C 0 0000 0001 0x001
- * 0C 0 0000 0000 0x000
- * -0.5C 1 1111 1111 0x1ff
- * -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 13-bit two's complement
- * integer in steps of 0.5C. The LM76 is similar, but the integer is
- * in steps of 0.065C
- *
- * LM75 temperature word:
- *
- * MSB Bit7 Bit6 Bit5 Bit4 Bit3 Bit2 Bit1 Bit0 X X X X X X X
- * 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
- * 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0
- */
- int lmtemp_temp_read(struct lmtemp_softc *, uint8_t, int *);
- void lmtemp_refresh_sensor_data(void *);
- int
- lmtemp_match(struct device *parent, void *match, void *aux)
- {
- struct i2c_attach_args *ia = aux;
- if (strcmp(ia->ia_name, "lm75") == 0 ||
- strcmp(ia->ia_name, "lm76") == 0 ||
- strcmp(ia->ia_name, "lm77") == 0 ||
- strcmp(ia->ia_name, "ds1775") == 0 ||
- strcmp(ia->ia_name, "lm75a") == 0)
- return (1);
- return (0);
- }
- void
- lmtemp_attach(struct device *parent, struct device *self, void *aux)
- {
- struct lmtemp_softc *sc = (struct lmtemp_softc *)self;
- struct i2c_attach_args *ia = aux;
- u_int8_t cmd, data;
- sc->sc_tag = ia->ia_tag;
- sc->sc_addr = ia->ia_addr;
- printf(": %s", ia->ia_name);
- /* If in SHUTDOWN mode, wake it up */
- iic_acquire_bus(sc->sc_tag, 0);
- cmd = LM75_REG_CONFIG;
- if (iic_exec(sc->sc_tag, I2C_OP_READ_WITH_STOP,
- sc->sc_addr, &cmd, sizeof cmd, &data, sizeof data, 0)) {
- iic_release_bus(sc->sc_tag, 0);
- printf(", fails to respond\n");
- return;
- }
- if (data & LM75_CONFIG_SHUTDOWN) {
- data &= ~LM75_CONFIG_SHUTDOWN;
- if (iic_exec(sc->sc_tag, I2C_OP_WRITE_WITH_STOP,
- sc->sc_addr, &cmd, sizeof cmd, &data, sizeof data, 0)) {
- printf(", cannot wake up\n");
- iic_release_bus(sc->sc_tag, 0);
- return;
- }
- printf(", woken up");
- }
- iic_release_bus(sc->sc_tag, 0);
- sc->sc_model = LM_MODEL_LM75;
- sc->sc_bits = 9;
- sc->sc_ratio = 500000; /* 0.5 degC for LSB */
- if (strcmp(ia->ia_name, "lm77") == 0) {
- sc->sc_model = LM_MODEL_LM77;
- sc->sc_bits = 13;
- } else if (strcmp(ia->ia_name, "lm76") == 0) {
- sc->sc_model = LM_MODEL_LM76;
- sc->sc_bits = 13;
- sc->sc_ratio = 62500; /* 0.0625 degC for LSB */
- } else if (strcmp(ia->ia_name, "ds1775") == 0) {
- sc->sc_model = LM_MODEL_DS1775;
- //sc->sc_bits = DS1755_CONFIG_RESOLUTION(data);
- } else if (strcmp(ia->ia_name, "lm75a") == 0) {
- /* For simplicity's sake, treat the LM75A as an LM75 */
- sc->sc_model = LM_MODEL_LM75A;
- }
- printf("\n");
- /* Initialize sensor data */
- strlcpy(sc->sc_sensordev.xname, sc->sc_dev.dv_xname,
- sizeof(sc->sc_sensordev.xname));
- sc->sc_sensor.type = SENSOR_TEMP;
- /* Hook into the hw.sensors sysctl */
- sensor_attach(&sc->sc_sensordev, &sc->sc_sensor);
- sensordev_install(&sc->sc_sensordev);
- sensor_task_register(sc, lmtemp_refresh_sensor_data, LM_POLLTIME);
- }
- int
- lmtemp_temp_read(struct lmtemp_softc *sc, uint8_t which, int *valp)
- {
- u_int8_t cmd = which;
- u_int16_t data = 0x0000;
- int error;
- iic_acquire_bus(sc->sc_tag, 0);
- error = iic_exec(sc->sc_tag, I2C_OP_READ_WITH_STOP,
- sc->sc_addr, &cmd, sizeof cmd, &data, sizeof data, 0);
- iic_release_bus(sc->sc_tag, 0);
- if (error)
- return (error);
- /* Some chips return transient 0's.. we try next time */
- if (data == 0x0000)
- return (1);
- /* convert to half-degrees C */
- *valp = betoh16(data) / (1 << (16 - sc->sc_bits));
- return (0);
- }
- void
- lmtemp_refresh_sensor_data(void *aux)
- {
- struct lmtemp_softc *sc = aux;
- int val;
- int error;
- error = lmtemp_temp_read(sc, LM75_REG_TEMP, &val);
- if (error) {
- #if 0
- printf("%s: unable to read temperature, error = %d\n",
- sc->sc_dev.dv_xname, error);
- #endif
- sc->sc_sensor.flags |= SENSOR_FINVALID;
- return;
- }
- sc->sc_sensor.value = val * sc->sc_ratio + 273150000;
- sc->sc_sensor.flags &= ~SENSOR_FINVALID;
- }
|