1 /* $OpenBSD: asb100.c,v 1.12 2022/04/06 18:59:28 naddy 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 const 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
asbtm_match(struct device * parent,void * match,void * aux)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
asbtm_banksel(struct asbtm_softc * sc,u_int8_t new_bank,u_int8_t * orig_bank)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
asbtm_attach(struct device * parent,struct device * self,void * aux)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
fanval(struct ksensor * sens,int mul,u_int8_t data)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
asbtm_refresh(void * arg)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 * (betoh16(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 * (betoh16(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 }
403