Annotation of sys/dev/i2c/asb100.c, Revision 1.1.1.1
1.1 nbrk 1: /* $OpenBSD: asb100.c,v 1.10 2007/06/24 05:34:35 dlg Exp $ */
2:
3: /*
4: * Copyright (c) 2005 Damien Miller <djm@openbsd.org>
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: /* Apparently the ASB100 always lives here */
27: #define ASB100_ADDR 0x2d
28:
29: /* ASB100 registers */
30: #define ASB100_TEMP3 0x17
31: #define ASB100_TEMP3_MAX 0x18
32: #define ASB100_TEMP3_HYST 0x19
33: #define ASB100_VIN0 0x20
34: #define ASB100_VIN1 0x21
35: #define ASB100_VIN2 0x22
36: #define ASB100_VIN3 0x23
37: #define ASB100_VIN4 0x24
38: #define ASB100_VIN5 0x25
39: #define ASB100_VIN6 0x26
40: #define ASB100_TEMP0 0x27
41: #define ASB100_FAN0 0x28
42: #define ASB100_FAN1 0x29
43: #define ASB100_FAN2 0x30
44: #define ASB100_VIN0_MIN 0x2b
45: #define ASB100_VIN0_MAX 0x2c
46: #define ASB100_VIN1_MIN 0x2d
47: #define ASB100_VIN1_MAX 0x2e
48: #define ASB100_VIN2_MIN 0x2f
49: #define ASB100_VIN2_MAX 0x30
50: #define ASB100_VIN3_MIN 0x31
51: #define ASB100_VIN3_MAX 0x32
52: #define ASB100_VIN4_MIN 0x33
53: #define ASB100_VIN4_MAX 0x34
54: #define ASB100_VIN5_MIN 0x35
55: #define ASB100_VIN5_MAX 0x36
56: #define ASB100_VIN6_MIN 0x37
57: #define ASB100_VIN6_MAX 0x38
58: #define ASB100_TEMP0_MAX 0x39
59: #define ASB100_TEMP0_HYST 0x3a
60: #define ASB100_FAN0_MIN 0x3b
61: #define ASB100_FAN1_MIN 0x3c
62: #define ASB100_FAN2_MIN 0x3d
63: #define ASB100_CONFIG 0x40
64: #define ASB100_ALARM1 0x41
65: #define ASB100_ALARM2 0x42
66: #define ASB100_SMIM1 0x43
67: #define ASB100_SMIM2 0x44
68: #define ASB100_VID_FANDIV01 0x47 /* 0-3 vid, 4-5 fan0, 6-7 fan1 */
69: #define ASB100_I2C_ADDR 0x48
70: #define ASB100_CHIPID 0x49
71: #define ASB100_I2C_SUBADDR 0x4a
72: #define ASB100_PIN_FANDIV2 0x4b /* 6-7 fan2 */
73: #define ASB100_IRQ 0x4c
74: #define ASB100_BANK 0x4e
75: #define ASB100_CHIPMAN 0x4f
76: #define ASB100_VID_CHIPID 0x58 /* 0 vid highbit, 1-7 chipid */
77: #define ASB100_PWM 0x59 /* 0-3 duty cycle, 7 enable */
78:
79: /* TEMP1/2 sensors live on other chips, pointed to by the I2C_SUBADDR reg */
80: #define ASB100_SUB1_TEMP1 0x50 /* LM75 format */
81: #define ASB100_SUB1_TEMP1_HYST 0x53
82: #define ASB100_SUB1_TEMP1_MAX 0x55
83: #define ASB100_SUB2_TEMP2 0x50 /* LM75 format */
84: #define ASB100_SUB2_TEMP2_HYST 0x53
85: #define ASB100_SUB2_TEMP2_MAX 0x55
86:
87: /* Sensors */
88: #define ASB100_SENSOR_VIN0 0
89: #define ASB100_SENSOR_VIN1 1
90: #define ASB100_SENSOR_VIN2 2
91: #define ASB100_SENSOR_VIN3 3
92: #define ASB100_SENSOR_VIN4 4
93: #define ASB100_SENSOR_VIN5 5
94: #define ASB100_SENSOR_VIN6 6
95: #define ASB100_SENSOR_FAN0 7
96: #define ASB100_SENSOR_FAN1 8
97: #define ASB100_SENSOR_FAN2 9
98: #define ASB100_SENSOR_TEMP0 10
99: #define ASB100_SENSOR_TEMP1 11
100: #define ASB100_SENSOR_TEMP2 12
101: #define ASB100_SENSOR_TEMP3 13
102: #define ASB100_NUM_SENSORS 14
103:
104: struct asbtm_softc {
105: struct device sc_dev;
106: i2c_tag_t sc_tag;
107: i2c_addr_t sc_addr;
108:
109: struct ksensor sc_sensor[ASB100_NUM_SENSORS];
110: struct ksensordev sc_sensordev;
111: int sc_fanmul[3];
112: int sc_satellite[2];
113: };
114:
115: int asbtm_banksel(struct asbtm_softc *, u_int8_t, u_int8_t *);
116: int asbtm_match(struct device *, void *, void *);
117: void asbtm_attach(struct device *, struct device *, void *);
118: void asbtm_refresh(void *);
119:
120: struct cfattach asbtm_ca = {
121: sizeof(struct asbtm_softc), asbtm_match, asbtm_attach
122: };
123:
124: struct cfdriver asbtm_cd = {
125: NULL, "asbtm", DV_DULL
126: };
127:
128: int
129: asbtm_match(struct device *parent, void *match, void *aux)
130: {
131: struct i2c_attach_args *ia = aux;
132:
133: if (strcmp(ia->ia_name, "asb100") == 0)
134: return (1);
135:
136: return (0);
137: }
138:
139: int
140: asbtm_banksel(struct asbtm_softc *sc, u_int8_t new_bank, u_int8_t *orig_bank)
141: {
142: u_int8_t cmd, data;
143:
144: new_bank &= 0xf;
145:
146: cmd = ASB100_BANK;
147: if (iic_exec(sc->sc_tag, I2C_OP_READ_WITH_STOP, sc->sc_addr,
148: &cmd, sizeof cmd, &data, sizeof data, 0))
149: return (-1);
150:
151: if (orig_bank != NULL)
152: *orig_bank = data & 0x0f;
153:
154: if ((data & 0xf) != new_bank) {
155: cmd = ASB100_BANK;
156: data = new_bank | (data & 0xf0);
157: if (iic_exec(sc->sc_tag, I2C_OP_WRITE_WITH_STOP, sc->sc_addr,
158: &cmd, sizeof cmd, &data, sizeof data, 0))
159: return (-1);
160: }
161:
162: return (0);
163: }
164:
165: void
166: asbtm_attach(struct device *parent, struct device *self, void *aux)
167: {
168: struct asbtm_softc *sc = (struct asbtm_softc *)self;
169: struct i2c_attach_args *ia = aux;
170: u_int8_t orig_bank, cmd, data;
171: int i;
172:
173: sc->sc_tag = ia->ia_tag;
174: sc->sc_addr = ia->ia_addr;
175:
176: iic_acquire_bus(sc->sc_tag, 0);
177:
178: if (asbtm_banksel(sc, 0, &orig_bank) == -1) {
179: printf(": cannot get/set register bank\n");
180: iic_release_bus(sc->sc_tag, 0);
181: return;
182: }
183:
184: cmd = ASB100_VID_FANDIV01;
185: if (iic_exec(sc->sc_tag, I2C_OP_READ_WITH_STOP, sc->sc_addr,
186: &cmd, sizeof cmd, &data, sizeof data, 0)) {
187: printf(": cannot get fan01 register\n");
188: iic_release_bus(sc->sc_tag, 0);
189: return;
190: }
191: sc->sc_fanmul[0] = (1 << (data >> 4) & 0x3);
192: sc->sc_fanmul[1] = (1 << (data >> 6) & 0x3);
193:
194: cmd = ASB100_PIN_FANDIV2;
195: if (iic_exec(sc->sc_tag, I2C_OP_READ_WITH_STOP, sc->sc_addr,
196: &cmd, sizeof cmd, &data, sizeof data, 0)) {
197: printf(": cannot get fan2 register\n");
198: iic_release_bus(sc->sc_tag, 0);
199: return;
200: }
201: sc->sc_fanmul[0] = (1 << (data >> 6) & 0x3);
202:
203: cmd = ASB100_I2C_SUBADDR;
204: if (iic_exec(sc->sc_tag, I2C_OP_READ_WITH_STOP, sc->sc_addr,
205: &cmd, sizeof cmd, &data, sizeof data, 0)) {
206: printf(": cannot get satellite chip address register\n");
207: iic_release_bus(sc->sc_tag, 0);
208: return;
209: }
210: /* Maybe a relative address of zero means "not present" here... */
211: sc->sc_satellite[0] = 0x48 + (data & 0xf);
212: sc->sc_satellite[1] = 0x48 + ((data >> 4) & 0xf);
213:
214: iic_ignore_addr(sc->sc_satellite[0]);
215: iic_ignore_addr(sc->sc_satellite[1]);
216: if (sc->sc_satellite[0] == sc->sc_satellite[1])
217: sc->sc_satellite[1] = -1;
218:
219: if (asbtm_banksel(sc, orig_bank, NULL) == -1) {
220: printf(": cannot restore saved bank %d\n", orig_bank);
221: iic_release_bus(sc->sc_tag, 0);
222: return;
223: }
224:
225: iic_release_bus(sc->sc_tag, 0);
226:
227: /* Initialize sensor data. */
228: strlcpy(sc->sc_sensordev.xname, sc->sc_dev.dv_xname,
229: sizeof(sc->sc_sensordev.xname));
230:
231: sc->sc_sensor[ASB100_SENSOR_VIN0].type = SENSOR_VOLTS_DC;
232: sc->sc_sensor[ASB100_SENSOR_VIN1].type = SENSOR_VOLTS_DC;
233: sc->sc_sensor[ASB100_SENSOR_VIN2].type = SENSOR_VOLTS_DC;
234: sc->sc_sensor[ASB100_SENSOR_VIN3].type = SENSOR_VOLTS_DC;
235: sc->sc_sensor[ASB100_SENSOR_VIN4].type = SENSOR_VOLTS_DC;
236: sc->sc_sensor[ASB100_SENSOR_VIN5].type = SENSOR_VOLTS_DC;
237: sc->sc_sensor[ASB100_SENSOR_VIN6].type = SENSOR_VOLTS_DC;
238:
239: sc->sc_sensor[ASB100_SENSOR_FAN0].type = SENSOR_FANRPM;
240: sc->sc_sensor[ASB100_SENSOR_FAN1].type = SENSOR_FANRPM;
241: sc->sc_sensor[ASB100_SENSOR_FAN2].type = SENSOR_FANRPM;
242:
243: sc->sc_sensor[ASB100_SENSOR_TEMP0].type = SENSOR_TEMP;
244: strlcpy(sc->sc_sensor[ASB100_SENSOR_TEMP0].desc, "External",
245: sizeof(sc->sc_sensor[ASB100_SENSOR_TEMP0].desc));
246:
247: sc->sc_sensor[ASB100_SENSOR_TEMP1].type = SENSOR_TEMP;
248: strlcpy(sc->sc_sensor[ASB100_SENSOR_TEMP1].desc, "Internal",
249: sizeof(sc->sc_sensor[ASB100_SENSOR_TEMP1].desc));
250:
251: sc->sc_sensor[ASB100_SENSOR_TEMP2].type = SENSOR_TEMP;
252: strlcpy(sc->sc_sensor[ASB100_SENSOR_TEMP2].desc, "Internal",
253: sizeof(sc->sc_sensor[ASB100_SENSOR_TEMP2].desc));
254: if (sc->sc_satellite[1] == -1)
255: sc->sc_sensor[ASB100_SENSOR_TEMP2].flags |= SENSOR_FINVALID;
256:
257: sc->sc_sensor[ASB100_SENSOR_TEMP3].type = SENSOR_TEMP;
258: strlcpy(sc->sc_sensor[ASB100_SENSOR_TEMP3].desc, "External",
259: sizeof(sc->sc_sensor[ASB100_SENSOR_TEMP3].desc));
260:
261: if (sensor_task_register(sc, asbtm_refresh, 5) == NULL) {
262: printf(", unable to register update task\n");
263: return;
264: }
265:
266: for (i = 0; i < ASB100_NUM_SENSORS; i++)
267: sensor_attach(&sc->sc_sensordev, &sc->sc_sensor[i]);
268: sensordev_install(&sc->sc_sensordev);
269:
270: printf("\n");
271: }
272:
273: static void
274: fanval(struct ksensor *sens, int mul, u_int8_t data)
275: {
276: int tmp = data * mul;
277:
278: if (tmp == 0)
279: sens->flags |= SENSOR_FINVALID;
280: else {
281: sens->value = 1350000 / tmp;
282: sens->flags &= ~SENSOR_FINVALID;
283: }
284: }
285:
286: void
287: asbtm_refresh(void *arg)
288: {
289: struct asbtm_softc *sc = arg;
290: u_int8_t orig_bank, cmd, data;
291: int8_t sdata;
292: u_int16_t sdata2;
293:
294: iic_acquire_bus(sc->sc_tag, 0);
295:
296: if (asbtm_banksel(sc, 0, &orig_bank) == -1) {
297: printf("%s: cannot get/set register bank\n",
298: sc->sc_dev.dv_xname);
299: iic_release_bus(sc->sc_tag, 0);
300: return;
301: }
302:
303: cmd = ASB100_VIN0;
304: if (iic_exec(sc->sc_tag, I2C_OP_READ_WITH_STOP, sc->sc_addr,
305: &cmd, sizeof cmd, &data, sizeof data, 0) == 0)
306: sc->sc_sensor[ASB100_SENSOR_VIN0].value = (data * 1000000) / 16;
307:
308: cmd = ASB100_VIN1;
309: if (iic_exec(sc->sc_tag, I2C_OP_READ_WITH_STOP, sc->sc_addr,
310: &cmd, sizeof cmd, &data, sizeof data, 0) == 0)
311: sc->sc_sensor[ASB100_SENSOR_VIN1].value = (data * 1000000) / 16;
312:
313: cmd = ASB100_VIN2;
314: if (iic_exec(sc->sc_tag, I2C_OP_READ_WITH_STOP, sc->sc_addr,
315: &cmd, sizeof cmd, &data, sizeof data, 0) == 0)
316: sc->sc_sensor[ASB100_SENSOR_VIN2].value = (data * 1000000) / 16;
317:
318: cmd = ASB100_VIN3;
319: if (iic_exec(sc->sc_tag, I2C_OP_READ_WITH_STOP, sc->sc_addr,
320: &cmd, sizeof cmd, &data, sizeof data, 0) == 0)
321: sc->sc_sensor[ASB100_SENSOR_VIN3].value = (data * 1000000) / 16;
322:
323: cmd = ASB100_VIN4;
324: if (iic_exec(sc->sc_tag, I2C_OP_READ_WITH_STOP, sc->sc_addr,
325: &cmd, sizeof cmd, &data, sizeof data, 0) == 0)
326: sc->sc_sensor[ASB100_SENSOR_VIN4].value = (data * 1000000) / 16;
327:
328: cmd = ASB100_VIN5;
329: if (iic_exec(sc->sc_tag, I2C_OP_READ_WITH_STOP, sc->sc_addr,
330: &cmd, sizeof cmd, &data, sizeof data, 0) == 0)
331: sc->sc_sensor[ASB100_SENSOR_VIN5].value = (data * 1000000) / 16;
332:
333: cmd = ASB100_VIN6;
334: if (iic_exec(sc->sc_tag, I2C_OP_READ_WITH_STOP, sc->sc_addr,
335: &cmd, sizeof cmd, &data, sizeof data, 0) == 0)
336: sc->sc_sensor[ASB100_SENSOR_VIN6].value = (data * 1000000) / 16;
337:
338: cmd = ASB100_FAN0;
339: if (iic_exec(sc->sc_tag, I2C_OP_READ_WITH_STOP, sc->sc_addr,
340: &cmd, sizeof cmd, &data, sizeof data, 0) == 0)
341: fanval(&sc->sc_sensor[ASB100_SENSOR_FAN0],
342: sc->sc_fanmul[0], data);
343:
344: cmd = ASB100_FAN1;
345: if (iic_exec(sc->sc_tag, I2C_OP_READ_WITH_STOP, sc->sc_addr,
346: &cmd, sizeof cmd, &data, sizeof data, 0) == 0)
347: fanval(&sc->sc_sensor[ASB100_SENSOR_FAN1],
348: sc->sc_fanmul[1], data);
349:
350: cmd = ASB100_FAN2;
351: if (iic_exec(sc->sc_tag, I2C_OP_READ_WITH_STOP, sc->sc_addr,
352: &cmd, sizeof cmd, &data, sizeof data, 0) == 0)
353: fanval(&sc->sc_sensor[ASB100_SENSOR_FAN2],
354: sc->sc_fanmul[2], data);
355:
356: cmd = ASB100_TEMP0;
357: if (iic_exec(sc->sc_tag, I2C_OP_READ_WITH_STOP, sc->sc_addr,
358: &cmd, sizeof cmd, &sdata, sizeof sdata, 0) == 0)
359: sc->sc_sensor[ASB100_SENSOR_TEMP0].value = 273150000 +
360: 1000000 * sdata;
361:
362: cmd = ASB100_TEMP3;
363: if (iic_exec(sc->sc_tag, I2C_OP_READ_WITH_STOP, sc->sc_addr,
364: &cmd, sizeof cmd, &data, sizeof sdata, 0) == 0)
365: sc->sc_sensor[ASB100_SENSOR_TEMP3].value = 273150000 +
366: 1000000 * sdata;
367:
368: /* Read satellite chips for TEMP1/TEMP2 */
369: cmd = ASB100_SUB1_TEMP1;
370: if (sc->sc_satellite[0] != -1) {
371: if (iic_exec(sc->sc_tag, I2C_OP_READ_WITH_STOP,
372: sc->sc_satellite[0], &cmd, sizeof cmd, &sdata2,
373: sizeof sdata2, 0) == 0 && sdata2 != 0xffff) {
374: sc->sc_sensor[ASB100_SENSOR_TEMP1].value = 273150000 +
375: 500000 * (swap16(sdata2) / 128);
376: sc->sc_sensor[ASB100_SENSOR_TEMP2].flags &=
377: ~SENSOR_FINVALID;
378: } else {
379: sc->sc_sensor[ASB100_SENSOR_TEMP2].flags |=
380: SENSOR_FINVALID;
381: }
382: }
383:
384: cmd = ASB100_SUB2_TEMP2;
385: if (sc->sc_satellite[1] != -1) {
386: if (iic_exec(sc->sc_tag, I2C_OP_READ_WITH_STOP,
387: sc->sc_satellite[1], &cmd, sizeof cmd, &sdata2,
388: sizeof sdata2, 0) == 0 && sdata2 != 0xffff) {
389: sc->sc_sensor[ASB100_SENSOR_TEMP2].value = 273150000 +
390: 500000 * (swap16(sdata2) / 128);
391: sc->sc_sensor[ASB100_SENSOR_TEMP2].flags &=
392: ~SENSOR_FINVALID;
393: } else {
394: sc->sc_sensor[ASB100_SENSOR_TEMP2].flags |=
395: SENSOR_FINVALID;
396: }
397: }
398:
399: asbtm_banksel(sc, orig_bank, NULL);
400:
401: iic_release_bus(sc->sc_tag, 0);
402: }
CVSweb