]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - sys/dev/iicbus/lm75.c
xen: convert the Grant-table code to a NewBus device
[FreeBSD/FreeBSD.git] / sys / dev / iicbus / lm75.c
1 /*-
2  * Copyright (c) 2010 Andreas Tobler.
3  * Copyright (c) 2013-2014 Luiz Otavio O Souza <loos@freebsd.org>
4  * All rights reserved.
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 "opt_platform.h"
32
33 #include <sys/param.h>
34 #include <sys/bus.h>
35 #include <sys/endian.h>
36 #include <sys/kernel.h>
37 #include <sys/module.h>
38 #include <sys/sysctl.h>
39 #include <sys/systm.h>
40
41 #include <machine/bus.h>
42
43 #include <dev/iicbus/iicbus.h>
44 #include <dev/iicbus/iiconf.h>
45
46 #ifdef FDT
47 #include <dev/ofw/openfirm.h>
48 #include <dev/ofw/ofw_bus.h>
49 #include <dev/ofw/ofw_bus_subr.h>
50 #endif
51
52 /* LM75 registers. */
53 #define LM75_TEMP       0x0
54 #define LM75_CONF       0x1
55 #define LM75_CONF_FSHIFT        3
56 #define LM75_CONF_FAULT         0x18
57 #define LM75_CONF_POL           0x04
58 #define LM75_CONF_MODE          0x02
59 #define LM75_CONF_SHUTD         0x01
60 #define LM75_CONF_MASK          0x1f
61 #define LM75_THYST      0x2
62 #define LM75_TOS        0x3
63
64 /* LM75 constants. */
65 #define LM75_TEST_PATTERN       0xa
66 #define LM75_MIN_TEMP           -55
67 #define LM75_MAX_TEMP           125
68 #define LM75_0500C              0x80
69 #define LM75_0250C              0x40
70 #define LM75_0125C              0x20
71 #define LM75_MSB                0x8000
72 #define LM75_NEG_BIT            LM75_MSB
73 #define TZ_ZEROC                2732
74
75 /* LM75 supported models. */
76 #define HWTYPE_LM75             1
77 #define HWTYPE_LM75A            2
78
79 /* Regular bus attachment functions */
80 static int  lm75_probe(device_t);
81 static int  lm75_attach(device_t);
82
83 struct lm75_softc {
84         device_t                sc_dev;
85         struct intr_config_hook enum_hook;
86         int32_t                 sc_hwtype;
87         uint32_t                sc_addr;
88         uint32_t                sc_conf;
89 };
90
91 static int lm75_faults[4] = { 1, 2, 4, 6 };
92
93 /* Utility functions */
94 static int  lm75_conf_read(struct lm75_softc *);
95 static int  lm75_conf_write(struct lm75_softc *);
96 static int  lm75_temp_read(struct lm75_softc *, uint8_t, int *);
97 static int  lm75_temp_write(struct lm75_softc *, uint8_t, int);
98 static void lm75_start(void *);
99 static int  lm75_read(device_t, uint32_t, uint8_t, uint8_t *, size_t);
100 static int  lm75_write(device_t, uint32_t, uint8_t *, size_t);
101 static int  lm75_str_mode(char *);
102 static int  lm75_str_pol(char *);
103 static int  lm75_temp_sysctl(SYSCTL_HANDLER_ARGS);
104 static int  lm75_faults_sysctl(SYSCTL_HANDLER_ARGS);
105 static int  lm75_mode_sysctl(SYSCTL_HANDLER_ARGS);
106 static int  lm75_pol_sysctl(SYSCTL_HANDLER_ARGS);
107 static int  lm75_shutdown_sysctl(SYSCTL_HANDLER_ARGS);
108
109 static device_method_t  lm75_methods[] = {
110         /* Device interface */
111         DEVMETHOD(device_probe,         lm75_probe),
112         DEVMETHOD(device_attach,        lm75_attach),
113
114         DEVMETHOD_END
115 };
116
117 static driver_t lm75_driver = {
118         "lm75",
119         lm75_methods,
120         sizeof(struct lm75_softc)
121 };
122
123 static devclass_t lm75_devclass;
124
125 DRIVER_MODULE(lm75, iicbus, lm75_driver, lm75_devclass, 0, 0);
126
127 static int
128 lm75_read(device_t dev, uint32_t addr, uint8_t reg, uint8_t *data, size_t len)
129 {
130         struct iic_msg msg[2] = {
131             { addr, IIC_M_WR | IIC_M_NOSTOP, 1, &reg },
132             { addr, IIC_M_RD, len, data },
133         };
134
135         if (iicbus_transfer(dev, msg, 2) != 0)
136                 return (-1);
137
138         return (0);
139 }
140
141 static int
142 lm75_write(device_t dev, uint32_t addr, uint8_t *data, size_t len)
143 {
144         struct iic_msg msg[1] = {
145             { addr, IIC_M_WR, len, data },
146         };
147
148         if (iicbus_transfer(dev, msg, 1) != 0)
149                 return (-1);
150
151         return (0);
152 }
153
154 static int
155 lm75_probe(device_t dev)
156 {
157         struct lm75_softc *sc;
158
159         sc = device_get_softc(dev);
160         sc->sc_hwtype = HWTYPE_LM75;
161 #ifdef FDT
162         if (!ofw_bus_is_compatible(dev, "national,lm75"))
163                 return (ENXIO);
164 #endif
165         device_set_desc(dev, "LM75 temperature sensor");
166
167         return (BUS_PROBE_GENERIC);
168 }
169
170 static int
171 lm75_attach(device_t dev)
172 {
173         struct lm75_softc *sc;
174
175         sc = device_get_softc(dev);
176         sc->sc_dev = dev;
177         sc->sc_addr = iicbus_get_addr(dev);
178
179         sc->enum_hook.ich_func = lm75_start;
180         sc->enum_hook.ich_arg = dev;
181
182         /*
183          * We have to wait until interrupts are enabled.  Usually I2C read
184          * and write only works when the interrupts are available.
185          */
186         if (config_intrhook_establish(&sc->enum_hook) != 0)
187                 return (ENOMEM);
188
189         return (0);
190 }
191
192 static int
193 lm75_type_detect(struct lm75_softc *sc)
194 {
195         int i, lm75a;
196         uint8_t buf8;
197         uint32_t conf;
198
199         /* Save the contents of the configuration register. */
200         if (lm75_conf_read(sc) != 0)
201                 return (-1);
202         conf = sc->sc_conf;
203
204         /*
205          * Just write some pattern at configuration register so we can later
206          * verify.  The test pattern should be pretty harmless.
207          */
208         sc->sc_conf = LM75_TEST_PATTERN;
209         if (lm75_conf_write(sc) != 0)
210                 return (-1);
211
212         /*
213          * Read the configuration register again and check for our test
214          * pattern.
215          */
216         if (lm75_conf_read(sc) != 0)
217                 return (-1);
218         if (sc->sc_conf != LM75_TEST_PATTERN)
219                 return (-1);
220
221         /*
222          * Read from nonexistent registers (0x4 ~ 0x6).
223          * LM75A always return 0xff for nonexistent registers.
224          * LM75 will return the last read value - our test pattern written to
225          * configuration register.
226          */
227         lm75a = 0;
228         for (i = 4; i <= 6; i++) {
229                 if (lm75_read(sc->sc_dev, sc->sc_addr, i, &buf8, 1) < 0)
230                         return (-1);
231                 if (buf8 != LM75_TEST_PATTERN && buf8 != 0xff)
232                         return (-1);
233                 if (buf8 == 0xff)
234                         lm75a++;
235         }
236         if (lm75a == 3)
237                 sc->sc_hwtype = HWTYPE_LM75A;
238
239         /* Restore the configuration register. */
240         sc->sc_conf = conf;
241         if (lm75_conf_write(sc) != 0)
242                 return (-1);
243
244         return (0);
245 }
246
247 static void
248 lm75_start(void *xdev)
249 {
250         device_t dev;
251         struct lm75_softc *sc;
252         struct sysctl_ctx_list *ctx;
253         struct sysctl_oid *tree_node;
254         struct sysctl_oid_list *tree;
255
256         dev = (device_t)xdev;
257         sc = device_get_softc(dev);
258         ctx = device_get_sysctl_ctx(dev);
259         tree_node = device_get_sysctl_tree(dev);
260         tree = SYSCTL_CHILDREN(tree_node);
261
262         config_intrhook_disestablish(&sc->enum_hook);
263
264         /*
265          * Detect the kind of chip we are attaching to.
266          * This may not work for LM75 clones.
267          */
268         if (lm75_type_detect(sc) != 0) {
269                 device_printf(dev, "cannot read from sensor.\n");
270                 return;
271         }
272         if (sc->sc_hwtype == HWTYPE_LM75A)
273                 device_printf(dev,
274                     "LM75A type sensor detected (11bits resolution).\n");
275
276         /* Temperature. */
277         SYSCTL_ADD_PROC(ctx, tree, OID_AUTO, "temperature",
278             CTLTYPE_INT | CTLFLAG_RD | CTLFLAG_MPSAFE, dev, LM75_TEMP,
279             lm75_temp_sysctl, "IK", "Current temperature");
280         SYSCTL_ADD_PROC(ctx, tree, OID_AUTO, "thyst",
281             CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_MPSAFE, dev, LM75_THYST,
282             lm75_temp_sysctl, "IK", "Hysteresis temperature");
283         SYSCTL_ADD_PROC(ctx, tree, OID_AUTO, "tos",
284             CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_MPSAFE, dev, LM75_TOS,
285             lm75_temp_sysctl, "IK", "Overtemperature");
286
287         /* Configuration parameters. */
288         SYSCTL_ADD_PROC(ctx, tree, OID_AUTO, "faults",
289             CTLFLAG_RW | CTLTYPE_UINT, dev, 0,
290             lm75_faults_sysctl, "IU", "LM75 fault queue");
291         SYSCTL_ADD_PROC(ctx, tree, OID_AUTO, "mode",
292             CTLFLAG_RW | CTLTYPE_STRING, dev, 0,
293             lm75_mode_sysctl, "A", "LM75 mode");
294         SYSCTL_ADD_PROC(ctx, tree, OID_AUTO, "polarity",
295             CTLFLAG_RW | CTLTYPE_STRING, dev, 0,
296             lm75_pol_sysctl, "A", "LM75 OS polarity");
297         SYSCTL_ADD_PROC(ctx, tree, OID_AUTO, "shutdown",
298             CTLFLAG_RW | CTLTYPE_UINT, dev, 0,
299             lm75_shutdown_sysctl, "IU", "LM75 shutdown");
300 }
301
302 static int
303 lm75_conf_read(struct lm75_softc *sc)
304 {
305         uint8_t buf8;
306
307         if (lm75_read(sc->sc_dev, sc->sc_addr, LM75_CONF, &buf8, 1) < 0)
308                 return (-1);
309
310         sc->sc_conf = (uint32_t)buf8;
311
312         return (0);
313 }
314
315 static int
316 lm75_conf_write(struct lm75_softc *sc)
317 {
318         uint8_t buf8[2];
319
320         buf8[0] = LM75_CONF;
321         buf8[1] = (uint8_t)sc->sc_conf & LM75_CONF_MASK;
322
323         if (lm75_write(sc->sc_dev, sc->sc_addr, buf8, 2) < 0)
324                 return (-1);
325
326         return (0);
327 }
328
329 static int
330 lm75_temp_read(struct lm75_softc *sc, uint8_t reg, int *temp)
331 {
332         uint8_t buf8[2];
333         uint16_t buf;
334         int t;
335
336         if (lm75_read(sc->sc_dev, sc->sc_addr, reg, buf8, 2) < 0)
337                 return (-1);
338
339         buf = (buf8[0] << 8) | (buf8[1] & 0xff);
340
341         /*
342          * LM75 has a 9 bit ADC with resolution of 0.5 C per bit.
343          * LM75A has an 11 bit ADC with resolution of 0.125 C per bit.
344          * Temperature is stored with two's complement.
345          */
346         if (buf & LM75_NEG_BIT)
347                 buf = ~buf + 1;
348         *temp = ((int16_t)buf >> 8) * 10;
349         t = 0;
350         if (sc->sc_hwtype == HWTYPE_LM75A) {
351                 if (buf & LM75_0125C)
352                         t += 125;
353                 if (buf & LM75_0250C)
354                         t += 250;
355         }
356         if (buf & LM75_0500C)
357                 t += 500;
358         t /= 100;
359         *temp += t;
360         if (buf & LM75_NEG_BIT)
361                 *temp = -(*temp);
362         *temp += TZ_ZEROC;
363
364         return (0);
365 }
366
367 static int
368 lm75_temp_write(struct lm75_softc *sc, uint8_t reg, int temp)
369 {
370         uint8_t buf8[3];
371         uint16_t buf;
372
373         if (temp > LM75_MAX_TEMP)
374                 temp = LM75_MAX_TEMP;
375         if (temp < LM75_MIN_TEMP)
376                 temp = LM75_MIN_TEMP;
377
378         buf = (uint16_t)temp;
379         buf <<= 8;
380
381         buf8[0] = reg;
382         buf8[1] = buf >> 8;
383         buf8[2] = buf & 0xff;
384
385         if (lm75_write(sc->sc_dev, sc->sc_addr, buf8, 3) < 0)
386                 return (-1);
387
388         return (0);
389 }
390
391 static int
392 lm75_str_mode(char *buf)
393 {
394         int len, rtrn;
395
396         rtrn = -1;
397         len = strlen(buf);
398         if (len > 2 && strncasecmp("interrupt", buf, len) == 0)
399                 rtrn = 1;
400         else if (len > 2 && strncasecmp("comparator", buf, len) == 0)
401                 rtrn = 0;
402
403         return (rtrn);
404 }
405
406 static int
407 lm75_str_pol(char *buf)
408 {
409         int len, rtrn;
410
411         rtrn = -1;
412         len = strlen(buf);
413         if (len > 1 && strncasecmp("high", buf, len) == 0)
414                 rtrn = 1;
415         else if (len > 1 && strncasecmp("low", buf, len) == 0)
416                 rtrn = 0;
417         else if (len > 8 && strncasecmp("active-high", buf, len) == 0)
418                 rtrn = 1;
419         else if (len > 8 && strncasecmp("active-low", buf, len) == 0)
420                 rtrn = 0;
421
422         return (rtrn);
423 }
424
425 static int
426 lm75_temp_sysctl(SYSCTL_HANDLER_ARGS)
427 {
428         device_t dev;
429         int error, temp;
430         struct lm75_softc *sc;
431         uint8_t reg;
432
433         dev = (device_t)arg1;
434         reg = (uint8_t)arg2;
435         sc = device_get_softc(dev);
436
437         if (lm75_temp_read(sc, reg, &temp) != 0)
438                 return (EIO);
439
440         error = sysctl_handle_int(oidp, &temp, 0, req);
441         if (error != 0 || req->newptr == NULL)
442                 return (error);
443
444         if (lm75_temp_write(sc, reg, temp) != 0)
445                 return (EIO);
446
447         return (error);
448 }
449
450 static int
451 lm75_faults_sysctl(SYSCTL_HANDLER_ARGS)
452 {
453         device_t dev;
454         int error, faults, i, newf, tmp;
455         struct lm75_softc *sc;
456
457         dev = (device_t)arg1;
458         sc = device_get_softc(dev);
459         tmp = (sc->sc_conf & LM75_CONF_FAULT) >> LM75_CONF_FSHIFT;
460         if (tmp > nitems(lm75_faults))
461                 tmp = nitems(lm75_faults);
462         faults = lm75_faults[tmp];
463
464         error = sysctl_handle_int(oidp, &faults, 0, req);
465         if (error != 0 || req->newptr == NULL)
466                 return (error);
467
468         if (faults != lm75_faults[tmp]) {
469                 newf = 0;
470                 for (i = 0; i < nitems(lm75_faults); i++)
471                         if (faults >= lm75_faults[i])
472                                 newf = i;
473                 sc->sc_conf &= ~LM75_CONF_FAULT;
474                 sc->sc_conf |= newf << LM75_CONF_FSHIFT;
475                 if (lm75_conf_write(sc) != 0)
476                         return (EIO);
477         }
478
479         return (error);
480 }
481
482 static int
483 lm75_mode_sysctl(SYSCTL_HANDLER_ARGS)
484 {
485         char buf[16];
486         device_t dev;
487         int error, mode, newm;
488         struct lm75_softc *sc;
489
490         dev = (device_t)arg1;
491         sc = device_get_softc(dev);
492         if (sc->sc_conf & LM75_CONF_MODE) {
493                 mode = 1;
494                 strlcpy(buf, "interrupt", sizeof(buf));
495         } else {
496                 mode = 0;
497                 strlcpy(buf, "comparator", sizeof(buf));
498         }
499
500         error = sysctl_handle_string(oidp, buf, sizeof(buf), req);
501         if (error != 0 || req->newptr == NULL)
502                 return (error);
503
504         newm = lm75_str_mode(buf);
505         if (newm != -1 && mode != newm) {
506                 sc->sc_conf &= ~LM75_CONF_MODE;
507                 if (newm == 1)
508                         sc->sc_conf |= LM75_CONF_MODE;
509                 if (lm75_conf_write(sc) != 0)
510                         return (EIO);
511         }
512
513         return (error);
514 }
515
516 static int
517 lm75_pol_sysctl(SYSCTL_HANDLER_ARGS)
518 {
519         char buf[16];
520         device_t dev;
521         int error, newp, pol;
522         struct lm75_softc *sc;
523
524         dev = (device_t)arg1;
525         sc = device_get_softc(dev);
526         if (sc->sc_conf & LM75_CONF_POL) {
527                 pol = 1;
528                 strlcpy(buf, "active-high", sizeof(buf));
529         } else {
530                 pol = 0;
531                 strlcpy(buf, "active-low", sizeof(buf));
532         }
533
534         error = sysctl_handle_string(oidp, buf, sizeof(buf), req);
535         if (error != 0 || req->newptr == NULL)
536                 return (error);
537
538         newp = lm75_str_pol(buf);
539         if (newp != -1 && pol != newp) {
540                 sc->sc_conf &= ~LM75_CONF_POL;
541                 if (newp == 1)
542                         sc->sc_conf |= LM75_CONF_POL;
543                 if (lm75_conf_write(sc) != 0)
544                         return (EIO);
545         }
546
547         return (error);
548 }
549
550 static int
551 lm75_shutdown_sysctl(SYSCTL_HANDLER_ARGS)
552 {
553         device_t dev;
554         int error, shutdown, tmp;
555         struct lm75_softc *sc;
556
557         dev = (device_t)arg1;
558         sc = device_get_softc(dev);
559         tmp = shutdown = (sc->sc_conf & LM75_CONF_SHUTD) ? 1 : 0;
560
561         error = sysctl_handle_int(oidp, &shutdown, 0, req);
562         if (error != 0 || req->newptr == NULL)
563                 return (error);
564
565         if (shutdown != tmp) {
566                 sc->sc_conf &= ~LM75_CONF_SHUTD;
567                 if (shutdown)
568                         sc->sc_conf |= LM75_CONF_SHUTD;
569                 if (lm75_conf_write(sc) != 0)
570                         return (EIO);
571         }
572
573         return (error);
574 }