1 /* $OpenBSD: lm75.c,v 1.20 2015/05/30 08:39:05 kettenis 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/LM76/LM77 temperature sensor. 22 */ 23 24 #include <sys/param.h> 25 #include <sys/systm.h> 26 #include <sys/device.h> 27 #include <sys/sensors.h> 28 29 #include <dev/i2c/i2cvar.h> 30 31 #define LM_MODEL_LM75 1 32 #define LM_MODEL_LM77 2 33 #define LM_MODEL_DS1775 3 34 #define LM_MODEL_LM75A 4 35 #define LM_MODEL_LM76 5 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 int sc_ratio; 64 65 struct ksensor sc_sensor; 66 struct ksensordev sc_sensordev; 67 }; 68 69 int lmtemp_match(struct device *, void *, void *); 70 void lmtemp_attach(struct device *, struct device *, void *); 71 72 struct cfattach lmtemp_ca = { 73 sizeof(struct lmtemp_softc), 74 lmtemp_match, 75 lmtemp_attach 76 }; 77 78 struct cfdriver lmtemp_cd = { 79 NULL, "lmtemp", DV_DULL 80 }; 81 82 /* 83 * Temperature on the LM75 is represented by a 9-bit two's complement 84 * integer in steps of 0.5C. The following examples are taken from 85 * the LM75 data sheet: 86 * 87 * +125C 0 1111 1010 0x0fa 88 * +25C 0 0011 0010 0x032 89 * +0.5C 0 0000 0001 0x001 90 * 0C 0 0000 0000 0x000 91 * -0.5C 1 1111 1111 0x1ff 92 * -25C 1 1100 1110 0x1ce 93 * -55C 1 1001 0010 0x192 94 * 95 * Temperature on the LM75A is represented by an 11-bit two's complement 96 * integer in steps of 0.125C. The LM75A can be treated like an LM75 if 97 * the extra precision is not required. The following examples are 98 * taken from the LM75A data sheet: 99 * 100 * +127.000C 011 1111 1000 0x3f8 101 * +126.875C 011 1111 0111 0x3f7 102 * +126.125C 011 1111 0001 0x3f1 103 * +125.000C 011 1110 1000 0x3e8 104 * +25.000C 000 1100 1000 0x0c8 105 * +0.125C 000 0000 0001 0x001 106 * 0C 000 0000 0000 0x000 107 * -0.125C 111 1111 1111 0x7ff 108 * -25.000C 111 0011 1000 0x738 109 * -54.875C 110 0100 1001 0x649 110 * -55.000C 110 0100 1000 0x648 111 * 112 * Temperature on the LM77 is represented by a 13-bit two's complement 113 * integer in steps of 0.5C. The LM76 is similar, but the integer is 114 * in steps of 0.065C 115 * 116 * LM75 temperature word: 117 * 118 * MSB Bit7 Bit6 Bit5 Bit4 Bit3 Bit2 Bit1 Bit0 X X X X X X X 119 * 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0 120 * 121 * 122 * LM75A temperature word: 123 * 124 * MSB Bit9 Bit8 Bit7 Bit6 Bit5 Bit4 Bit3 Bit2 Bit1 Bit0 X X X X X 125 * 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0 126 * 127 * 128 * LM77 temperature word: 129 * 130 * Sign Sign Sign Sign MSB Bit7 Bit6 Bit5 Bit4 Bit3 Bit2 Bit1 Bit0 Status bits 131 * 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0 132 */ 133 134 int lmtemp_temp_read(struct lmtemp_softc *, uint8_t, int *); 135 void lmtemp_refresh_sensor_data(void *); 136 137 int 138 lmtemp_match(struct device *parent, void *match, void *aux) 139 { 140 struct i2c_attach_args *ia = aux; 141 142 if (strcmp(ia->ia_name, "lm75") == 0 || 143 strcmp(ia->ia_name, "lm76") == 0 || 144 strcmp(ia->ia_name, "lm77") == 0 || 145 strcmp(ia->ia_name, "ds1775") == 0 || 146 strcmp(ia->ia_name, "lm75a") == 0) 147 return (1); 148 return (0); 149 } 150 151 void 152 lmtemp_attach(struct device *parent, struct device *self, void *aux) 153 { 154 struct lmtemp_softc *sc = (struct lmtemp_softc *)self; 155 struct i2c_attach_args *ia = aux; 156 u_int8_t cmd, data; 157 158 sc->sc_tag = ia->ia_tag; 159 sc->sc_addr = ia->ia_addr; 160 161 printf(": %s", ia->ia_name); 162 163 /* If in SHUTDOWN mode, wake it up */ 164 iic_acquire_bus(sc->sc_tag, 0); 165 cmd = LM75_REG_CONFIG; 166 if (iic_exec(sc->sc_tag, I2C_OP_READ_WITH_STOP, 167 sc->sc_addr, &cmd, sizeof cmd, &data, sizeof data, 0)) { 168 iic_release_bus(sc->sc_tag, 0); 169 printf(", fails to respond\n"); 170 return; 171 } 172 if (data & LM75_CONFIG_SHUTDOWN) { 173 data &= ~LM75_CONFIG_SHUTDOWN; 174 if (iic_exec(sc->sc_tag, I2C_OP_WRITE_WITH_STOP, 175 sc->sc_addr, &cmd, sizeof cmd, &data, sizeof data, 0)) { 176 printf(", cannot wake up\n"); 177 iic_release_bus(sc->sc_tag, 0); 178 return; 179 } 180 printf(", woken up"); 181 } 182 iic_release_bus(sc->sc_tag, 0); 183 184 sc->sc_model = LM_MODEL_LM75; 185 sc->sc_bits = 9; 186 sc->sc_ratio = 500000; /* 0.5 degC for LSB */ 187 if (strcmp(ia->ia_name, "lm77") == 0) { 188 sc->sc_model = LM_MODEL_LM77; 189 sc->sc_bits = 13; 190 } else if (strcmp(ia->ia_name, "lm76") == 0) { 191 sc->sc_model = LM_MODEL_LM76; 192 sc->sc_bits = 13; 193 sc->sc_ratio = 62500; /* 0.0625 degC for LSB */ 194 } else if (strcmp(ia->ia_name, "ds1775") == 0) { 195 sc->sc_model = LM_MODEL_DS1775; 196 //sc->sc_bits = DS1755_CONFIG_RESOLUTION(data); 197 } else if (strcmp(ia->ia_name, "lm75a") == 0) { 198 /* For simplicity's sake, treat the LM75A as an LM75 */ 199 sc->sc_model = LM_MODEL_LM75A; 200 } 201 202 printf("\n"); 203 204 /* Initialize sensor data */ 205 strlcpy(sc->sc_sensordev.xname, sc->sc_dev.dv_xname, 206 sizeof(sc->sc_sensordev.xname)); 207 sc->sc_sensor.type = SENSOR_TEMP; 208 209 /* Hook into the hw.sensors sysctl */ 210 sensor_attach(&sc->sc_sensordev, &sc->sc_sensor); 211 sensordev_install(&sc->sc_sensordev); 212 213 sensor_task_register(sc, lmtemp_refresh_sensor_data, LM_POLLTIME); 214 } 215 216 int 217 lmtemp_temp_read(struct lmtemp_softc *sc, uint8_t which, int *valp) 218 { 219 u_int8_t cmd = which; 220 u_int16_t data = 0x0000; 221 int error; 222 223 iic_acquire_bus(sc->sc_tag, 0); 224 error = iic_exec(sc->sc_tag, I2C_OP_READ_WITH_STOP, 225 sc->sc_addr, &cmd, sizeof cmd, &data, sizeof data, 0); 226 iic_release_bus(sc->sc_tag, 0); 227 if (error) 228 return (error); 229 230 /* Some chips return transient 0's.. we try next time */ 231 if (data == 0x0000) 232 return (1); 233 234 /* convert to half-degrees C */ 235 *valp = betoh16(data) / (1 << (16 - sc->sc_bits)); 236 return (0); 237 } 238 239 void 240 lmtemp_refresh_sensor_data(void *aux) 241 { 242 struct lmtemp_softc *sc = aux; 243 int val; 244 int error; 245 246 error = lmtemp_temp_read(sc, LM75_REG_TEMP, &val); 247 if (error) { 248 #if 0 249 printf("%s: unable to read temperature, error = %d\n", 250 sc->sc_dev.dv_xname, error); 251 #endif 252 sc->sc_sensor.flags |= SENSOR_FINVALID; 253 return; 254 } 255 256 sc->sc_sensor.value = val * sc->sc_ratio + 273150000; 257 sc->sc_sensor.flags &= ~SENSOR_FINVALID; 258 } 259