1 /* $OpenBSD: lm75.c,v 1.21 2022/04/06 18:59:28 naddy 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 const 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
lmtemp_match(struct device * parent,void * match,void * aux)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
lmtemp_attach(struct device * parent,struct device * self,void * aux)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
lmtemp_temp_read(struct lmtemp_softc * sc,uint8_t which,int * valp)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
lmtemp_refresh_sensor_data(void * aux)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