Annotation of sys/dev/i2c/fintek.c, Revision 1.1.1.1
1.1 nbrk 1: /* $OpenBSD: fintek.c,v 1.6 2007/06/24 05:34:35 dlg Exp $ */
2: /*
3: * Copyright (c) 2006 Dale Rahn <drahn@openbsd.org>
4: *
5: * Permission to use, copy, modify, and distribute this software for any
6: * purpose with or without fee is hereby granted, provided that the above
7: * copyright notice and this permission notice appear in all copies.
8: *
9: * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
10: * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
11: * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
12: * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
13: * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
14: * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
15: * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
16: */
17:
18: #include <sys/param.h>
19: #include <sys/systm.h>
20: #include <sys/device.h>
21: #include <sys/sensors.h>
22:
23: #include <dev/i2c/i2cvar.h>
24:
25: /* Sensors */
26: #define F_VCC 0
27: #define F_V1 1
28: #define F_V2 2
29: #define F_V3 3
30: #define F_TEMP1 4
31: #define F_TEMP2 5
32: #define F_FAN1 6
33: #define F_FAN2 7
34: #define F_NUM_SENSORS 8
35:
36: struct fintek_softc {
37: struct device sc_dev;
38: i2c_tag_t sc_tag;
39: i2c_addr_t sc_addr;
40:
41: struct ksensor sc_sensor[F_NUM_SENSORS];
42: struct ksensordev sc_sensordev;
43: };
44:
45: int fintek_match(struct device *, void *, void *);
46: void fintek_attach(struct device *, struct device *, void *);
47:
48: void fintek_refresh(void *);
49: int fintek_read_reg(struct fintek_softc *sc, u_int8_t cmd, u_int8_t *data,
50: size_t size);
51: int fintek_write_reg(struct fintek_softc *sc, u_int8_t cmd, u_int8_t *data,
52: size_t size);
53: void fintek_fullspeed(struct fintek_softc *sc);
54:
55: struct cfattach fintek_ca = {
56: sizeof(struct fintek_softc), fintek_match, fintek_attach
57: };
58:
59: struct cfdriver fintek_cd = {
60: NULL, "fintek", DV_DULL
61: };
62:
63: #define FINTEK_CONFIG1 0x01
64: #define FINTEK_FAN1_LINEAR_MODE 0x10
65: #define FINTEK_FAN2_LINEAR_MODE 0x20
66: #define FINTEK_VOLT0 0x10
67: #define FINTEK_VOLT1 0x11
68: #define FINTEK_VOLT2 0x12
69: #define FINTEK_VOLT3 0x13
70: #define FINTEK_TEMP1 0x14
71: #define FINTEK_TEMP2 0x15
72: #define FINTEK_FAN1 0x16
73: #define FINTEK_FAN2 0x18
74: #define FINTEK_VERSION 0x5c
75: #define FINTEK_RSTCR 0x60
76: #define FINTEK_FAN1_MODE_MANUAL 0x30
77: #define FINTEK_FAN2_MODE_MANUAL 0xc0
78: #define FINTEK_PWM_DUTY1 0x76
79: #define FINTEK_PWM_DUTY2 0x86
80:
81: /* Options passed via the 'flags' config keyword. */
82: #define FINTEK_OPTION_FULLSPEED 0x0001
83:
84: int
85: fintek_match(struct device *parent, void *match, void *aux)
86: {
87: struct i2c_attach_args *ia = aux;
88:
89: if (strcmp(ia->ia_name, "f75375") == 0)
90: return (1);
91: return (0);
92: }
93:
94: int
95: fintek_read_reg(struct fintek_softc *sc, u_int8_t cmd, u_int8_t *data,
96: size_t size)
97: {
98: return iic_exec(sc->sc_tag, I2C_OP_READ_WITH_STOP,
99: sc->sc_addr, &cmd, sizeof cmd, data, size, 0);
100: }
101:
102: int
103: fintek_write_reg(struct fintek_softc *sc, u_int8_t cmd, u_int8_t *data,
104: size_t size)
105: {
106: return iic_exec(sc->sc_tag, I2C_OP_WRITE_WITH_STOP,
107: sc->sc_addr, &cmd, sizeof cmd, data, size, 0);
108: }
109:
110: void
111: fintek_attach(struct device *parent, struct device *self, void *aux)
112: {
113: struct fintek_softc *sc = (struct fintek_softc *)self;
114: struct i2c_attach_args *ia = aux;
115: u_int8_t cmd, data;
116: int i;
117:
118: sc->sc_tag = ia->ia_tag;
119: sc->sc_addr = ia->ia_addr;
120:
121: iic_acquire_bus(sc->sc_tag, 0);
122:
123: cmd = FINTEK_VERSION;
124: if (fintek_read_reg(sc, cmd, &data, sizeof data))
125: goto failread;
126:
127: printf(": F75375 rev %d.%d", data>> 4, data & 0xf);
128:
129: /*
130: * It seems the fan in the Thecus n2100 doesn't provide a
131: * reliable fan count. As a result the automatic fan
132: * controlling mode that the chip comes up in after reset
133: * doesn't work reliably. So we have a flag to drive the fan
134: * at maximum voltage such that the box doesn't overheat.
135: */
136: if (sc->sc_dev.dv_cfdata->cf_flags & FINTEK_OPTION_FULLSPEED)
137: fintek_fullspeed(sc);
138:
139: iic_release_bus(sc->sc_tag, 0);
140:
141: strlcpy(sc->sc_sensordev.xname, sc->sc_dev.dv_xname,
142: sizeof(sc->sc_sensordev.xname));
143:
144: sc->sc_sensor[F_VCC].type = SENSOR_VOLTS_DC;
145: strlcpy(sc->sc_sensor[F_VCC].desc, "Vcc",
146: sizeof(sc->sc_sensor[F_VCC].desc));
147:
148: sc->sc_sensor[F_V1].type = SENSOR_VOLTS_DC;
149: sc->sc_sensor[F_V2].type = SENSOR_VOLTS_DC;
150: sc->sc_sensor[F_V3].type = SENSOR_VOLTS_DC;
151:
152: sc->sc_sensor[F_TEMP1].type = SENSOR_TEMP;
153: sc->sc_sensor[F_TEMP2].type = SENSOR_TEMP;
154:
155: sc->sc_sensor[F_FAN1].type = SENSOR_FANRPM;
156: sc->sc_sensor[F_FAN2].type = SENSOR_FANRPM;
157:
158: if (sensor_task_register(sc, fintek_refresh, 5) == NULL) {
159: printf(", unable to register update task\n");
160: return;
161: }
162:
163: for (i = 0; i < F_NUM_SENSORS; i++) {
164: sc->sc_sensor[i].flags &= ~SENSOR_FINVALID;
165: sensor_attach(&sc->sc_sensordev, &sc->sc_sensor[i]);
166: }
167: sensordev_install(&sc->sc_sensordev);
168:
169: printf("\n");
170: return;
171:
172: failread:
173: printf("unable to read reg %d\n", cmd);
174: iic_release_bus(sc->sc_tag, 0);
175: return;
176: }
177:
178:
179: struct {
180: char sensor;
181: u_int8_t cmd;
182: } fintek_worklist[] = {
183: { F_VCC, FINTEK_VOLT0 },
184: { F_V1, FINTEK_VOLT1 },
185: { F_V2, FINTEK_VOLT2 },
186: { F_V3, FINTEK_VOLT3 },
187: { F_TEMP1, FINTEK_TEMP1 },
188: { F_TEMP2, FINTEK_TEMP2 },
189: { F_FAN1, FINTEK_FAN1 },
190: { F_FAN2, FINTEK_FAN2 }
191: };
192: #define FINTEK_WORKLIST_SZ (sizeof(fintek_worklist) / sizeof(fintek_worklist[0]))
193:
194: void
195: fintek_refresh(void *arg)
196: {
197: struct fintek_softc *sc = arg;
198: u_int8_t cmd, data, data2;
199: int i;
200:
201: iic_acquire_bus(sc->sc_tag, 0);
202:
203: for (i = 0; i < FINTEK_WORKLIST_SZ; i++){
204: cmd = fintek_worklist[i].cmd;
205: if (fintek_read_reg(sc, cmd, &data, sizeof data)) {
206: sc->sc_sensor[i].flags |= SENSOR_FINVALID;
207: continue;
208: }
209: sc->sc_sensor[i].flags &= ~SENSOR_FINVALID;
210: switch (fintek_worklist[i].sensor) {
211: case F_VCC:
212: sc->sc_sensor[i].value = data * 16000;
213: break;
214: case F_V1:
215: /* FALLTHROUGH */
216: case F_V2:
217: /* FALLTHROUGH */
218: case F_V3:
219: sc->sc_sensor[i].value = data * 8000;
220: break;
221: case F_TEMP1:
222: /* FALLTHROUGH */
223: case F_TEMP2:
224: sc->sc_sensor[i].value = 273150000 + data * 1000000;
225: break;
226: case F_FAN1:
227: /* FALLTHROUGH */
228: case F_FAN2:
229: /* FANx LSB follows FANx MSB */
230: cmd = fintek_worklist[i].cmd + 1;
231: if (fintek_read_reg(sc, cmd, &data2, sizeof data2)) {
232: sc->sc_sensor[i].flags |= SENSOR_FINVALID;
233: continue;
234: }
235: if ((data == 0xff && data2 == 0xff) ||
236: (data == 0 && data2 == 0))
237: sc->sc_sensor[i].value = 0;
238: else
239: sc->sc_sensor[i].value = 1500000 /
240: (data << 8 | data2);
241: break;
242: default:
243: sc->sc_sensor[i].flags |= SENSOR_FINVALID;
244: break;
245: }
246: }
247:
248: iic_release_bus(sc->sc_tag, 0);
249: }
250:
251: void
252: fintek_fullspeed(struct fintek_softc *sc)
253: {
254: u_int8_t data;
255:
256: data = FINTEK_FAN1_LINEAR_MODE | FINTEK_FAN2_LINEAR_MODE;
257: fintek_write_reg(sc, FINTEK_CONFIG1, &data, sizeof data);
258:
259: data = FINTEK_FAN1_MODE_MANUAL | FINTEK_FAN2_MODE_MANUAL;
260: fintek_write_reg(sc, FINTEK_RSTCR, &data, sizeof data);
261:
262: data = 0xff; /* Maximum voltage */
263: fintek_write_reg(sc, FINTEK_PWM_DUTY1, &data, sizeof data);
264: fintek_write_reg(sc, FINTEK_PWM_DUTY2, &data, sizeof data);
265: }
CVSweb