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