Line data Source code
1 : /* $OpenBSD: adm1026.c,v 1.11 2008/06/09 16:21:33 cnst Exp $ */
2 :
3 : /*
4 : * Copyright (c) 2005 Theo de Raadt
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 : /* ADM 1026 registers */
27 : #define ADM1026_TEMP 0x1f
28 : #define ADM1026_STATUS 0x20
29 : #define ADM1026_Vbat 0x26
30 : #define ADM1026_Ain8 0x27
31 : #define ADM1026_EXT1 0x28
32 : #define ADM1026_EXT2 0x29
33 : #define ADM1026_V3_3stby 0x2a
34 : #define ADM1026_V3_3main 0x2b
35 : #define ADM1026_V5 0x2c
36 : #define ADM1026_Vccp 0x2d
37 : #define ADM1026_V12 0x2e
38 : #define ADM1026_Vminus12 0x2f
39 : #define ADM1026_FAN0 0x38
40 : #define ADM1026_FAN1 0x39
41 : #define ADM1026_FAN2 0x3a
42 : #define ADM1026_FAN3 0x3b
43 : #define ADM1026_FAN4 0x3c
44 : #define ADM1026_FAN5 0x3d
45 : #define ADM1026_FAN6 0x3e
46 : #define ADM1026_FAN7 0x3f
47 : #define ADM1026_EXT1_OFF 0x6e
48 : #define ADM1026_EXT2_OFF 0x6f
49 : #define ADM1026_FAN0123DIV 0x02
50 : #define ADM1026_FAN4567DIV 0x03
51 : #define ADM1026_CONTROL 0x00
52 : #define ADM1026_CONTROL_START 0x01
53 : #define ADM1026_CONTROL_INTCLR 0x04
54 :
55 : /* Sensors */
56 : #define ADMCTS_TEMP 0
57 : #define ADMCTS_EXT1 1
58 : #define ADMCTS_EXT2 2
59 : #define ADMCTS_Vbat 3
60 : #define ADMCTS_V3_3stby 4
61 : #define ADMCTS_V3_3main 5
62 : #define ADMCTS_V5 6
63 : #define ADMCTS_Vccp 7
64 : #define ADMCTS_V12 8
65 : #define ADMCTS_Vminus12 9
66 : #define ADMCTS_FAN0 10
67 : #define ADMCTS_FAN1 11
68 : #define ADMCTS_FAN2 12
69 : #define ADMCTS_FAN3 13
70 : #define ADMCTS_FAN4 14
71 : #define ADMCTS_FAN5 15
72 : #define ADMCTS_FAN6 16
73 : #define ADMCTS_FAN7 17
74 : #define ADMCTS_NUM_SENSORS 18
75 :
76 : struct admcts_softc {
77 : struct device sc_dev;
78 : i2c_tag_t sc_tag;
79 : i2c_addr_t sc_addr;
80 :
81 : struct ksensor sc_sensor[ADMCTS_NUM_SENSORS];
82 : struct ksensordev sc_sensordev;
83 : int sc_fanmul[8];
84 : };
85 :
86 : int admcts_match(struct device *, void *, void *);
87 : void admcts_attach(struct device *, struct device *, void *);
88 : void admcts_refresh(void *);
89 :
90 : struct cfattach admcts_ca = {
91 : sizeof(struct admcts_softc), admcts_match, admcts_attach
92 : };
93 :
94 : struct cfdriver admcts_cd = {
95 : NULL, "admcts", DV_DULL
96 : };
97 :
98 : int
99 0 : admcts_match(struct device *parent, void *match, void *aux)
100 : {
101 0 : struct i2c_attach_args *ia = aux;
102 :
103 0 : if (strcmp(ia->ia_name, "adm1026") == 0)
104 0 : return (1);
105 0 : return (0);
106 0 : }
107 :
108 : void
109 0 : admcts_attach(struct device *parent, struct device *self, void *aux)
110 : {
111 0 : struct admcts_softc *sc = (struct admcts_softc *)self;
112 0 : struct i2c_attach_args *ia = aux;
113 0 : u_int8_t cmd, data, data2;
114 : int i;
115 :
116 0 : sc->sc_tag = ia->ia_tag;
117 0 : sc->sc_addr = ia->ia_addr;
118 :
119 0 : iic_acquire_bus(sc->sc_tag, 0);
120 0 : cmd = ADM1026_CONTROL;
121 0 : if (iic_exec(sc->sc_tag, I2C_OP_READ_WITH_STOP,
122 0 : sc->sc_addr, &cmd, sizeof cmd, &data, sizeof data, 0)) {
123 0 : iic_release_bus(sc->sc_tag, 0);
124 0 : printf(": cannot get control register\n");
125 0 : return;
126 : }
127 0 : data2 = data | ADM1026_CONTROL_START;
128 0 : data2 = data2 & ~ADM1026_CONTROL_INTCLR;
129 0 : if (data != data2) {
130 0 : if (iic_exec(sc->sc_tag, I2C_OP_WRITE_WITH_STOP,
131 0 : sc->sc_addr, &cmd, sizeof cmd, &data2, sizeof data2, 0)) {
132 0 : iic_release_bus(sc->sc_tag, 0);
133 0 : printf(": cannot set control register\n");
134 0 : return;
135 : }
136 : }
137 :
138 0 : cmd = ADM1026_FAN0123DIV;
139 0 : if (iic_exec(sc->sc_tag, I2C_OP_READ_WITH_STOP,
140 0 : sc->sc_addr, &cmd, sizeof cmd, &data, sizeof data, 0)) {
141 0 : iic_release_bus(sc->sc_tag, 0);
142 0 : printf(": cannot get fan0123div register\n");
143 0 : return;
144 : }
145 0 : sc->sc_fanmul[0] = (1 << ((data >> 0) & 0x3));
146 0 : sc->sc_fanmul[1] = (1 << ((data >> 2) & 0x3));
147 0 : sc->sc_fanmul[2] = (1 << ((data >> 4) & 0x3));
148 0 : sc->sc_fanmul[3] = (1 << ((data >> 6) & 0x3));
149 :
150 0 : cmd = ADM1026_FAN4567DIV;
151 0 : if (iic_exec(sc->sc_tag, I2C_OP_READ_WITH_STOP,
152 0 : sc->sc_addr, &cmd, sizeof cmd, &data, sizeof data, 0)) {
153 0 : iic_release_bus(sc->sc_tag, 0);
154 0 : printf(": cannot get fan0123div register\n");
155 0 : return;
156 : }
157 0 : sc->sc_fanmul[4] = (1 << ((data >> 0) & 0x3));
158 0 : sc->sc_fanmul[5] = (1 << ((data >> 2) & 0x3));
159 0 : sc->sc_fanmul[6] = (1 << ((data >> 4) & 0x3));
160 0 : sc->sc_fanmul[7] = (1 << ((data >> 6) & 0x3));
161 :
162 0 : iic_release_bus(sc->sc_tag, 0);
163 :
164 : /* Initialize sensor data. */
165 0 : strlcpy(sc->sc_sensordev.xname, sc->sc_dev.dv_xname,
166 : sizeof(sc->sc_sensordev.xname));
167 :
168 0 : sc->sc_sensor[ADMCTS_TEMP].type = SENSOR_TEMP;
169 0 : strlcpy(sc->sc_sensor[ADMCTS_TEMP].desc, "Internal",
170 : sizeof(sc->sc_sensor[ADMCTS_TEMP].desc));
171 :
172 0 : sc->sc_sensor[ADMCTS_Vbat].type = SENSOR_VOLTS_DC;
173 0 : strlcpy(sc->sc_sensor[ADMCTS_Vbat].desc, "Vbat",
174 : sizeof(sc->sc_sensor[ADMCTS_Vbat].desc));
175 :
176 0 : sc->sc_sensor[ADMCTS_EXT1].type = SENSOR_TEMP;
177 0 : strlcpy(sc->sc_sensor[ADMCTS_EXT1].desc, "External",
178 : sizeof(sc->sc_sensor[ADMCTS_EXT1].desc));
179 :
180 0 : sc->sc_sensor[ADMCTS_EXT2].type = SENSOR_TEMP;
181 0 : strlcpy(sc->sc_sensor[ADMCTS_EXT2].desc, "External",
182 : sizeof(sc->sc_sensor[ADMCTS_EXT2].desc));
183 :
184 0 : sc->sc_sensor[ADMCTS_V3_3stby].type = SENSOR_VOLTS_DC;
185 0 : strlcpy(sc->sc_sensor[ADMCTS_V3_3stby].desc, "3.3 V standby",
186 : sizeof(sc->sc_sensor[ADMCTS_V3_3stby].desc));
187 :
188 0 : sc->sc_sensor[ADMCTS_V3_3main].type = SENSOR_VOLTS_DC;
189 0 : strlcpy(sc->sc_sensor[ADMCTS_V3_3main].desc, "3.3 V main",
190 : sizeof(sc->sc_sensor[ADMCTS_V3_3main].desc));
191 :
192 0 : sc->sc_sensor[ADMCTS_V5].type = SENSOR_VOLTS_DC;
193 0 : strlcpy(sc->sc_sensor[ADMCTS_V5].desc, "5 V",
194 : sizeof(sc->sc_sensor[ADMCTS_V5].desc));
195 :
196 0 : sc->sc_sensor[ADMCTS_Vccp].type = SENSOR_VOLTS_DC;
197 0 : strlcpy(sc->sc_sensor[ADMCTS_Vccp].desc, "Vccp",
198 : sizeof(sc->sc_sensor[ADMCTS_Vccp].desc));
199 :
200 0 : sc->sc_sensor[ADMCTS_V12].type = SENSOR_VOLTS_DC;
201 0 : strlcpy(sc->sc_sensor[ADMCTS_V12].desc, "12 V",
202 : sizeof(sc->sc_sensor[ADMCTS_V12].desc));
203 :
204 0 : sc->sc_sensor[ADMCTS_Vminus12].type = SENSOR_VOLTS_DC;
205 0 : strlcpy(sc->sc_sensor[ADMCTS_Vminus12].desc, "-12 V",
206 : sizeof(sc->sc_sensor[ADMCTS_Vminus12].desc));
207 :
208 0 : sc->sc_sensor[ADMCTS_FAN1].type = SENSOR_FANRPM;
209 0 : sc->sc_sensor[ADMCTS_FAN2].type = SENSOR_FANRPM;
210 0 : sc->sc_sensor[ADMCTS_FAN3].type = SENSOR_FANRPM;
211 0 : sc->sc_sensor[ADMCTS_FAN4].type = SENSOR_FANRPM;
212 0 : sc->sc_sensor[ADMCTS_FAN5].type = SENSOR_FANRPM;
213 0 : sc->sc_sensor[ADMCTS_FAN6].type = SENSOR_FANRPM;
214 0 : sc->sc_sensor[ADMCTS_FAN7].type = SENSOR_FANRPM;
215 :
216 0 : if (sensor_task_register(sc, admcts_refresh, 5) == NULL) {
217 0 : printf(", unable to register update task\n");
218 0 : return;
219 : }
220 :
221 0 : for (i = 0; i < ADMCTS_NUM_SENSORS; i++)
222 0 : sensor_attach(&sc->sc_sensordev, &sc->sc_sensor[i]);
223 0 : sensordev_install(&sc->sc_sensordev);
224 :
225 0 : printf("\n");
226 0 : }
227 :
228 : static void
229 0 : fanval(struct ksensor *sens, int mul, u_int8_t data)
230 : {
231 0 : int tmp = data * mul;
232 :
233 0 : if (tmp == 0)
234 0 : sens->flags |= SENSOR_FINVALID;
235 : else
236 0 : sens->value = 1630000 / tmp;
237 0 : }
238 :
239 : void
240 0 : admcts_refresh(void *arg)
241 : {
242 0 : struct admcts_softc *sc = arg;
243 0 : u_int8_t cmd, data;
244 0 : int8_t sdata;
245 :
246 0 : iic_acquire_bus(sc->sc_tag, 0);
247 :
248 0 : cmd = ADM1026_TEMP;
249 0 : if (iic_exec(sc->sc_tag, I2C_OP_READ_WITH_STOP,
250 0 : sc->sc_addr, &cmd, sizeof cmd, &sdata, sizeof sdata, 0) == 0)
251 0 : sc->sc_sensor[ADMCTS_TEMP].value = 273150000 + 1000000 * sdata;
252 :
253 0 : cmd = ADM1026_EXT1;
254 0 : if (iic_exec(sc->sc_tag, I2C_OP_READ_WITH_STOP,
255 0 : sc->sc_addr, &cmd, sizeof cmd, &sdata, sizeof sdata, 0) == 0)
256 0 : sc->sc_sensor[ADMCTS_EXT1].value = 273150000 + 1000000 * sdata;
257 :
258 0 : cmd = ADM1026_EXT2;
259 0 : if (iic_exec(sc->sc_tag, I2C_OP_READ_WITH_STOP,
260 0 : sc->sc_addr, &cmd, sizeof cmd, &sdata, sizeof sdata, 0) == 0)
261 0 : sc->sc_sensor[ADMCTS_EXT2].value = 273150000 + 1000000 * sdata;
262 :
263 0 : cmd = ADM1026_Vbat;
264 0 : if (iic_exec(sc->sc_tag, I2C_OP_READ_WITH_STOP,
265 0 : sc->sc_addr, &cmd, sizeof cmd, &data, sizeof data, 0) == 0)
266 0 : sc->sc_sensor[ADMCTS_Vbat].value = 3000000 * data / 192;
267 :
268 0 : cmd = ADM1026_V3_3stby;
269 0 : if (iic_exec(sc->sc_tag, I2C_OP_READ_WITH_STOP,
270 0 : sc->sc_addr, &cmd, sizeof cmd, &data, sizeof data, 0) == 0)
271 0 : sc->sc_sensor[ADMCTS_V3_3stby].value = 3300000 * data / 192;
272 :
273 0 : cmd = ADM1026_V3_3main;
274 0 : if (iic_exec(sc->sc_tag, I2C_OP_READ_WITH_STOP,
275 0 : sc->sc_addr, &cmd, sizeof cmd, &data, sizeof data, 0) == 0)
276 0 : sc->sc_sensor[ADMCTS_V3_3main].value = 3300000 * data / 192;
277 :
278 0 : cmd = ADM1026_V5;
279 0 : if (iic_exec(sc->sc_tag, I2C_OP_READ_WITH_STOP,
280 0 : sc->sc_addr, &cmd, sizeof cmd, &data, sizeof data, 0) == 0)
281 0 : sc->sc_sensor[ADMCTS_V5].value = 5500000 * data / 192;
282 :
283 0 : cmd = ADM1026_Vccp;
284 0 : if (iic_exec(sc->sc_tag, I2C_OP_READ_WITH_STOP,
285 0 : sc->sc_addr, &cmd, sizeof cmd, &data, sizeof data, 0) == 0)
286 0 : sc->sc_sensor[ADMCTS_Vccp].value = 2250000 * data / 192;
287 :
288 0 : cmd = ADM1026_V12;
289 0 : if (iic_exec(sc->sc_tag, I2C_OP_READ_WITH_STOP,
290 0 : sc->sc_addr, &cmd, sizeof cmd, &data, sizeof data, 0) == 0)
291 0 : sc->sc_sensor[ADMCTS_V12].value = 12000000 * data / 192;
292 :
293 0 : cmd = ADM1026_Vminus12;
294 0 : if (iic_exec(sc->sc_tag, I2C_OP_READ_WITH_STOP,
295 0 : sc->sc_addr, &cmd, sizeof cmd, &data, sizeof data, 0) == 0)
296 0 : sc->sc_sensor[ADMCTS_Vminus12].value = -2125000 * data / 192;
297 :
298 0 : cmd = ADM1026_FAN0;
299 0 : if (iic_exec(sc->sc_tag, I2C_OP_READ_WITH_STOP,
300 0 : sc->sc_addr, &cmd, sizeof cmd, &data, sizeof data, 0) == 0)
301 0 : fanval(&sc->sc_sensor[ADMCTS_FAN0], sc->sc_fanmul[0], data);
302 :
303 0 : cmd = ADM1026_FAN1;
304 0 : if (iic_exec(sc->sc_tag, I2C_OP_READ_WITH_STOP,
305 0 : sc->sc_addr, &cmd, sizeof cmd, &data, sizeof data, 0) == 0)
306 0 : fanval(&sc->sc_sensor[ADMCTS_FAN1], sc->sc_fanmul[1], data);
307 :
308 0 : cmd = ADM1026_FAN2;
309 0 : if (iic_exec(sc->sc_tag, I2C_OP_READ_WITH_STOP,
310 0 : sc->sc_addr, &cmd, sizeof cmd, &data, sizeof data, 0) == 0)
311 0 : fanval(&sc->sc_sensor[ADMCTS_FAN2], sc->sc_fanmul[2], data);
312 :
313 0 : cmd = ADM1026_FAN3;
314 0 : if (iic_exec(sc->sc_tag, I2C_OP_READ_WITH_STOP,
315 0 : sc->sc_addr, &cmd, sizeof cmd, &data, sizeof data, 0) == 0)
316 0 : fanval(&sc->sc_sensor[ADMCTS_FAN3], sc->sc_fanmul[3], data);
317 :
318 0 : cmd = ADM1026_FAN4;
319 0 : if (iic_exec(sc->sc_tag, I2C_OP_READ_WITH_STOP,
320 0 : sc->sc_addr, &cmd, sizeof cmd, &data, sizeof data, 0) == 0)
321 0 : fanval(&sc->sc_sensor[ADMCTS_FAN4], sc->sc_fanmul[4], data);
322 :
323 0 : cmd = ADM1026_FAN5;
324 0 : if (iic_exec(sc->sc_tag, I2C_OP_READ_WITH_STOP,
325 0 : sc->sc_addr, &cmd, sizeof cmd, &data, sizeof data, 0) == 0)
326 0 : fanval(&sc->sc_sensor[ADMCTS_FAN5], sc->sc_fanmul[5], data);
327 :
328 0 : cmd = ADM1026_FAN6;
329 0 : if (iic_exec(sc->sc_tag, I2C_OP_READ_WITH_STOP,
330 0 : sc->sc_addr, &cmd, sizeof cmd, &data, sizeof data, 0) == 0)
331 0 : fanval(&sc->sc_sensor[ADMCTS_FAN6], sc->sc_fanmul[6], data);
332 :
333 0 : cmd = ADM1026_FAN7;
334 0 : if (iic_exec(sc->sc_tag, I2C_OP_READ_WITH_STOP,
335 0 : sc->sc_addr, &cmd, sizeof cmd, &data, sizeof data, 0) == 0)
336 0 : fanval(&sc->sc_sensor[ADMCTS_FAN7], sc->sc_fanmul[7], data);
337 :
338 0 : iic_release_bus(sc->sc_tag, 0);
339 0 : }
|