FreeBSD/Linux Kernel Cross Reference
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 TZ_ZEROC 27315
69 #define TZ_ZEROC_DIVIDER 100
70
71 enum max_resolution{
72 BITS_9 = 1,
73 BITS_11
74 };
75
76 /* Regular bus attachment functions */
77 static int lm75_probe(device_t);
78 static int lm75_attach(device_t);
79
80 struct lm75_softc {
81 device_t sc_dev;
82 struct intr_config_hook enum_hook;
83 uint32_t sc_addr;
84 uint32_t sc_conf;
85 uint8_t sc_resolution;
86 uint8_t sc_max_resolution;
87 uint16_t sc_multiplier;
88 };
89
90 /* Utility functions */
91 static int lm75_conf_read(struct lm75_softc *);
92 static int lm75_conf_write(struct lm75_softc *);
93 static int lm75_temp_read(struct lm75_softc *, uint8_t, int *);
94 static int lm75_temp_write(struct lm75_softc *, uint8_t, int);
95 static void lm75_start(void *);
96 static int lm75_read(device_t, uint32_t, uint8_t, uint8_t *, size_t);
97 static int lm75_write(device_t, uint32_t, uint8_t *, size_t);
98 static int lm75_str_mode(char *);
99 static int lm75_str_pol(char *);
100 static int lm75_temp_sysctl(SYSCTL_HANDLER_ARGS);
101 static int lm75_faults_sysctl(SYSCTL_HANDLER_ARGS);
102 static int lm75_mode_sysctl(SYSCTL_HANDLER_ARGS);
103 static int lm75_pol_sysctl(SYSCTL_HANDLER_ARGS);
104 static int lm75_shutdown_sysctl(SYSCTL_HANDLER_ARGS);
105 static int lm75_resolution_sysctl(SYSCTL_HANDLER_ARGS);
106
107 static device_method_t lm75_methods[] = {
108 /* Device interface */
109 DEVMETHOD(device_probe, lm75_probe),
110 DEVMETHOD(device_attach, lm75_attach),
111
112 DEVMETHOD_END
113 };
114
115 static driver_t lm75_driver = {
116 "lm75",
117 lm75_methods,
118 sizeof(struct lm75_softc)
119 };
120
121 #ifdef FDT
122 static struct ofw_compat_data compat_data[] = {
123 {"national,lm75", BITS_9},
124 {"ti,lm75", BITS_9},
125 {0,0}
126 };
127 #endif
128
129 DRIVER_MODULE(lm75, iicbus, lm75_driver, 0, 0);
130
131 static int
132 lm75_read(device_t dev, uint32_t addr, uint8_t reg, uint8_t *data, size_t len)
133 {
134 struct iic_msg msg[2] = {
135 { addr, IIC_M_WR | IIC_M_NOSTOP, 1, ® },
136 { addr, IIC_M_RD, len, data },
137 };
138
139 if (iicbus_transfer(dev, msg, nitems(msg)) != 0)
140 return (-1);
141
142 return (0);
143 }
144
145 static int
146 lm75_write(device_t dev, uint32_t addr, uint8_t *data, size_t len)
147 {
148 struct iic_msg msg[1] = {
149 { addr, IIC_M_WR, len, data },
150 };
151
152 if (iicbus_transfer(dev, msg, nitems(msg)) != 0)
153 return (-1);
154
155 return (0);
156 }
157
158 static int
159 lm75_probe(device_t dev)
160 {
161 #ifdef FDT
162 const struct ofw_compat_data *compat_ptr;
163 #endif
164 struct lm75_softc *sc;
165
166 sc = device_get_softc(dev);
167 sc->sc_max_resolution = 9;
168
169 #ifdef FDT
170 if (!ofw_bus_status_okay(dev))
171 return (ENXIO);
172
173 compat_ptr = ofw_bus_search_compatible(dev, compat_data);
174
175 switch (compat_ptr->ocd_data){
176 case BITS_9:
177 sc->sc_max_resolution = 9;
178 break;
179 case BITS_11:
180 sc->sc_max_resolution = 11;
181 break;
182 default:
183 return (ENXIO);
184 }
185 #endif
186 device_set_desc(dev, "LM75 temperature sensor");
187
188 return (BUS_PROBE_GENERIC);
189 }
190
191 static int
192 lm75_attach(device_t dev)
193 {
194 struct lm75_softc *sc;
195
196 sc = device_get_softc(dev);
197 sc->sc_dev = dev;
198 sc->sc_addr = iicbus_get_addr(dev);
199
200 sc->enum_hook.ich_func = lm75_start;
201 sc->enum_hook.ich_arg = dev;
202
203 switch (sc->sc_max_resolution) {
204 case 9:
205 sc->sc_resolution = 9;
206 sc->sc_max_resolution = 9;
207 sc->sc_multiplier = 10;
208 break;
209 case 11:
210 sc->sc_resolution = 11;
211 sc->sc_max_resolution = 11;
212 sc->sc_multiplier = 1000;
213 break;
214 default:
215 return (ENXIO);
216 }
217
218 /*
219 * We have to wait until interrupts are enabled. Usually I2C read
220 * and write only works when the interrupts are available.
221 */
222 if (config_intrhook_establish(&sc->enum_hook) != 0)
223 return (ENOMEM);
224
225 return (0);
226 }
227
228 static int
229 lm75_type_detect(struct lm75_softc *sc)
230 {
231 int i, lm75a;
232 uint8_t buf8;
233 uint32_t conf;
234
235 /* Save the contents of the configuration register. */
236 if (lm75_conf_read(sc) != 0)
237 return (-1);
238 conf = sc->sc_conf;
239
240 /*
241 * Just write some pattern at configuration register so we can later
242 * verify. The test pattern should be pretty harmless.
243 */
244 sc->sc_conf = LM75_TEST_PATTERN;
245 if (lm75_conf_write(sc) != 0)
246 return (-1);
247
248 /*
249 * Read the configuration register again and check for our test
250 * pattern.
251 */
252 if (lm75_conf_read(sc) != 0)
253 return (-1);
254 if (sc->sc_conf != LM75_TEST_PATTERN)
255 return (-1);
256
257 /*
258 * Read from nonexistent registers (0x4 ~ 0x6).
259 * LM75A always return 0xff for nonexistent registers.
260 * LM75 will return the last read value - our test pattern written to
261 * configuration register.
262 */
263 lm75a = 0;
264 for (i = 4; i <= 6; i++) {
265 if (lm75_read(sc->sc_dev, sc->sc_addr, i,
266 &buf8, sizeof(buf8)) < 0)
267 return (-1);
268 if (buf8 != LM75_TEST_PATTERN && buf8 != 0xff)
269 return (-1);
270 if (buf8 == 0xff)
271 lm75a++;
272 }
273 if (lm75a == 3){
274 sc->sc_multiplier = 1000;
275 sc->sc_resolution = 11;
276 sc->sc_max_resolution = 11;
277 }
278
279 /* Restore the configuration register. */
280 sc->sc_conf = conf;
281 if (lm75_conf_write(sc) != 0)
282 return (-1);
283
284 return (0);
285 }
286
287 static void
288 lm75_start(void *xdev)
289 {
290 device_t dev;
291 struct lm75_softc *sc;
292 struct sysctl_ctx_list *ctx;
293 struct sysctl_oid *tree_node;
294 struct sysctl_oid_list *tree;
295 char *mult_format;
296
297 dev = (device_t)xdev;
298 sc = device_get_softc(dev);
299 ctx = device_get_sysctl_ctx(dev);
300 tree_node = device_get_sysctl_tree(dev);
301 tree = SYSCTL_CHILDREN(tree_node);
302
303 config_intrhook_disestablish(&sc->enum_hook);
304
305 /*
306 * Detect the kind of chip we are attaching to.
307 * This may not work for LM75 clones.
308 */
309 if (lm75_type_detect(sc) != 0) {
310 device_printf(dev, "cannot detect sensor.\n");
311 #ifndef FDT
312 return;
313 #endif
314 }
315
316 device_printf(dev,"%d bit resolution sensor attached.\n",
317 sc->sc_resolution);
318
319 if (sc->sc_multiplier == 1000)
320 mult_format = "IK3";
321 else
322 mult_format = "IK";
323
324 /* Temperature. */
325 SYSCTL_ADD_PROC(ctx, tree, OID_AUTO, "temperature",
326 CTLTYPE_INT | CTLFLAG_RD | CTLFLAG_MPSAFE, dev, LM75_TEMP,
327 lm75_temp_sysctl, mult_format, "Current temperature");
328 SYSCTL_ADD_PROC(ctx, tree, OID_AUTO, "thyst",
329 CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_MPSAFE, dev, LM75_THYST,
330 lm75_temp_sysctl, mult_format, "Hysteresis temperature");
331 SYSCTL_ADD_PROC(ctx, tree, OID_AUTO, "tos",
332 CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_MPSAFE, dev, LM75_TOS,
333 lm75_temp_sysctl, mult_format, "Overtemperature");
334
335 /* Configuration parameters. */
336 SYSCTL_ADD_PROC(ctx, tree, OID_AUTO, "faults",
337 CTLFLAG_RW | CTLTYPE_UINT | CTLFLAG_MPSAFE, dev, 0,
338 lm75_faults_sysctl, "IU", "LM75 fault queue");
339 SYSCTL_ADD_PROC(ctx, tree, OID_AUTO, "mode",
340 CTLFLAG_RW | CTLTYPE_STRING | CTLFLAG_MPSAFE, dev, 0,
341 lm75_mode_sysctl, "A", "LM75 mode");
342 SYSCTL_ADD_PROC(ctx, tree, OID_AUTO, "polarity",
343 CTLFLAG_RW | CTLTYPE_STRING | CTLFLAG_MPSAFE, dev, 0,
344 lm75_pol_sysctl, "A", "LM75 OS polarity");
345 SYSCTL_ADD_PROC(ctx, tree, OID_AUTO, "shutdown",
346 CTLFLAG_RW | CTLTYPE_UINT | CTLFLAG_MPSAFE, dev, 0,
347 lm75_shutdown_sysctl, "IU", "LM75 shutdown");
348 SYSCTL_ADD_PROC(ctx, tree, OID_AUTO, "resolution",
349 CTLFLAG_RW | CTLTYPE_INT | CTLFLAG_MPSAFE, dev, 0,
350 lm75_resolution_sysctl, "IU", "LM75 resolution");
351 }
352
353 static int
354 lm75_conf_read(struct lm75_softc *sc)
355 {
356 uint8_t buf8;
357
358 if (lm75_read(sc->sc_dev, sc->sc_addr, LM75_CONF,
359 &buf8, sizeof(buf8)) < 0)
360 return (-1);
361 sc->sc_conf = (uint32_t)buf8;
362
363 return (0);
364 }
365
366 static int
367 lm75_conf_write(struct lm75_softc *sc)
368 {
369 uint8_t buf8[2];
370
371 buf8[0] = LM75_CONF;
372 buf8[1] = (uint8_t)sc->sc_conf & LM75_CONF_MASK;
373 if (lm75_write(sc->sc_dev, sc->sc_addr, buf8, sizeof(buf8)) < 0)
374 return (-1);
375
376 return (0);
377 }
378
379 static int
380 lm75_temp_read(struct lm75_softc *sc, uint8_t reg, int32_t *temp)
381 {
382 int32_t buf;
383 uint8_t buf8[2];
384 uint8_t resolution = sc->sc_resolution;
385 uint16_t multiplier = sc->sc_multiplier;
386
387 if (lm75_read(sc->sc_dev, sc->sc_addr, reg, buf8, sizeof(buf8)) < 0)
388 return (-1);
389
390 buf = (int16_t)((buf8[0] << 8) | buf8[1]);
391 *temp = ((buf >> (16 - resolution)) * multiplier) >> (resolution - 8);
392
393 *temp += TZ_ZEROC * sc->sc_multiplier / TZ_ZEROC_DIVIDER;
394
395 return (0);
396 }
397
398 static int
399 lm75_temp_write(struct lm75_softc *sc, uint8_t reg, int32_t temp)
400 {
401 int32_t buf;
402 uint8_t buf8[3], resolution = sc->sc_resolution;
403 uint16_t multiplier = sc->sc_multiplier;
404
405 temp -= TZ_ZEROC * multiplier / TZ_ZEROC_DIVIDER;
406 if (temp > LM75_MAX_TEMP * multiplier)
407 temp = LM75_MAX_TEMP * multiplier;
408 if (temp < LM75_MIN_TEMP * multiplier)
409 temp = LM75_MIN_TEMP * multiplier;
410
411 buf = ((temp << (resolution - 8)) / multiplier) << (16 - resolution);
412
413 buf8[0] = reg;
414 buf8[1] = (buf >> 8) & 0xff;
415 buf8[2] = buf & 0xff;
416
417 if (lm75_write(sc->sc_dev, sc->sc_addr, buf8, sizeof(buf8)) < 0)
418 return (-1);
419
420 return (0);
421 }
422
423 static int
424 lm75_str_mode(char *buf)
425 {
426 int len, rtrn;
427
428 rtrn = -1;
429 len = strlen(buf);
430 if (len > 2 && strncasecmp("interrupt", buf, len) == 0)
431 rtrn = 1;
432 else if (len > 2 && strncasecmp("comparator", buf, len) == 0)
433 rtrn = 0;
434
435 return (rtrn);
436 }
437
438 static int
439 lm75_str_pol(char *buf)
440 {
441 int len, rtrn;
442
443 rtrn = -1;
444 len = strlen(buf);
445 if (len > 1 && strncasecmp("high", buf, len) == 0)
446 rtrn = 1;
447 else if (len > 1 && strncasecmp("low", buf, len) == 0)
448 rtrn = 0;
449 else if (len > 8 && strncasecmp("active-high", buf, len) == 0)
450 rtrn = 1;
451 else if (len > 8 && strncasecmp("active-low", buf, len) == 0)
452 rtrn = 0;
453
454 return (rtrn);
455 }
456
457 static int
458 lm75_temp_sysctl(SYSCTL_HANDLER_ARGS)
459 {
460 device_t dev;
461 int error;
462 int32_t temp;
463 struct lm75_softc *sc;
464 uint8_t reg;
465
466 dev = (device_t)arg1;
467 reg = (uint8_t)arg2;
468 sc = device_get_softc(dev);
469
470 if (lm75_temp_read(sc, reg, &temp) != 0)
471 return (EIO);
472
473 error = sysctl_handle_int(oidp, &temp, 0, req);
474 if (error != 0 || req->newptr == NULL)
475 return (error);
476
477 if (lm75_temp_write(sc, reg, temp) != 0)
478 return (EIO);
479
480 return (error);
481 }
482
483 static int
484 lm75_faults_sysctl(SYSCTL_HANDLER_ARGS)
485 {
486 device_t dev;
487 int lm75_faults[] = { 1, 2, 4, 6 };
488 int error, faults, i, newf, tmp;
489 struct lm75_softc *sc;
490
491 dev = (device_t)arg1;
492 sc = device_get_softc(dev);
493 tmp = (sc->sc_conf & LM75_CONF_FAULT) >> LM75_CONF_FSHIFT;
494 if (tmp >= nitems(lm75_faults))
495 tmp = nitems(lm75_faults) - 1;
496 faults = lm75_faults[tmp];
497
498 error = sysctl_handle_int(oidp, &faults, 0, req);
499 if (error != 0 || req->newptr == NULL)
500 return (error);
501
502 if (faults != lm75_faults[tmp]) {
503 newf = 0;
504 for (i = 0; i < nitems(lm75_faults); i++)
505 if (faults >= lm75_faults[i])
506 newf = i;
507 sc->sc_conf &= ~LM75_CONF_FAULT;
508 sc->sc_conf |= newf << LM75_CONF_FSHIFT;
509 if (lm75_conf_write(sc) != 0)
510 return (EIO);
511 }
512
513 return (error);
514 }
515
516 static int
517 lm75_mode_sysctl(SYSCTL_HANDLER_ARGS)
518 {
519 char buf[16];
520 device_t dev;
521 int error, mode, newm;
522 struct lm75_softc *sc;
523
524 dev = (device_t)arg1;
525 sc = device_get_softc(dev);
526 if (sc->sc_conf & LM75_CONF_MODE) {
527 mode = 1;
528 strlcpy(buf, "interrupt", sizeof(buf));
529 } else {
530 mode = 0;
531 strlcpy(buf, "comparator", 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 newm = lm75_str_mode(buf);
539 if (newm != -1 && mode != newm) {
540 sc->sc_conf &= ~LM75_CONF_MODE;
541 if (newm == 1)
542 sc->sc_conf |= LM75_CONF_MODE;
543 if (lm75_conf_write(sc) != 0)
544 return (EIO);
545 }
546
547 return (error);
548 }
549
550 static int
551 lm75_pol_sysctl(SYSCTL_HANDLER_ARGS)
552 {
553 char buf[16];
554 device_t dev;
555 int error, newp, pol;
556 struct lm75_softc *sc;
557
558 dev = (device_t)arg1;
559 sc = device_get_softc(dev);
560 if (sc->sc_conf & LM75_CONF_POL) {
561 pol = 1;
562 strlcpy(buf, "active-high", sizeof(buf));
563 } else {
564 pol = 0;
565 strlcpy(buf, "active-low", sizeof(buf));
566 }
567
568 error = sysctl_handle_string(oidp, buf, sizeof(buf), req);
569 if (error != 0 || req->newptr == NULL)
570 return (error);
571
572 newp = lm75_str_pol(buf);
573 if (newp != -1 && pol != newp) {
574 sc->sc_conf &= ~LM75_CONF_POL;
575 if (newp == 1)
576 sc->sc_conf |= LM75_CONF_POL;
577 if (lm75_conf_write(sc) != 0)
578 return (EIO);
579 }
580
581 return (error);
582 }
583
584 static int
585 lm75_shutdown_sysctl(SYSCTL_HANDLER_ARGS)
586 {
587 device_t dev;
588 int error, shutdown, tmp;
589 struct lm75_softc *sc;
590
591 dev = (device_t)arg1;
592 sc = device_get_softc(dev);
593 tmp = shutdown = (sc->sc_conf & LM75_CONF_SHUTD) ? 1 : 0;
594
595 error = sysctl_handle_int(oidp, &shutdown, 0, req);
596 if (error != 0 || req->newptr == NULL)
597 return (error);
598
599 if (shutdown != tmp) {
600 sc->sc_conf &= ~LM75_CONF_SHUTD;
601 if (shutdown)
602 sc->sc_conf |= LM75_CONF_SHUTD;
603 if (lm75_conf_write(sc) != 0)
604 return (EIO);
605 }
606
607 return (error);
608 }
609
610 static int
611 lm75_resolution_sysctl(SYSCTL_HANDLER_ARGS)
612 {
613 device_t dev;
614 int error;
615 struct lm75_softc *sc;
616 int resolution;
617
618 dev = (device_t)arg1;
619 sc = device_get_softc(dev);
620 resolution = sc->sc_resolution;
621
622 error = sysctl_handle_int(oidp, &resolution, 0, req);
623 if (error != 0 || req->newptr == NULL)
624 return (error);
625
626 if (resolution > sc->sc_max_resolution || resolution < 9)
627 return (EINVAL);
628
629 sc->sc_resolution = (uint8_t) resolution;
630
631 return (0);
632 }
Cache object: f469823a7523750161584fcb01d24777
|