]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - sys/dev/iicbus/ad7417.c
Add IRQ resource to SPIBUS
[FreeBSD/FreeBSD.git] / sys / dev / iicbus / ad7417.c
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
63 uint8_t adc741x_config;
64
65 struct ad7417_sensor {
66         struct  pmac_therm therm;
67         device_t dev;
68         int     id;
69         enum {
70                 ADC7417_TEMP_SENSOR,
71                 ADC7417_ADC_SENSOR
72         } type;
73 };
74
75 struct write_data {
76         uint8_t reg;
77         uint8_t val;
78 };
79
80 struct read_data {
81         uint8_t reg;
82         uint16_t val;
83 };
84
85 /* Regular bus attachment functions */
86 static int ad7417_probe(device_t);
87 static int ad7417_attach(device_t);
88
89 /* Utility functions */
90 static int ad7417_sensor_sysctl(SYSCTL_HANDLER_ARGS);
91 static int ad7417_write(device_t dev, uint32_t addr, uint8_t reg,
92                         uint8_t *buf, int len);
93 static int ad7417_read_1(device_t dev, uint32_t addr, uint8_t reg,
94                          uint8_t *data);
95 static int ad7417_read_2(device_t dev, uint32_t addr, uint8_t reg,
96                          uint16_t *data);
97 static int ad7417_write_read(device_t dev, uint32_t addr,
98                              struct write_data out, struct read_data *in);
99 static int ad7417_diode_read(struct ad7417_sensor *sens);
100 static int ad7417_adc_read(struct ad7417_sensor *sens);
101 static int ad7417_sensor_read(struct ad7417_sensor *sens);
102
103 struct ad7417_softc {
104         device_t                sc_dev;
105         uint32_t                sc_addr;
106         struct ad7417_sensor    *sc_sensors;
107         int                     sc_nsensors;
108         int                     init_done;
109 };
110 static 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
117 static driver_t ad7417_driver = {
118         "ad7417",
119         ad7417_methods,
120         sizeof(struct ad7417_softc)
121 };
122
123 static devclass_t ad7417_devclass;
124
125 DRIVER_MODULE(ad7417, iicbus, ad7417_driver, ad7417_devclass, 0, 0);
126 static MALLOC_DEFINE(M_AD7417, "ad7417", "Supply-Monitor AD7417");
127
128
129 static int
130 ad7417_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
156 static int
157 ad7417_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
184 static int
185 ad7417_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
212 static int
213 ad7417_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
247 static int
248 ad7417_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));
265         err = ad7417_read_1(dev, addr, AD7417_CONFIG, &buf);
266         adc741x_config = (uint8_t)buf;
267
268         /* Disable shutdown mode */
269         adc741x_config &= 0xfe;
270         buf = adc741x_config;
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 }
280 static int
281 ad7417_probe(device_t dev)
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  */
309 static int
310 ad7417_fill_sensor_prop(device_t dev)
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
403 static int
404 ad7417_attach(device_t dev)
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. */
419         sc->sc_nsensors = ad7417_fill_sensor_prop(dev);
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. */
435         sc->sc_nsensors = ad7417_fill_sensor_prop(dev);
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,
461                                 dev, i, ad7417_sensor_sysctl,
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
479 static int
480 ad7417_get_temp(device_t dev, uint32_t addr, int *temp)
481 {
482         uint16_t buf[2];
483         uint16_t read;
484         int err;
485
486         err = ad7417_read_2(dev, addr, AD7417_TEMP, buf);
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
500 static int
501 ad7417_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
527 static int
528 ad7417_diode_read(struct ad7417_sensor *sens)
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
562 static int
563 ad7417_adc_read(struct ad7417_sensor *sens)
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
599 static int
600 ad7417_sensor_read(struct ad7417_sensor *sens)
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
622 static int
623 ad7417_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 }