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