xref: /freebsd/sys/dev/iicbus/adc/ad7417.c (revision 2e620256bd76c449c835c604e404483437743011)
1 /*-
2  * SPDX-License-Identifier: BSD-2-Clause
3  *
4  * Copyright (c) 2010 Andreas Tobler
5  *
6  * Redistribution and use in source and binary forms, with or without
7  * modification, are permitted provided that the following conditions
8  * are met:
9  * 1. Redistributions of source code must retain the above copyright
10  *    notice, this list of conditions and the following disclaimer.
11  * 2. Redistributions in binary form must reproduce the above copyright
12  *    notice, this list of conditions and the following disclaimer in the
13  *    documentation and/or other materials provided with the distribution.
14  *
15  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
16  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
17  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
18  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
19  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
20  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
21  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
22  * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
23  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25  * SUCH DAMAGE.
26  */
27 
28 #include <sys/cdefs.h>
29 #include <sys/param.h>
30 #include <sys/bus.h>
31 #include <sys/systm.h>
32 #include <sys/module.h>
33 #include <sys/callout.h>
34 #include <sys/conf.h>
35 #include <sys/cpu.h>
36 #include <sys/ctype.h>
37 #include <sys/kernel.h>
38 #include <sys/reboot.h>
39 #include <sys/rman.h>
40 #include <sys/sysctl.h>
41 #include <sys/limits.h>
42 
43 #include <machine/bus.h>
44 #include <machine/md_var.h>
45 
46 #include <dev/iicbus/iicbus.h>
47 #include <dev/iicbus/iiconf.h>
48 
49 #include <dev/ofw/openfirm.h>
50 #include <dev/ofw/ofw_bus.h>
51 #include <powerpc/powermac/powermac_thermal.h>
52 
53 /* CPU A/B sensors, temp and adc: AD7417. */
54 
55 #define AD7417_TEMP         0x00
56 #define AD7417_CONFIG       0x01
57 #define AD7417_ADC          0x04
58 #define AD7417_CONFIG2      0x05
59 #define AD7417_CONFMASK     0xe0
60 
61 uint8_t adc741x_config;
62 
63 struct ad7417_sensor {
64 	struct	pmac_therm therm;
65 	device_t dev;
66 	int     id;
67 	enum {
68 		ADC7417_TEMP_SENSOR,
69 		ADC7417_ADC_SENSOR
70 	} type;
71 };
72 
73 struct write_data {
74 	uint8_t reg;
75 	uint8_t val;
76 };
77 
78 struct read_data {
79 	uint8_t reg;
80 	uint16_t val;
81 };
82 
83 /* Regular bus attachment functions */
84 static int ad7417_probe(device_t);
85 static int ad7417_attach(device_t);
86 
87 /* Utility functions */
88 static int ad7417_sensor_sysctl(SYSCTL_HANDLER_ARGS);
89 static int ad7417_write(device_t dev, uint32_t addr, uint8_t reg,
90 			uint8_t *buf, int len);
91 static int ad7417_read_1(device_t dev, uint32_t addr, uint8_t reg,
92 			 uint8_t *data);
93 static int ad7417_read_2(device_t dev, uint32_t addr, uint8_t reg,
94 			 uint16_t *data);
95 static int ad7417_write_read(device_t dev, uint32_t addr,
96 			     struct write_data out, struct read_data *in);
97 static int ad7417_diode_read(struct ad7417_sensor *sens);
98 static int ad7417_adc_read(struct ad7417_sensor *sens);
99 static int ad7417_sensor_read(struct ad7417_sensor *sens);
100 
101 struct ad7417_softc {
102 	device_t		sc_dev;
103 	uint32_t                sc_addr;
104 	struct ad7417_sensor    *sc_sensors;
105 	int                     sc_nsensors;
106 	int                     init_done;
107 };
108 static device_method_t  ad7417_methods[] = {
109 	/* Device interface */
110 	DEVMETHOD(device_probe,		ad7417_probe),
111 	DEVMETHOD(device_attach,	ad7417_attach),
112 	{ 0, 0 },
113 };
114 
115 static driver_t ad7417_driver = {
116 	"ad7417",
117 	ad7417_methods,
118 	sizeof(struct ad7417_softc)
119 };
120 
121 DRIVER_MODULE(ad7417, iicbus, ad7417_driver, 0, 0);
122 static MALLOC_DEFINE(M_AD7417, "ad7417", "Supply-Monitor AD7417");
123 
124 
125 static int
126 ad7417_write(device_t dev, uint32_t addr, uint8_t reg, uint8_t *buff, int len)
127 {
128 	unsigned char buf[4];
129 	int try = 0;
130 
131 	struct iic_msg msg[] = {
132 		{ addr, IIC_M_WR, 0, buf }
133 	};
134 
135 	msg[0].len = len + 1;
136 	buf[0] = reg;
137 	memcpy(buf + 1, buff, len);
138 
139 	for (;;)
140 	{
141 		if (iicbus_transfer(dev, msg, nitems(msg)) == 0)
142 			return (0);
143 
144 		if (++try > 5) {
145 			device_printf(dev, "iicbus write failed\n");
146 			return (-1);
147 		}
148 		pause("ad7417_write", hz);
149 	}
150 }
151 
152 static int
153 ad7417_read_1(device_t dev, uint32_t addr, uint8_t reg, uint8_t *data)
154 {
155 	uint8_t buf[4];
156 	int err, try = 0;
157 
158 	struct iic_msg msg[2] = {
159 	    { addr, IIC_M_WR | IIC_M_NOSTOP, 1, &reg },
160 	    { addr, IIC_M_RD, 1, buf },
161 	};
162 
163 	for (;;)
164 	{
165 		err = iicbus_transfer(dev, msg, nitems(msg));
166 		if (err != 0)
167 			goto retry;
168 
169 		*data = *((uint8_t*)buf);
170 		return (0);
171 	retry:
172 		if (++try > 5) {
173 			device_printf(dev, "iicbus read failed\n");
174 			return (-1);
175 		}
176 		pause("ad7417_read_1", hz);
177 	}
178 }
179 
180 static int
181 ad7417_read_2(device_t dev, uint32_t addr, uint8_t reg, uint16_t *data)
182 {
183 	uint8_t buf[4];
184 	int err, try = 0;
185 
186 	struct iic_msg msg[2] = {
187 	    { addr, IIC_M_WR | IIC_M_NOSTOP, 1, &reg },
188 	    { addr, IIC_M_RD, 2, buf },
189 	};
190 
191 	for (;;)
192 	{
193 		err = iicbus_transfer(dev, msg, nitems(msg));
194 		if (err != 0)
195 			goto retry;
196 
197 		*data = *((uint16_t*)buf);
198 		return (0);
199 	retry:
200 		if (++try > 5) {
201 			device_printf(dev, "iicbus read failed\n");
202 			return (-1);
203 		}
204 		pause("ad7417_read_2", hz);
205 	}
206 }
207 
208 static int
209 ad7417_write_read(device_t dev, uint32_t addr, struct write_data out,
210 		  struct read_data *in)
211 {
212 	uint8_t buf[4];
213 	int err, try = 0;
214 
215 	/* Do a combined write/read. */
216 	struct iic_msg msg[3] = {
217 	    { addr, IIC_M_WR, 2, buf },
218 	    { addr, IIC_M_WR | IIC_M_NOSTOP, 1, &in->reg },
219 	    { addr, IIC_M_RD, 2, buf },
220 	};
221 
222 	/* Prepare the write msg. */
223 	buf[0] = out.reg;
224 	buf[1] = out.val & 0xff;
225 
226 	for (;;)
227 	{
228 		err = iicbus_transfer(dev, msg, nitems(msg));
229 		if (err != 0)
230 			goto retry;
231 
232 		in->val = *((uint16_t*)buf);
233 		return (0);
234 	retry:
235 		if (++try > 5) {
236 			device_printf(dev, "iicbus write/read failed\n");
237 			return (-1);
238 		}
239 		pause("ad7417_write_read", hz);
240 	}
241 }
242 
243 static int
244 ad7417_init_adc(device_t dev, uint32_t addr)
245 {
246 	uint8_t buf;
247 	int err;
248 	struct ad7417_softc *sc;
249 
250 	sc = device_get_softc(dev);
251 
252 	adc741x_config = 0;
253 	/* Clear Config2 */
254 	buf = 0;
255 
256 	err = ad7417_write(dev, addr, AD7417_CONFIG2, &buf, sizeof(buf));
257 
258 	 /* Read & cache Config1 */
259 	buf = 0;
260 	err = ad7417_write(dev, addr, AD7417_CONFIG, &buf, sizeof(buf));
261 	err = ad7417_read_1(dev, addr, AD7417_CONFIG, &buf);
262 	adc741x_config = (uint8_t)buf;
263 
264 	/* Disable shutdown mode */
265 	adc741x_config &= 0xfe;
266 	buf = adc741x_config;
267 	err = ad7417_write(dev, addr, AD7417_CONFIG, &buf, sizeof(buf));
268 	if (err < 0)
269 		return (-1);
270 
271 	sc->init_done = 1;
272 
273 	return (0);
274 
275 }
276 static int
277 ad7417_probe(device_t dev)
278 {
279 	const char  *name, *compatible;
280 	struct ad7417_softc *sc;
281 
282 	name = ofw_bus_get_name(dev);
283 	compatible = ofw_bus_get_compat(dev);
284 
285 	if (!name)
286 		return (ENXIO);
287 
288 	if (strcmp(name, "supply-monitor") != 0 ||
289 	    strcmp(compatible, "ad7417") != 0)
290 		return (ENXIO);
291 
292 	sc = device_get_softc(dev);
293 	sc->sc_dev = dev;
294 	sc->sc_addr = iicbus_get_addr(dev);
295 
296 	device_set_desc(dev, "Supply-Monitor AD7417");
297 
298 	return (0);
299 }
300 
301 /*
302  * This function returns the number of sensors. If we call it the second time
303  * and we have allocated memory for sc->sc_sensors, we fill in the properties.
304  */
305 static int
306 ad7417_fill_sensor_prop(device_t dev)
307 {
308 	phandle_t child, node;
309 	struct ad7417_softc *sc;
310 	u_int id[10];
311 	char location[96];
312 	char type[32];
313 	int i = 0, j, len = 0, prop_len, prev_len = 0;
314 
315 	sc = device_get_softc(dev);
316 
317 	child = ofw_bus_get_node(dev);
318 
319 	/* Fill the sensor location property. */
320 	prop_len = OF_getprop(child, "hwsensor-location", location,
321 			      sizeof(location));
322 	while (len < prop_len) {
323 		if (sc->sc_sensors != NULL)
324 			strcpy(sc->sc_sensors[i].therm.name, location + len);
325 		prev_len = strlen(location + len) + 1;
326 		len += prev_len;
327 		i++;
328 	}
329 	if (sc->sc_sensors == NULL)
330 		return (i);
331 
332 	/* Fill the sensor type property. */
333 	len = 0;
334 	i = 0;
335 	prev_len = 0;
336 	prop_len = OF_getprop(child, "hwsensor-type", type, sizeof(type));
337 	while (len < prop_len) {
338 		if (strcmp(type + len, "temperature") == 0)
339 			sc->sc_sensors[i].type = ADC7417_TEMP_SENSOR;
340 		else
341 			sc->sc_sensors[i].type = ADC7417_ADC_SENSOR;
342 		prev_len = strlen(type + len) + 1;
343 		len += prev_len;
344 		i++;
345 	}
346 
347 	/* Fill the sensor id property. Taken from OF. */
348 	prop_len = OF_getprop(child, "hwsensor-id", id, sizeof(id));
349 	for (j = 0; j < i; j++)
350 		sc->sc_sensors[j].id = id[j];
351 
352 	/* Fill the sensor zone property. Taken from OF. */
353 	prop_len = OF_getprop(child, "hwsensor-zone", id, sizeof(id));
354 	for (j = 0; j < i; j++)
355 		sc->sc_sensors[j].therm.zone = id[j];
356 
357 	/* Some PowerMac's have the real location of the sensors on
358 	   child nodes of the hwsensor-location node. Check for and
359 	   fix the name if needed.
360 	   This is needed to apply the below HACK with the diode.
361 	*/
362 	j = 0;
363 	for (node = OF_child(child); node != 0; node = OF_peer(node)) {
364 
365 	    OF_getprop(node, "location", location, sizeof(location));
366 	    strcpy(sc->sc_sensors[i].therm.name, location);
367 	    j++;
368 	}
369 
370 	/* Finish setting up sensor properties */
371 	for (j = 0; j < i; j++) {
372 		sc->sc_sensors[j].dev = dev;
373 
374 		/* HACK: Apple wired a random diode to the ADC line */
375 		if ((strstr(sc->sc_sensors[j].therm.name, "DIODE TEMP")
376 		    != NULL)
377 		    || (strstr(sc->sc_sensors[j].therm.name, "AD1") != NULL)) {
378 			sc->sc_sensors[j].type = ADC7417_TEMP_SENSOR;
379 			sc->sc_sensors[j].therm.read =
380 			    (int (*)(struct pmac_therm *))(ad7417_diode_read);
381 		} else {
382 			sc->sc_sensors[j].therm.read =
383 			    (int (*)(struct pmac_therm *))(ad7417_sensor_read);
384 		}
385 
386 		if (sc->sc_sensors[j].type != ADC7417_TEMP_SENSOR)
387 			continue;
388 
389 		/* Make up some ranges */
390 		sc->sc_sensors[j].therm.target_temp = 500 + ZERO_C_TO_K;
391 		sc->sc_sensors[j].therm.max_temp = 900 + ZERO_C_TO_K;
392 
393 		pmac_thermal_sensor_register(&sc->sc_sensors[j].therm);
394 	}
395 
396 	return (i);
397 }
398 
399 static int
400 ad7417_attach(device_t dev)
401 {
402 	struct ad7417_softc *sc;
403 	struct sysctl_oid *oid, *sensroot_oid;
404 	struct sysctl_ctx_list *ctx;
405 	char sysctl_name[32];
406 	int i, j;
407 	const char *unit;
408 
409 	sc = device_get_softc(dev);
410 
411 	sc->sc_nsensors = 0;
412 
413 	/* Count the actual number of sensors. */
414 	sc->sc_nsensors = ad7417_fill_sensor_prop(dev);
415 
416 	device_printf(dev, "%d sensors detected.\n", sc->sc_nsensors);
417 
418 	if (sc->sc_nsensors == 0)
419 		device_printf(dev, "WARNING: No AD7417 sensors detected!\n");
420 
421 	sc->sc_sensors = malloc (sc->sc_nsensors * sizeof(struct ad7417_sensor),
422 				 M_AD7417, M_WAITOK | M_ZERO);
423 
424 	ctx = device_get_sysctl_ctx(dev);
425 	sensroot_oid = SYSCTL_ADD_NODE(ctx,
426 	    SYSCTL_CHILDREN(device_get_sysctl_tree(dev)), OID_AUTO, "sensor",
427 	    CTLFLAG_RD | CTLFLAG_MPSAFE, 0, "AD7417 Sensor Information");
428 
429 	/* Now we can fill the properties into the allocated struct. */
430 	sc->sc_nsensors = ad7417_fill_sensor_prop(dev);
431 
432 	/* Add sysctls for the sensors. */
433 	for (i = 0; i < sc->sc_nsensors; i++) {
434 		for (j = 0; j < strlen(sc->sc_sensors[i].therm.name); j++) {
435 			sysctl_name[j] =
436 			    tolower(sc->sc_sensors[i].therm.name[j]);
437 			if (isspace(sysctl_name[j]))
438 				sysctl_name[j] = '_';
439 		}
440 		sysctl_name[j] = 0;
441 
442 		oid = SYSCTL_ADD_NODE(ctx, SYSCTL_CHILDREN(sensroot_oid),
443 		    OID_AUTO, sysctl_name, CTLFLAG_RD | CTLFLAG_MPSAFE, 0,
444 		    "Sensor Information");
445 
446 		if (sc->sc_sensors[i].type == ADC7417_TEMP_SENSOR) {
447 			unit = "temp";
448 		} else {
449 			unit = "volt";
450 		}
451 		/* I use i to pass the sensor id. */
452 		SYSCTL_ADD_PROC(ctx, SYSCTL_CHILDREN(oid), OID_AUTO,
453 				unit, CTLTYPE_INT | CTLFLAG_RD | CTLFLAG_MPSAFE,
454 				dev, i, ad7417_sensor_sysctl,
455 				sc->sc_sensors[i].type == ADC7417_TEMP_SENSOR ?
456 				"IK" : "I",
457 				sc->sc_sensors[i].type == ADC7417_TEMP_SENSOR ?
458 				"sensor unit (C)" : "sensor unit (mV)");
459 	}
460 	/* Dump sensor location, ID & type. */
461 	if (bootverbose) {
462 		device_printf(dev, "Sensors\n");
463 		for (i = 0; i < sc->sc_nsensors; i++) {
464 			device_printf(dev, "Location: %s ID: %d type: %d\n",
465 				      sc->sc_sensors[i].therm.name,
466 				      sc->sc_sensors[i].id,
467 				      sc->sc_sensors[i].type);
468 		}
469 	}
470 
471 	return (0);
472 }
473 
474 static int
475 ad7417_get_temp(device_t dev, uint32_t addr, int *temp)
476 {
477 	uint16_t buf[2];
478 	uint16_t read;
479 	int err;
480 
481 	err = ad7417_read_2(dev, addr, AD7417_TEMP, buf);
482 
483 	if (err < 0)
484 		return (-1);
485 
486 	read = *((int16_t*)buf);
487 
488 	/* The ADC is 10 bit, the resolution is 0.25 C.
489 	   The temperature is in tenth kelvin.
490 	*/
491 	*temp = (((int16_t)(read & 0xffc0)) >> 6) * 25 / 10;
492 	return (0);
493 }
494 
495 static int
496 ad7417_get_adc(device_t dev, uint32_t addr, unsigned int *value,
497 	       uint8_t chan)
498 {
499 	uint8_t tmp;
500 	int err;
501 	struct write_data config;
502 	struct read_data data;
503 
504 	tmp = chan << 5;
505 	config.reg = AD7417_CONFIG;
506 	data.reg = AD7417_ADC;
507 	data.val = 0;
508 
509 	err = ad7417_read_1(dev, addr, AD7417_CONFIG, &config.val);
510 
511 	config.val = (config.val & ~AD7417_CONFMASK) | (tmp & AD7417_CONFMASK);
512 
513 	err = ad7417_write_read(dev, addr, config, &data);
514 	if (err < 0)
515 		return (-1);
516 
517 	*value = ((uint32_t)data.val) >> 6;
518 
519 	return (0);
520 }
521 
522 static int
523 ad7417_diode_read(struct ad7417_sensor *sens)
524 {
525 	static int eeprom_read = 0;
526 	static cell_t eeprom[2][40];
527 	phandle_t eeprom_node;
528 	int rawval, diode_slope, diode_offset;
529 	int temp;
530 
531 	if (!eeprom_read) {
532 		eeprom_node = OF_finddevice("/u3/i2c/cpuid@a0");
533 		OF_getprop(eeprom_node, "cpuid", eeprom[0], sizeof(eeprom[0]));
534 		eeprom_node = OF_finddevice("/u3/i2c/cpuid@a2");
535 		OF_getprop(eeprom_node, "cpuid", eeprom[1], sizeof(eeprom[1]));
536 		eeprom_read = 1;
537 	}
538 
539 	rawval = ad7417_adc_read(sens);
540 	if (rawval < 0)
541 		return (-1);
542 
543 	if (strstr(sens->therm.name, "CPU B") != NULL) {
544 		diode_slope = eeprom[1][0x11] >> 16;
545 		diode_offset = (int16_t)(eeprom[1][0x11] & 0xffff) << 12;
546 	} else {
547 		diode_slope = eeprom[0][0x11] >> 16;
548 		diode_offset = (int16_t)(eeprom[0][0x11] & 0xffff) << 12;
549 	}
550 
551 	temp = (rawval*diode_slope + diode_offset) >> 2;
552 	temp = (10*(temp >> 16)) + ((10*(temp & 0xffff)) >> 16);
553 
554 	return (temp + ZERO_C_TO_K);
555 }
556 
557 static int
558 ad7417_adc_read(struct ad7417_sensor *sens)
559 {
560 	struct ad7417_softc *sc;
561 	uint8_t chan;
562 	int temp;
563 
564 	sc = device_get_softc(sens->dev);
565 
566 	switch (sens->id) {
567 	case 11:
568 	case 16:
569 		chan = 1;
570 		break;
571 	case 12:
572 	case 17:
573 		chan = 2;
574 		break;
575 	case 13:
576 	case 18:
577 		chan = 3;
578 		break;
579 	case 14:
580 	case 19:
581 		chan = 4;
582 		break;
583 	default:
584 		chan = 1;
585 	}
586 
587 	if (ad7417_get_adc(sc->sc_dev, sc->sc_addr, &temp, chan) < 0)
588 		return (-1);
589 
590 	return (temp);
591 }
592 
593 
594 static int
595 ad7417_sensor_read(struct ad7417_sensor *sens)
596 {
597 	struct ad7417_softc *sc;
598 	int temp;
599 
600 	sc = device_get_softc(sens->dev);
601 
602 	/* Init the ADC if not already done.*/
603 	if (!sc->init_done)
604 		if (ad7417_init_adc(sc->sc_dev, sc->sc_addr) < 0)
605 			return (-1);
606 
607 	if (sens->type == ADC7417_TEMP_SENSOR) {
608 		if (ad7417_get_temp(sc->sc_dev, sc->sc_addr, &temp) < 0)
609 			return (-1);
610 		temp += ZERO_C_TO_K;
611 	} else {
612 		temp = ad7417_adc_read(sens);
613 	}
614 	return (temp);
615 }
616 
617 static int
618 ad7417_sensor_sysctl(SYSCTL_HANDLER_ARGS)
619 {
620 	device_t dev;
621 	struct ad7417_softc *sc;
622 	struct ad7417_sensor *sens;
623 	int value = 0;
624 	int error;
625 
626 	dev = arg1;
627 	sc = device_get_softc(dev);
628 	sens = &sc->sc_sensors[arg2];
629 
630 	value = sens->therm.read(&sens->therm);
631 	if (value < 0)
632 		return (ENXIO);
633 
634 	error = sysctl_handle_int(oidp, &value, 0, req);
635 
636 	return (error);
637 }
638