xref: /openbsd/sys/dev/i2c/asb100.c (revision 471aeecf)
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