File: | dev/i2c/adt7460.c |
Warning: | line 315, column 35 The left operand of '*' is a garbage value |
Press '?' to see keyboard shortcuts
Keyboard shortcuts:
1 | /* $OpenBSD: adt7460.c,v 1.21 2007/12/12 16:56:59 deraadt Exp $ */ | |||
2 | ||||
3 | /* | |||
4 | * Copyright (c) 2005 Mark Kettenis | |||
5 | * | |||
6 | * Permission to use, copy, modify, and distribute this software for any | |||
7 | * purpose with or without fee is hereby granted, provided that the above | |||
8 | * copyright notice and this permission notice appear in all copies. | |||
9 | * | |||
10 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES | |||
11 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF | |||
12 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR | |||
13 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES | |||
14 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN | |||
15 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF | |||
16 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. | |||
17 | */ | |||
18 | ||||
19 | #include <sys/param.h> | |||
20 | #include <sys/systm.h> | |||
21 | #include <sys/device.h> | |||
22 | #include <sys/sensors.h> | |||
23 | ||||
24 | #include <dev/i2c/i2cvar.h> | |||
25 | ||||
26 | /* ADT7460 registers */ | |||
27 | #define ADT7460_2_5V0x20 0x20 | |||
28 | #define ADT7460_VCCP0x21 0x21 | |||
29 | #define ADT7460_VCC0x22 0x22 | |||
30 | #define ADT7460_V50x23 0x23 | |||
31 | #define ADT7460_V120x24 0x24 | |||
32 | #define ADT7460_VTR0x99 0x99 | |||
33 | #define ADT7460_VBAT0x9a 0x9a | |||
34 | #define ADT7460_REM1_TEMP0x25 0x25 | |||
35 | #define ADT7460_LOCAL_TEMP0x26 0x26 | |||
36 | #define ADT7460_REM2_TEMP0x27 0x27 | |||
37 | #define ADT7460_TACH1L0x28 0x28 | |||
38 | #define ADT7460_TACH1H0x29 0x29 | |||
39 | #define ADT7460_TACH2L0x2a 0x2a | |||
40 | #define ADT7460_TACH2H0x2b 0x2b | |||
41 | #define ADT7460_TACH3L0x2c 0x2c | |||
42 | #define ADT7460_TACH3H0x2d 0x2d | |||
43 | #define ADT7460_TACH4L0x2e 0x2e | |||
44 | #define ADT7460_TACH4H0x2f 0x2f | |||
45 | #define ADT7460_TACH5L0xa9 0xa9 | |||
46 | #define ADT7460_TACH5H0xaa 0xaa | |||
47 | #define ADT7460_TACH6L0xab 0xab | |||
48 | #define ADT7460_TACH6H0xac 0xac | |||
49 | #define ADT7460_REVISION0x3f 0x3f | |||
50 | #define ADT7460_CONFIG0x40 0x40 | |||
51 | #define ADT7460_CONFIG_Vcc0x80 0x80 | |||
52 | ||||
53 | /* Sensors */ | |||
54 | #define ADT_2_5V0 0 | |||
55 | #define ADT_VCCP1 1 | |||
56 | #define ADT_VCC2 2 | |||
57 | #define ADT_V53 3 | |||
58 | #define ADT_V124 4 | |||
59 | #define ADT_VTR5 5 | |||
60 | #define ADT_VBAT6 6 | |||
61 | #define ADT_REM1_TEMP7 7 | |||
62 | #define ADT_LOCAL_TEMP8 8 | |||
63 | #define ADT_REM2_TEMP9 9 | |||
64 | #define ADT_TACH110 10 | |||
65 | #define ADT_TACH211 11 | |||
66 | #define ADT_TACH312 12 | |||
67 | #define ADT_TACH413 13 | |||
68 | #define ADT_TACH514 14 | |||
69 | #define ADT_TACH615 15 | |||
70 | #define ADT_NUM_SENSORS16 16 | |||
71 | ||||
72 | struct adt_chip { | |||
73 | const char *name; | |||
74 | short ratio[7]; | |||
75 | int type; | |||
76 | short vcc; | |||
77 | } adt_chips[] = { | |||
78 | /* register 0x20 0x21 0x22 0x23 0x24 0xa8 0xaa type */ | |||
79 | /* 2.5v vccp vcc 5v 12v vtr vbat */ | |||
80 | ||||
81 | { "adt7460", { 2500, 0, 3300, 0, 0, 0, 0 }, 7460, 5000 }, | |||
82 | { "adt7467", { 2500, 2250, 3300, 5000, 12000, 0, 0 }, 7467, 5000 }, | |||
83 | { "adt7475", { 0, 2250, 3300, 0, 0, 0, 0 }, 7475, 0 }, | |||
84 | { "adt7476", { 2500, 2250, 3300, 5000, 12000, 0, 0 }, 7476, 0 }, | |||
85 | { "adm1027", { 2500, 2250, 3300, 5000, 12000, 0, 0 }, 1027, 5000 }, | |||
86 | { "lm85", { 2500, 2250, 3300, 5000, 12000, 0, 0 }, 7467, 0 }, | |||
87 | { "emc6d100", { 2500, 2250, 3300, 5000, 12000, 0, 0 }, 6100, 0 }, | |||
88 | { "emc6w201", { 2500, 2250, 3300, 5000, 12000, 0, 0 }, 6201, 0 }, | |||
89 | { "lm96000", { 2500, 2250, 3300, 5000, 12000, 0, 0 }, 96000, 0 }, | |||
90 | { "sch5017", { 5000, 2250, 3300, 5000, 12000, 0, 0 }, 5017, 0 }, | |||
91 | { "sch5027", { 5000, 2250, 3300, 5000, 12000, 3300, 3300 }, 5027, 0 } | |||
92 | }; | |||
93 | ||||
94 | struct { | |||
95 | char sensor; | |||
96 | u_int8_t cmd; | |||
97 | u_short index; | |||
98 | } worklist[] = { | |||
99 | { ADT_2_5V0, ADT7460_2_5V0x20, 32768 + 0 }, | |||
100 | { ADT_VCCP1, ADT7460_VCCP0x21, 32768 + 1 }, | |||
101 | { ADT_VCC2, ADT7460_VCC0x22, 32768 + 2 }, | |||
102 | { ADT_V53, ADT7460_V50x23, 32768 + 3 }, | |||
103 | { ADT_V124, ADT7460_V120x24, 32768 + 4 }, | |||
104 | { ADT_VTR5, ADT7460_VTR0x99, 32768 + 5 }, | |||
105 | { ADT_VBAT6, ADT7460_VBAT0x9a, 32768 + 6 }, | |||
106 | { ADT_REM1_TEMP7, ADT7460_REM1_TEMP0x25 }, | |||
107 | { ADT_LOCAL_TEMP8, ADT7460_LOCAL_TEMP0x26 }, | |||
108 | { ADT_REM2_TEMP9, ADT7460_REM2_TEMP0x27 }, | |||
109 | { ADT_TACH110, ADT7460_TACH1L0x28 }, | |||
110 | { ADT_TACH211, ADT7460_TACH2L0x2a }, | |||
111 | { ADT_TACH312, ADT7460_TACH3L0x2c }, | |||
112 | { ADT_TACH413, ADT7460_TACH4L0x2e }, | |||
113 | { ADT_TACH514, ADT7460_TACH5L0xa9 }, | |||
114 | { ADT_TACH615, ADT7460_TACH6L0xab }, | |||
115 | }; | |||
116 | ||||
117 | struct adt_softc { | |||
118 | struct device sc_dev; | |||
119 | i2c_tag_t sc_tag; | |||
120 | i2c_addr_t sc_addr; | |||
121 | u_int8_t sc_conf; | |||
122 | struct adt_chip *chip; | |||
123 | ||||
124 | struct ksensor sc_sensor[ADT_NUM_SENSORS16]; | |||
125 | struct ksensordev sc_sensordev; | |||
126 | }; | |||
127 | ||||
128 | int adt_match(struct device *, void *, void *); | |||
129 | void adt_attach(struct device *, struct device *, void *); | |||
130 | ||||
131 | void adt_refresh(void *); | |||
132 | ||||
133 | struct cfattach adt_ca = { | |||
134 | sizeof(struct adt_softc), adt_match, adt_attach | |||
135 | }; | |||
136 | ||||
137 | struct cfdriver adt_cd = { | |||
138 | NULL((void *)0), "adt", DV_DULL | |||
139 | }; | |||
140 | ||||
141 | int | |||
142 | adt_match(struct device *parent, void *match, void *aux) | |||
143 | { | |||
144 | struct i2c_attach_args *ia = aux; | |||
145 | int i; | |||
146 | ||||
147 | for (i = 0; i < sizeof(adt_chips) / sizeof(adt_chips[0]); i++) | |||
148 | if (strcmp(ia->ia_name, adt_chips[i].name) == 0) | |||
149 | return (1); | |||
150 | return (0); | |||
151 | } | |||
152 | ||||
153 | void | |||
154 | adt_attach(struct device *parent, struct device *self, void *aux) | |||
155 | { | |||
156 | struct adt_softc *sc = (struct adt_softc *)self; | |||
157 | struct i2c_attach_args *ia = aux; | |||
158 | u_int8_t cmd, rev, data; | |||
159 | int i; | |||
160 | ||||
161 | sc->sc_tag = ia->ia_tag; | |||
162 | sc->sc_addr = ia->ia_addr; | |||
163 | ||||
164 | iic_acquire_bus(sc->sc_tag, 0)(*(sc->sc_tag)->ic_acquire_bus)((sc->sc_tag)->ic_cookie , (0)); | |||
165 | ||||
166 | for (i = 0; i < sizeof(adt_chips) / sizeof(adt_chips[0]); i++) { | |||
167 | if (strcmp(ia->ia_name, adt_chips[i].name) == 0) { | |||
168 | sc->chip = &adt_chips[i]; | |||
169 | break; | |||
170 | } | |||
171 | } | |||
172 | ||||
173 | cmd = ADT7460_REVISION0x3f; | |||
174 | if (iic_exec(sc->sc_tag, I2C_OP_READ_WITH_STOP, | |||
175 | sc->sc_addr, &cmd, sizeof cmd, &rev, sizeof rev, 0)) { | |||
176 | iic_release_bus(sc->sc_tag, 0)(*(sc->sc_tag)->ic_release_bus)((sc->sc_tag)->ic_cookie , (0)); | |||
177 | printf(": cannot read REV register\n"); | |||
178 | return; | |||
179 | } | |||
180 | ||||
181 | cmd = ADT7460_CONFIG0x40; | |||
182 | if (iic_exec(sc->sc_tag, I2C_OP_READ_WITH_STOP, | |||
183 | sc->sc_addr, &cmd, sizeof cmd, &sc->sc_conf, sizeof sc->sc_conf, 0)) { | |||
184 | iic_release_bus(sc->sc_tag, 0)(*(sc->sc_tag)->ic_release_bus)((sc->sc_tag)->ic_cookie , (0)); | |||
185 | printf(": cannot read config register\n"); | |||
186 | return; | |||
187 | } | |||
188 | ||||
189 | if (sc->chip->type == 7460) { | |||
190 | data = 1; | |||
191 | cmd = ADT7460_CONFIG0x40; | |||
192 | if (iic_exec(sc->sc_tag, I2C_OP_WRITE_WITH_STOP, | |||
193 | sc->sc_addr, &cmd, sizeof cmd, &data, sizeof data, 0)) { | |||
194 | iic_release_bus(sc->sc_tag, 0)(*(sc->sc_tag)->ic_release_bus)((sc->sc_tag)->ic_cookie , (0)); | |||
195 | printf(": cannot set control register\n"); | |||
196 | return; | |||
197 | } | |||
198 | } | |||
199 | ||||
200 | iic_release_bus(sc->sc_tag, 0)(*(sc->sc_tag)->ic_release_bus)((sc->sc_tag)->ic_cookie , (0)); | |||
201 | ||||
202 | printf(": %s rev 0x%02x", ia->ia_name, rev); | |||
203 | ||||
204 | /* Initialize sensor data. */ | |||
205 | strlcpy(sc->sc_sensordev.xname, sc->sc_dev.dv_xname, | |||
206 | sizeof(sc->sc_sensordev.xname)); | |||
207 | ||||
208 | sc->sc_sensor[ADT_2_5V0].type = SENSOR_VOLTS_DC; | |||
209 | strlcpy(sc->sc_sensor[ADT_2_5V0].desc, "+2.5Vin", | |||
210 | sizeof(sc->sc_sensor[ADT_2_5V0].desc)); | |||
211 | ||||
212 | if (sc->chip->type == 5017) | |||
213 | strlcpy(sc->sc_sensor[ADT_2_5V0].desc, "+5VTR", | |||
214 | sizeof(sc->sc_sensor[ADT_2_5V0].desc)); | |||
215 | if (sc->chip->type == 5027) | |||
216 | strlcpy(sc->sc_sensor[ADT_2_5V0].desc, "+5V", | |||
217 | sizeof(sc->sc_sensor[ADT_2_5V0].desc)); | |||
218 | ||||
219 | sc->sc_sensor[ADT_VCCP1].type = SENSOR_VOLTS_DC; | |||
220 | strlcpy(sc->sc_sensor[ADT_VCCP1].desc, "Vccp", | |||
221 | sizeof(sc->sc_sensor[ADT_VCCP1].desc)); | |||
222 | ||||
223 | sc->sc_sensor[ADT_VCC2].type = SENSOR_VOLTS_DC; | |||
224 | strlcpy(sc->sc_sensor[ADT_VCC2].desc, "Vcc", | |||
225 | sizeof(sc->sc_sensor[ADT_VCC2].desc)); | |||
226 | ||||
227 | sc->sc_sensor[ADT_V53].type = SENSOR_VOLTS_DC; | |||
228 | strlcpy(sc->sc_sensor[ADT_V53].desc, "+5V", | |||
229 | sizeof(sc->sc_sensor[ADT_V53].desc)); | |||
230 | ||||
231 | sc->sc_sensor[ADT_V124].type = SENSOR_VOLTS_DC; | |||
232 | strlcpy(sc->sc_sensor[ADT_V124].desc, "+12V", | |||
233 | sizeof(sc->sc_sensor[ADT_V124].desc)); | |||
234 | ||||
235 | sc->sc_sensor[ADT_VTR5].type = SENSOR_VOLTS_DC; | |||
236 | strlcpy(sc->sc_sensor[ADT_VTR5].desc, "+Vtr", | |||
237 | sizeof(sc->sc_sensor[ADT_VTR5].desc)); | |||
238 | ||||
239 | sc->sc_sensor[ADT_VBAT6].type = SENSOR_VOLTS_DC; | |||
240 | strlcpy(sc->sc_sensor[ADT_VBAT6].desc, "+Vbat", | |||
241 | sizeof(sc->sc_sensor[ADT_VBAT6].desc)); | |||
242 | ||||
243 | sc->sc_sensor[ADT_REM1_TEMP7].type = SENSOR_TEMP; | |||
244 | strlcpy(sc->sc_sensor[ADT_REM1_TEMP7].desc, "Remote", | |||
245 | sizeof(sc->sc_sensor[ADT_REM1_TEMP7].desc)); | |||
246 | ||||
247 | sc->sc_sensor[ADT_LOCAL_TEMP8].type = SENSOR_TEMP; | |||
248 | strlcpy(sc->sc_sensor[ADT_LOCAL_TEMP8].desc, "Internal", | |||
249 | sizeof(sc->sc_sensor[ADT_LOCAL_TEMP8].desc)); | |||
250 | ||||
251 | sc->sc_sensor[ADT_REM2_TEMP9].type = SENSOR_TEMP; | |||
252 | strlcpy(sc->sc_sensor[ADT_REM2_TEMP9].desc, "Remote", | |||
253 | sizeof(sc->sc_sensor[ADT_REM2_TEMP9].desc)); | |||
254 | ||||
255 | sc->sc_sensor[ADT_TACH110].type = SENSOR_FANRPM; | |||
256 | sc->sc_sensor[ADT_TACH211].type = SENSOR_FANRPM; | |||
257 | sc->sc_sensor[ADT_TACH312].type = SENSOR_FANRPM; | |||
258 | sc->sc_sensor[ADT_TACH413].type = SENSOR_FANRPM; | |||
259 | sc->sc_sensor[ADT_TACH514].type = SENSOR_FANRPM; | |||
260 | sc->sc_sensor[ADT_TACH615].type = SENSOR_FANRPM; | |||
261 | ||||
262 | if (sensor_task_register(sc, adt_refresh, 5) == NULL((void *)0)) { | |||
263 | printf(", unable to register update task\n"); | |||
264 | return; | |||
265 | } | |||
266 | ||||
267 | for (i = 0; i < ADT_NUM_SENSORS16; i++) { | |||
268 | if (worklist[i].index >= 32768 && | |||
269 | sc->chip->ratio[worklist[i].index - 32768] == 0) | |||
270 | continue; | |||
271 | sensor_attach(&sc->sc_sensordev, &sc->sc_sensor[i]); | |||
272 | } | |||
273 | sensordev_install(&sc->sc_sensordev); | |||
274 | ||||
275 | ||||
276 | printf("\n"); | |||
277 | } | |||
278 | ||||
279 | void | |||
280 | adt_refresh(void *arg) | |||
281 | { | |||
282 | struct adt_softc *sc = arg; | |||
283 | u_int8_t cmd, data, data2; | |||
284 | u_int16_t fan; | |||
285 | int i, ratio; | |||
| ||||
286 | ||||
287 | iic_acquire_bus(sc->sc_tag, 0)(*(sc->sc_tag)->ic_acquire_bus)((sc->sc_tag)->ic_cookie , (0)); | |||
288 | ||||
289 | for (i = 0; i < sizeof worklist / sizeof(worklist[0]); i++) { | |||
290 | ||||
291 | if (worklist[i].index >= 32768) { | |||
292 | ratio = sc->chip->ratio[worklist[i].index - 32768]; | |||
293 | if (ratio == 0) /* do not read a dead register */ | |||
294 | continue; | |||
295 | } | |||
296 | cmd = worklist[i].cmd; | |||
297 | if (iic_exec(sc->sc_tag, I2C_OP_READ_WITH_STOP, | |||
298 | sc->sc_addr, &cmd, sizeof cmd, &data, sizeof data, 0)) { | |||
299 | sc->sc_sensor[i].flags |= SENSOR_FINVALID0x0001; | |||
300 | continue; | |||
301 | } | |||
302 | ||||
303 | sc->sc_sensor[i].flags &= ~SENSOR_FINVALID0x0001; | |||
304 | switch (worklist[i].sensor) { | |||
305 | case ADT_VCC2: | |||
306 | if (sc->chip->vcc && (sc->sc_conf & ADT7460_CONFIG_Vcc0x80)) | |||
307 | ratio = sc->chip->vcc; | |||
308 | /* FALLTHROUGH */ | |||
309 | case ADT_2_5V0: | |||
310 | case ADT_VCCP1: | |||
311 | case ADT_V53: | |||
312 | case ADT_V124: | |||
313 | case ADT_VTR5: | |||
314 | case ADT_VBAT6: | |||
315 | sc->sc_sensor[i].value = ratio * 1000 * (u_int)data / 192; | |||
| ||||
316 | break; | |||
317 | case ADT_LOCAL_TEMP8: | |||
318 | case ADT_REM1_TEMP7: | |||
319 | case ADT_REM2_TEMP9: | |||
320 | if (data == 0x80) | |||
321 | sc->sc_sensor[i].flags |= SENSOR_FINVALID0x0001; | |||
322 | else | |||
323 | sc->sc_sensor[i].value = | |||
324 | (int8_t)data * 1000000 + 273150000; | |||
325 | break; | |||
326 | case ADT_TACH110: | |||
327 | case ADT_TACH211: | |||
328 | case ADT_TACH312: | |||
329 | case ADT_TACH413: | |||
330 | cmd = worklist[i].cmd + 1; /* TACHnH follows TACHnL */ | |||
331 | if (iic_exec(sc->sc_tag, I2C_OP_READ_WITH_STOP, | |||
332 | sc->sc_addr, &cmd, sizeof cmd, &data2, sizeof data2, 0)) { | |||
333 | sc->sc_sensor[i].flags |= SENSOR_FINVALID0x0001; | |||
334 | continue; | |||
335 | } | |||
336 | ||||
337 | fan = data + (data2 << 8); | |||
338 | if (fan == 0 || fan == 0xffff) | |||
339 | sc->sc_sensor[i].flags |= SENSOR_FINVALID0x0001; | |||
340 | else | |||
341 | sc->sc_sensor[i].value = (90000 * 60) / fan; | |||
342 | break; | |||
343 | case ADT_TACH514: | |||
344 | case ADT_TACH615: | |||
345 | if (sc->chip->type != 5027) { | |||
346 | sc->sc_sensor[i].flags |= SENSOR_FINVALID0x0001; | |||
347 | break; /* only 5027 has these fans? */ | |||
348 | } | |||
349 | cmd = worklist[i].cmd + 1; /* TACHnH follows TACHnL */ | |||
350 | if (iic_exec(sc->sc_tag, I2C_OP_READ_WITH_STOP, | |||
351 | sc->sc_addr, &cmd, sizeof cmd, &data2, sizeof data2, 0)) { | |||
352 | sc->sc_sensor[i].flags |= SENSOR_FINVALID0x0001; | |||
353 | continue; | |||
354 | } | |||
355 | ||||
356 | fan = data + (data2 << 8); | |||
357 | if (fan == 0 || fan == 0xffff) | |||
358 | sc->sc_sensor[i].flags |= SENSOR_FINVALID0x0001; | |||
359 | else | |||
360 | sc->sc_sensor[i].value = fan * 60; | |||
361 | break; | |||
362 | default: | |||
363 | sc->sc_sensor[i].flags |= SENSOR_FINVALID0x0001; | |||
364 | break; | |||
365 | } | |||
366 | } | |||
367 | ||||
368 | iic_release_bus(sc->sc_tag, 0)(*(sc->sc_tag)->ic_release_bus)((sc->sc_tag)->ic_cookie , (0)); | |||
369 | } |