Annotation of sys/dev/i2c/lm75.c, Revision 1.1
1.1 ! nbrk 1: /* $OpenBSD: lm75.c,v 1.15 2007/03/22 16:55:31 deraadt Exp $ */
! 2: /* $NetBSD: lm75.c,v 1.1 2003/09/30 00:35:31 thorpej Exp $ */
! 3: /*
! 4: * Copyright (c) 2006 Theo de Raadt <deraadt@openbsd.org>
! 5: * Copyright (c) 2004 Alexander Yurchenko <grange@openbsd.org>
! 6: *
! 7: * Permission to use, copy, modify, and distribute this software for any
! 8: * purpose with or without fee is hereby granted, provided that the above
! 9: * copyright notice and this permission notice appear in all copies.
! 10: *
! 11: * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
! 12: * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
! 13: * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
! 14: * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
! 15: * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
! 16: * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
! 17: * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
! 18: */
! 19:
! 20: /*
! 21: * National Semiconductor LM75/LM77 temperature sensor.
! 22: */
! 23:
! 24: #include <sys/param.h>
! 25: #include <sys/systm.h>
! 26: #include <sys/device.h>
! 27: #include <sys/kernel.h>
! 28: #include <sys/sensors.h>
! 29:
! 30: #include <dev/i2c/i2cvar.h>
! 31:
! 32: #define LM_MODEL_LM75 1
! 33: #define LM_MODEL_LM77 2
! 34: #define LM_MODEL_DS1775 3
! 35: #define LM_MODEL_LM75A 4
! 36:
! 37: #define LM_POLLTIME 3 /* 3s */
! 38:
! 39: #define LM75_REG_TEMP 0x00
! 40: #define LM75_REG_CONFIG 0x01
! 41: #define LM75_CONFIG_SHUTDOWN 0x01
! 42: #define LM75_CONFIG_CMPINT 0x02
! 43: #define LM75_CONFIG_OSPOLARITY 0x04
! 44: #define LM75_CONFIG_FAULT_QUEUE_MASK 0x18
! 45: #define LM75_CONFIG_FAULT_QUEUE_1 (0 << 3)
! 46: #define LM75_CONFIG_FAULT_QUEUE_2 (1 << 3)
! 47: #define LM75_CONFIG_FAULT_QUEUE_4 (2 << 3)
! 48: #define LM75_CONFIG_FAULT_QUEUE_6 (3 << 3)
! 49: #define LM77_CONFIG_INTPOLARITY 0x08
! 50: #define LM77_CONFIG_FAULT_QUEUE_4 0x10
! 51: #define DS1755_CONFIG_RESOLUTION(i) (9 + (((i) >> 5) & 3))
! 52: #define LM75_REG_THYST_SET_POINT 0x02
! 53: #define LM75_REG_TOS_SET_POINT 0x03
! 54: #define LM77_REG_TLOW 0x04
! 55: #define LM77_REG_THIGH 0x05
! 56:
! 57: struct lmtemp_softc {
! 58: struct device sc_dev;
! 59: i2c_tag_t sc_tag;
! 60: int sc_addr;
! 61: int sc_model;
! 62: int sc_bits;
! 63:
! 64: struct ksensor sc_sensor;
! 65: struct ksensordev sc_sensordev;
! 66: };
! 67:
! 68: int lmtemp_match(struct device *, void *, void *);
! 69: void lmtemp_attach(struct device *, struct device *, void *);
! 70:
! 71: struct cfattach lmtemp_ca = {
! 72: sizeof(struct lmtemp_softc),
! 73: lmtemp_match,
! 74: lmtemp_attach
! 75: };
! 76:
! 77: struct cfdriver lmtemp_cd = {
! 78: NULL, "lmtemp", DV_DULL
! 79: };
! 80:
! 81: /*
! 82: * Temperature on the LM75 is represented by a 9-bit two's complement
! 83: * integer in steps of 0.5C. The following examples are taken from
! 84: * the LM75 data sheet:
! 85: *
! 86: * +125C 0 1111 1010 0x0fa
! 87: * +25C 0 0011 0010 0x032
! 88: * +0.5C 0 0000 0001 0x001
! 89: * 0C 0 0000 0000 0x000
! 90: * -0.5C 1 1111 1111 0x1ff
! 91: * -25C 1 1100 1110 0x1ce
! 92: * -55C 1 1001 0010 0x192
! 93: *
! 94: * Temperature on the LM75A is represented by an 11-bit two's complement
! 95: * integer in steps of 0.125C. The LM75A can be treated like an LM75 if
! 96: * the extra precision is not required. The following examples are
! 97: * taken from the LM75A data sheet:
! 98: *
! 99: * +127.000C 011 1111 1000 0x3f8
! 100: * +126.875C 011 1111 0111 0x3f7
! 101: * +126.125C 011 1111 0001 0x3f1
! 102: * +125.000C 011 1110 1000 0x3e8
! 103: * +25.000C 000 1100 1000 0x0c8
! 104: * +0.125C 000 0000 0001 0x001
! 105: * 0C 000 0000 0000 0x000
! 106: * -0.125C 111 1111 1111 0x7ff
! 107: * -25.000C 111 0011 1000 0x738
! 108: * -54.875C 110 0100 1001 0x649
! 109: * -55.000C 110 0100 1000 0x648
! 110: *
! 111: * Temperature on the LM77 is represented by a 10-bit two's complement
! 112: * integer in steps of 0.5C:
! 113: *
! 114: * +130C 01 0000 0100 0x104
! 115: * +125C 00 1111 1010 0x0fa
! 116: * +25C 00 0011 0010 0x032
! 117: * +0.5C 00 0000 0001 0x001
! 118: * 0C 00 0000 0000 0x000
! 119: * -0.5C 11 1111 1111 0x3ff
! 120: * -25C 11 1100 1110 0x3ce
! 121: * -55C 11 1001 0010 0x392
! 122: *
! 123: * LM75 temperature word:
! 124: *
! 125: * MSB Bit7 Bit6 Bit5 Bit4 Bit3 Bit2 Bit1 Bit0 X X X X X X X
! 126: * 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0
! 127: *
! 128: *
! 129: * LM75A temperature word:
! 130: *
! 131: * MSB Bit9 Bit8 Bit7 Bit6 Bit5 Bit4 Bit3 Bit2 Bit1 Bit0 X X X X X
! 132: * 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0
! 133: *
! 134: *
! 135: * LM77 temperature word:
! 136: *
! 137: * Sign Sign Sign Sign MSB Bit7 Bit6 Bit5 Bit4 Bit3 Bit2 Bit1 Bit0 Status bits
! 138: * 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0
! 139: */
! 140:
! 141: int lmtemp_temp_read(struct lmtemp_softc *, uint8_t, int *);
! 142: void lmtemp_refresh_sensor_data(void *);
! 143:
! 144: int
! 145: lmtemp_match(struct device *parent, void *match, void *aux)
! 146: {
! 147: struct i2c_attach_args *ia = aux;
! 148:
! 149: if (strcmp(ia->ia_name, "lm75") == 0 ||
! 150: strcmp(ia->ia_name, "lm77") == 0 ||
! 151: strcmp(ia->ia_name, "ds1775") == 0 ||
! 152: strcmp(ia->ia_name, "lm75a") == 0)
! 153: return (1);
! 154: return (0);
! 155: }
! 156:
! 157: void
! 158: lmtemp_attach(struct device *parent, struct device *self, void *aux)
! 159: {
! 160: struct lmtemp_softc *sc = (struct lmtemp_softc *)self;
! 161: struct i2c_attach_args *ia = aux;
! 162: u_int8_t cmd, data;
! 163:
! 164: sc->sc_tag = ia->ia_tag;
! 165: sc->sc_addr = ia->ia_addr;
! 166:
! 167: printf(": %s", ia->ia_name);
! 168:
! 169: /* If in SHUTDOWN mode, wake it up */
! 170: iic_acquire_bus(sc->sc_tag, 0);
! 171: cmd = LM75_REG_CONFIG;
! 172: if (iic_exec(sc->sc_tag, I2C_OP_READ_WITH_STOP,
! 173: sc->sc_addr, &cmd, 1, &data, 1, 0)) {
! 174: iic_release_bus(sc->sc_tag, 0);
! 175: return;
! 176: }
! 177: if (data & LM75_CONFIG_SHUTDOWN) {
! 178: data &= ~LM75_CONFIG_SHUTDOWN;
! 179: if (iic_exec(sc->sc_tag, I2C_OP_WRITE_WITH_STOP,
! 180: sc->sc_addr, &cmd, 1, &data, 1, 0)) {
! 181: printf(", cannot wake up\n");
! 182: iic_release_bus(sc->sc_tag, 0);
! 183: return;
! 184: }
! 185: printf(", woken up");
! 186: }
! 187: iic_release_bus(sc->sc_tag, 0);
! 188:
! 189: sc->sc_model = LM_MODEL_LM75;
! 190: sc->sc_bits = 9;
! 191: if (strcmp(ia->ia_name, "lm77") == 0) {
! 192: sc->sc_model = LM_MODEL_LM77;
! 193: sc->sc_bits = 13;
! 194: } else if (strcmp(ia->ia_name, "ds1775") == 0) {
! 195: sc->sc_model = LM_MODEL_DS1775;
! 196: sc->sc_bits = 9;
! 197: //sc->sc_bits = DS1755_CONFIG_RESOLUTION(data);
! 198: } else if (strcmp(ia->ia_name, "lm75a") == 0) {
! 199: /* For simplicity's sake, treat the LM75A as an LM75 */
! 200: sc->sc_model = LM_MODEL_LM75A;
! 201: sc->sc_bits = 9;
! 202: }
! 203:
! 204: printf("\n");
! 205:
! 206: /* Initialize sensor data */
! 207: strlcpy(sc->sc_sensordev.xname, sc->sc_dev.dv_xname,
! 208: sizeof(sc->sc_sensordev.xname));
! 209: sc->sc_sensor.type = SENSOR_TEMP;
! 210:
! 211: /* Hook into the hw.sensors sysctl */
! 212: sensor_attach(&sc->sc_sensordev, &sc->sc_sensor);
! 213: sensordev_install(&sc->sc_sensordev);
! 214:
! 215:
! 216: sensor_task_register(sc, lmtemp_refresh_sensor_data, LM_POLLTIME);
! 217: }
! 218:
! 219: int
! 220: lmtemp_temp_read(struct lmtemp_softc *sc, uint8_t which, int *valp)
! 221: {
! 222: u_int8_t cmd, buf[2];
! 223: int error;
! 224:
! 225: cmd = which;
! 226: error = iic_exec(sc->sc_tag, I2C_OP_READ_WITH_STOP,
! 227: sc->sc_addr, &cmd, 1, buf, 2, 0);
! 228: if (error)
! 229: return (error);
! 230:
! 231: /* Some chips return transient 0's.. we try next time */
! 232: if (buf[0] == 0x00 && buf[1] == 0x00)
! 233: return (1);
! 234:
! 235: /* convert to half-degrees C */
! 236: *valp = ((buf[0] << 8) | buf[1]) / (1 << (16 - sc->sc_bits));
! 237: return (0);
! 238: }
! 239:
! 240: void
! 241: lmtemp_refresh_sensor_data(void *aux)
! 242: {
! 243: struct lmtemp_softc *sc = aux;
! 244: int val;
! 245: int error;
! 246:
! 247: error = lmtemp_temp_read(sc, LM75_REG_TEMP, &val);
! 248: if (error) {
! 249: #if 0
! 250: printf("%s: unable to read temperature, error = %d\n",
! 251: sc->sc_dev.dv_xname, error);
! 252: #endif
! 253: sc->sc_sensor.flags |= SENSOR_FINVALID;
! 254: return;
! 255: }
! 256:
! 257: sc->sc_sensor.value = val * 500000 + 273150000;
! 258: sc->sc_sensor.flags &= ~SENSOR_FINVALID;
! 259: }
CVSweb