Annotation of sys/dev/i2c/adt7460.c, Revision 1.1.1.1
1.1 nbrk 1: /* $OpenBSD: adt7460.c,v 1.18 2007/06/24 05:34:35 dlg 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_5V 0x20
28: #define ADT7460_VCCP 0x21
29: #define ADT7460_VCC 0x22
30: #define ADT7460_V5 0x23
31: #define ADT7460_V12 0x24
32: #define ADT7460_REM1_TEMP 0x25
33: #define ADT7460_LOCAL_TEMP 0x26
34: #define ADT7460_REM2_TEMP 0x27
35: #define ADT7460_TACH1L 0x28
36: #define ADT7460_TACH1H 0x29
37: #define ADT7460_TACH2L 0x2a
38: #define ADT7460_TACH2H 0x2b
39: #define ADT7460_TACH3L 0x2c
40: #define ADT7460_TACH3H 0x2d
41: #define ADT7460_TACH4L 0x2e
42: #define ADT7460_TACH4H 0x2f
43: #define ADT7460_REVISION 0x3f
44: #define ADT7460_CONFIG 0x40
45: #define ADT7460_CONFIG_Vcc 0x80
46:
47: /* Sensors */
48: #define ADT_2_5V 0
49: #define ADT_VCCP 1
50: #define ADT_VCC 2
51: #define ADT_V5 3
52: #define ADT_V12 4
53: #define ADT_REM1_TEMP 5
54: #define ADT_LOCAL_TEMP 6
55: #define ADT_REM2_TEMP 7
56: #define ADT_TACH1 8
57: #define ADT_TACH2 9
58: #define ADT_TACH3 10
59: #define ADT_TACH4 11
60: #define ADT_NUM_SENSORS 12
61:
62: struct adt_chip {
63: const char *name;
64: short ratio[5];
65: int type;
66: short vcc;
67: } adt_chips[] = {
68: /* register 0x20 0x21 0x22 0x23 0x24 type */
69: /* 2.5v vccp vcc 5v 12v */
70:
71: { "adt7460", { 2500, 0, 3300, 0, 0 }, 7460, 5000 },
72: { "adt7467", { 2500, 2250, 3300, 5000, 12000 }, 7467, 5000 },
73: { "adt7475", { 0, 2250, 3300, 0, 0 }, 7475, 0 },
74: { "adt7476", { 2500, 2250, 3300, 5000, 12000 }, 7476, 0 },
75: { "adm1027", { 2500, 2250, 3300, 5000, 12000 }, 1027, 5000 },
76: { "lm85", { 2500, 2250, 3300, 5000, 12000 }, 7467, 0 },
77: { "emc6d100", { 2500, 2250, 3300, 5000, 12000 }, 6100, 0 },
78: { "emc6w201", { 2500, 2250, 3300, 5000, 12000 }, 6201, 0 },
79: { "lm96000", { 2500, 2250, 3300, 5000, 12000 }, 96000, 0 },
80: { "sch5017", { 5000, 2250, 3300, 5000, 12000 }, 5017, 0 }
81: };
82:
83: struct {
84: char sensor;
85: u_int8_t cmd;
86: u_short index;
87: } worklist[] = {
88: { ADT_2_5V, ADT7460_2_5V, 32768 + 0 },
89: { ADT_VCCP, ADT7460_VCCP, 32768 + 1 },
90: { ADT_VCC, ADT7460_VCC, 32768 + 2 },
91: { ADT_V5, ADT7460_V5, 32768 + 3 },
92: { ADT_V12, ADT7460_V12, 32768 + 4 },
93: { ADT_REM1_TEMP, ADT7460_REM1_TEMP },
94: { ADT_LOCAL_TEMP, ADT7460_LOCAL_TEMP },
95: { ADT_REM2_TEMP, ADT7460_REM2_TEMP },
96: { ADT_TACH1, ADT7460_TACH1L },
97: { ADT_TACH2, ADT7460_TACH2L },
98: { ADT_TACH3, ADT7460_TACH3L },
99: { ADT_TACH4, ADT7460_TACH4L },
100: };
101:
102: struct adt_softc {
103: struct device sc_dev;
104: i2c_tag_t sc_tag;
105: i2c_addr_t sc_addr;
106: u_int8_t sc_conf;
107: struct adt_chip *chip;
108:
109: struct ksensor sc_sensor[ADT_NUM_SENSORS];
110: struct ksensordev sc_sensordev;
111: };
112:
113: int adt_match(struct device *, void *, void *);
114: void adt_attach(struct device *, struct device *, void *);
115:
116: void adt_refresh(void *);
117:
118: struct cfattach adt_ca = {
119: sizeof(struct adt_softc), adt_match, adt_attach
120: };
121:
122: struct cfdriver adt_cd = {
123: NULL, "adt", DV_DULL
124: };
125:
126: int
127: adt_match(struct device *parent, void *match, void *aux)
128: {
129: struct i2c_attach_args *ia = aux;
130: int i;
131:
132: for (i = 0; i < sizeof(adt_chips) / sizeof(adt_chips[0]); i++)
133: if (strcmp(ia->ia_name, adt_chips[i].name) == 0)
134: return (1);
135: return (0);
136: }
137:
138: void
139: adt_attach(struct device *parent, struct device *self, void *aux)
140: {
141: struct adt_softc *sc = (struct adt_softc *)self;
142: struct i2c_attach_args *ia = aux;
143: u_int8_t cmd, rev, data;
144: int i;
145:
146: sc->sc_tag = ia->ia_tag;
147: sc->sc_addr = ia->ia_addr;
148:
149: iic_acquire_bus(sc->sc_tag, 0);
150:
151: for (i = 0; i < sizeof(adt_chips) / sizeof(adt_chips[0]); i++) {
152: if (strcmp(ia->ia_name, adt_chips[i].name) == 0) {
153: sc->chip = &adt_chips[i];
154: break;
155: }
156: }
157:
158: cmd = ADT7460_REVISION;
159: if (iic_exec(sc->sc_tag, I2C_OP_READ_WITH_STOP,
160: sc->sc_addr, &cmd, sizeof cmd, &rev, sizeof rev, 0)) {
161: iic_release_bus(sc->sc_tag, 0);
162: printf(": cannot read REV register\n");
163: return;
164: }
165:
166: cmd = ADT7460_CONFIG;
167: if (iic_exec(sc->sc_tag, I2C_OP_READ_WITH_STOP,
168: sc->sc_addr, &cmd, sizeof cmd, &sc->sc_conf, sizeof sc->sc_conf, 0)) {
169: iic_release_bus(sc->sc_tag, 0);
170: printf(": cannot read config register\n");
171: return;
172: }
173:
174: if (sc->chip->type == 7460) {
175: data = 1;
176: cmd = ADT7460_CONFIG;
177: if (iic_exec(sc->sc_tag, I2C_OP_WRITE_WITH_STOP,
178: sc->sc_addr, &cmd, sizeof cmd, &data, sizeof data, 0)) {
179: iic_release_bus(sc->sc_tag, 0);
180: printf(": cannot set control register\n");
181: return;
182: }
183: }
184:
185: iic_release_bus(sc->sc_tag, 0);
186:
187: printf(": %s rev 0x%02x", ia->ia_name, rev);
188:
189: /* Initialize sensor data. */
190: strlcpy(sc->sc_sensordev.xname, sc->sc_dev.dv_xname,
191: sizeof(sc->sc_sensordev.xname));
192:
193: sc->sc_sensor[ADT_2_5V].type = SENSOR_VOLTS_DC;
194: strlcpy(sc->sc_sensor[ADT_2_5V].desc, "+2.5Vin",
195: sizeof(sc->sc_sensor[ADT_2_5V].desc));
196:
197: if (sc->chip->type == 5017)
198: strlcpy(sc->sc_sensor[ADT_2_5V].desc, "+5VTR",
199: sizeof(sc->sc_sensor[ADT_2_5V].desc));
200:
201: sc->sc_sensor[ADT_VCCP].type = SENSOR_VOLTS_DC;
202: strlcpy(sc->sc_sensor[ADT_VCCP].desc, "Vccp",
203: sizeof(sc->sc_sensor[ADT_VCCP].desc));
204:
205: sc->sc_sensor[ADT_VCC].type = SENSOR_VOLTS_DC;
206: strlcpy(sc->sc_sensor[ADT_VCC].desc, "Vcc",
207: sizeof(sc->sc_sensor[ADT_VCC].desc));
208:
209: sc->sc_sensor[ADT_V5].type = SENSOR_VOLTS_DC;
210: strlcpy(sc->sc_sensor[ADT_V5].desc, "+5V",
211: sizeof(sc->sc_sensor[ADT_V5].desc));
212:
213: sc->sc_sensor[ADT_V12].type = SENSOR_VOLTS_DC;
214: strlcpy(sc->sc_sensor[ADT_V12].desc, "+12V",
215: sizeof(sc->sc_sensor[ADT_V12].desc));
216:
217: sc->sc_sensor[ADT_REM1_TEMP].type = SENSOR_TEMP;
218: strlcpy(sc->sc_sensor[ADT_REM1_TEMP].desc, "Remote",
219: sizeof(sc->sc_sensor[ADT_REM1_TEMP].desc));
220:
221: sc->sc_sensor[ADT_LOCAL_TEMP].type = SENSOR_TEMP;
222: strlcpy(sc->sc_sensor[ADT_LOCAL_TEMP].desc, "Internal",
223: sizeof(sc->sc_sensor[ADT_LOCAL_TEMP].desc));
224:
225: sc->sc_sensor[ADT_REM2_TEMP].type = SENSOR_TEMP;
226: strlcpy(sc->sc_sensor[ADT_REM2_TEMP].desc, "Remote",
227: sizeof(sc->sc_sensor[ADT_REM2_TEMP].desc));
228:
229: sc->sc_sensor[ADT_TACH1].type = SENSOR_FANRPM;
230: sc->sc_sensor[ADT_TACH2].type = SENSOR_FANRPM;
231: sc->sc_sensor[ADT_TACH3].type = SENSOR_FANRPM;
232: sc->sc_sensor[ADT_TACH4].type = SENSOR_FANRPM;
233:
234: if (sensor_task_register(sc, adt_refresh, 5) == NULL) {
235: printf(", unable to register update task\n");
236: return;
237: }
238:
239: for (i = 0; i < ADT_NUM_SENSORS; i++) {
240: if (worklist[i].index >= 32768 &&
241: sc->chip->ratio[worklist[i].index - 32768] == 0)
242: continue;
243: sc->sc_sensor[i].flags &= ~SENSOR_FINVALID;
244: sensor_attach(&sc->sc_sensordev, &sc->sc_sensor[i]);
245: }
246: sensordev_install(&sc->sc_sensordev);
247:
248:
249: printf("\n");
250: }
251:
252: void
253: adt_refresh(void *arg)
254: {
255: struct adt_softc *sc = arg;
256: u_int8_t cmd, data, data2;
257: u_int16_t fan;
258: int i, ratio;
259:
260: iic_acquire_bus(sc->sc_tag, 0);
261:
262: for (i = 0; i < sizeof worklist / sizeof(worklist[0]); i++) {
263:
264: if (worklist[i].index >= 32768) {
265: ratio = sc->chip->ratio[worklist[i].index - 32768];
266: if (ratio == 0) /* do not read a dead register */
267: continue;
268: }
269: cmd = worklist[i].cmd;
270: if (iic_exec(sc->sc_tag, I2C_OP_READ_WITH_STOP,
271: sc->sc_addr, &cmd, sizeof cmd, &data, sizeof data, 0)) {
272: sc->sc_sensor[i].flags |= SENSOR_FINVALID;
273: continue;
274: }
275:
276: sc->sc_sensor[i].flags &= ~SENSOR_FINVALID;
277: switch (worklist[i].sensor) {
278: case ADT_VCC:
279: if (sc->chip->vcc && (sc->sc_conf & ADT7460_CONFIG_Vcc))
280: ratio = sc->chip->vcc;
281: /* FALLTHROUGH */
282: case ADT_2_5V:
283: case ADT_VCCP:
284: case ADT_V5:
285: case ADT_V12:
286: sc->sc_sensor[i].value = ratio * 1000 * (u_int)data / 192;
287: break;
288: case ADT_LOCAL_TEMP:
289: case ADT_REM1_TEMP:
290: case ADT_REM2_TEMP:
291: if (data == 0x80)
292: sc->sc_sensor[i].flags |= SENSOR_FINVALID;
293: else
294: sc->sc_sensor[i].value =
295: (int8_t)data * 1000000 + 273150000;
296: break;
297: case ADT_TACH1:
298: case ADT_TACH2:
299: case ADT_TACH3:
300: case ADT_TACH4:
301: cmd = worklist[i].cmd + 1; /* TACHnH follows TACHnL */
302: if (iic_exec(sc->sc_tag, I2C_OP_READ_WITH_STOP,
303: sc->sc_addr, &cmd, sizeof cmd, &data2, sizeof data2, 0)) {
304: sc->sc_sensor[i].flags |= SENSOR_FINVALID;
305: continue;
306: }
307:
308: fan = data + (data2 << 8);
309: if (fan == 0 || fan == 0xffff)
310: sc->sc_sensor[i].flags |= SENSOR_FINVALID;
311: else
312: sc->sc_sensor[i].value = (90000 * 60) / fan;
313: break;
314: default:
315: sc->sc_sensor[i].flags |= SENSOR_FINVALID;
316: break;
317: }
318: }
319:
320: iic_release_bus(sc->sc_tag, 0);
321: }
CVSweb