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