Line data Source code
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 0 : lmtemp_match(struct device *parent, void *match, void *aux)
139 : {
140 0 : struct i2c_attach_args *ia = aux;
141 :
142 0 : if (strcmp(ia->ia_name, "lm75") == 0 ||
143 0 : strcmp(ia->ia_name, "lm76") == 0 ||
144 0 : strcmp(ia->ia_name, "lm77") == 0 ||
145 0 : strcmp(ia->ia_name, "ds1775") == 0 ||
146 0 : strcmp(ia->ia_name, "lm75a") == 0)
147 0 : return (1);
148 0 : return (0);
149 0 : }
150 :
151 : void
152 0 : lmtemp_attach(struct device *parent, struct device *self, void *aux)
153 : {
154 0 : struct lmtemp_softc *sc = (struct lmtemp_softc *)self;
155 0 : struct i2c_attach_args *ia = aux;
156 0 : u_int8_t cmd, data;
157 :
158 0 : sc->sc_tag = ia->ia_tag;
159 0 : sc->sc_addr = ia->ia_addr;
160 :
161 0 : printf(": %s", ia->ia_name);
162 :
163 : /* If in SHUTDOWN mode, wake it up */
164 0 : iic_acquire_bus(sc->sc_tag, 0);
165 0 : cmd = LM75_REG_CONFIG;
166 0 : if (iic_exec(sc->sc_tag, I2C_OP_READ_WITH_STOP,
167 0 : sc->sc_addr, &cmd, sizeof cmd, &data, sizeof data, 0)) {
168 0 : iic_release_bus(sc->sc_tag, 0);
169 0 : printf(", fails to respond\n");
170 0 : return;
171 : }
172 0 : if (data & LM75_CONFIG_SHUTDOWN) {
173 0 : data &= ~LM75_CONFIG_SHUTDOWN;
174 0 : if (iic_exec(sc->sc_tag, I2C_OP_WRITE_WITH_STOP,
175 0 : sc->sc_addr, &cmd, sizeof cmd, &data, sizeof data, 0)) {
176 0 : printf(", cannot wake up\n");
177 0 : iic_release_bus(sc->sc_tag, 0);
178 0 : return;
179 : }
180 0 : printf(", woken up");
181 0 : }
182 0 : iic_release_bus(sc->sc_tag, 0);
183 :
184 0 : sc->sc_model = LM_MODEL_LM75;
185 0 : sc->sc_bits = 9;
186 0 : sc->sc_ratio = 500000; /* 0.5 degC for LSB */
187 0 : if (strcmp(ia->ia_name, "lm77") == 0) {
188 0 : sc->sc_model = LM_MODEL_LM77;
189 0 : sc->sc_bits = 13;
190 0 : } else if (strcmp(ia->ia_name, "lm76") == 0) {
191 0 : sc->sc_model = LM_MODEL_LM76;
192 0 : sc->sc_bits = 13;
193 0 : sc->sc_ratio = 62500; /* 0.0625 degC for LSB */
194 0 : } else if (strcmp(ia->ia_name, "ds1775") == 0) {
195 0 : sc->sc_model = LM_MODEL_DS1775;
196 : //sc->sc_bits = DS1755_CONFIG_RESOLUTION(data);
197 0 : } else if (strcmp(ia->ia_name, "lm75a") == 0) {
198 : /* For simplicity's sake, treat the LM75A as an LM75 */
199 0 : sc->sc_model = LM_MODEL_LM75A;
200 0 : }
201 :
202 0 : printf("\n");
203 :
204 : /* Initialize sensor data */
205 0 : strlcpy(sc->sc_sensordev.xname, sc->sc_dev.dv_xname,
206 : sizeof(sc->sc_sensordev.xname));
207 0 : sc->sc_sensor.type = SENSOR_TEMP;
208 :
209 : /* Hook into the hw.sensors sysctl */
210 0 : sensor_attach(&sc->sc_sensordev, &sc->sc_sensor);
211 0 : sensordev_install(&sc->sc_sensordev);
212 :
213 0 : sensor_task_register(sc, lmtemp_refresh_sensor_data, LM_POLLTIME);
214 0 : }
215 :
216 : int
217 0 : lmtemp_temp_read(struct lmtemp_softc *sc, uint8_t which, int *valp)
218 : {
219 0 : u_int8_t cmd = which;
220 0 : u_int16_t data = 0x0000;
221 : int error;
222 :
223 0 : iic_acquire_bus(sc->sc_tag, 0);
224 0 : error = iic_exec(sc->sc_tag, I2C_OP_READ_WITH_STOP,
225 0 : sc->sc_addr, &cmd, sizeof cmd, &data, sizeof data, 0);
226 0 : iic_release_bus(sc->sc_tag, 0);
227 0 : if (error)
228 0 : return (error);
229 :
230 : /* Some chips return transient 0's.. we try next time */
231 0 : if (data == 0x0000)
232 0 : return (1);
233 :
234 : /* convert to half-degrees C */
235 0 : *valp = betoh16(data) / (1 << (16 - sc->sc_bits));
236 0 : return (0);
237 0 : }
238 :
239 : void
240 0 : lmtemp_refresh_sensor_data(void *aux)
241 : {
242 0 : struct lmtemp_softc *sc = aux;
243 0 : int val;
244 : int error;
245 :
246 0 : error = lmtemp_temp_read(sc, LM75_REG_TEMP, &val);
247 0 : 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 0 : sc->sc_sensor.flags |= SENSOR_FINVALID;
253 0 : return;
254 : }
255 :
256 0 : sc->sc_sensor.value = val * sc->sc_ratio + 273150000;
257 0 : sc->sc_sensor.flags &= ~SENSOR_FINVALID;
258 0 : }
|