.. | .. |
---|
| 1 | +// SPDX-License-Identifier: GPL-2.0-or-later |
---|
1 | 2 | /* |
---|
2 | 3 | * lm90.c - Part of lm_sensors, Linux kernel modules for hardware |
---|
3 | 4 | * monitoring |
---|
.. | .. |
---|
34 | 35 | * explicitly as max6659, or if its address is not 0x4c. |
---|
35 | 36 | * These chips lack the remote temperature offset feature. |
---|
36 | 37 | * |
---|
| 38 | + * This driver also supports the MAX6654 chip made by Maxim. This chip can be |
---|
| 39 | + * at 9 different addresses, similar to MAX6680/MAX6681. The MAX6654 is similar |
---|
| 40 | + * to MAX6657/MAX6658/MAX6659, but does not support critical temperature |
---|
| 41 | + * limits. Extended range is available by setting the configuration register |
---|
| 42 | + * accordingly, and is done during initialization. Extended precision is only |
---|
| 43 | + * available at conversion rates of 1 Hz and slower. Note that extended |
---|
| 44 | + * precision is not enabled by default, as this driver initializes all chips |
---|
| 45 | + * to 2 Hz by design. |
---|
| 46 | + * |
---|
37 | 47 | * This driver also supports the MAX6646, MAX6647, MAX6648, MAX6649 and |
---|
38 | 48 | * MAX6692 chips made by Maxim. These are again similar to the LM86, |
---|
39 | 49 | * but they use unsigned temperature values and can report temperatures |
---|
.. | .. |
---|
60 | 70 | * This driver also supports the G781 from GMT. This device is compatible |
---|
61 | 71 | * with the ADM1032. |
---|
62 | 72 | * |
---|
63 | | - * This driver also supports TMP451 from Texas Instruments. This device is |
---|
64 | | - * supported in both compatibility and extended mode. It's mostly compatible |
---|
65 | | - * with ADT7461 except for local temperature low byte register and max |
---|
66 | | - * conversion rate. |
---|
| 73 | + * This driver also supports TMP451 and TMP461 from Texas Instruments. |
---|
| 74 | + * Those devices are supported in both compatibility and extended mode. |
---|
| 75 | + * They are mostly compatible with ADT7461 except for local temperature |
---|
| 76 | + * low byte register and max conversion rate. |
---|
67 | 77 | * |
---|
68 | 78 | * Since the LM90 was the first chipset supported by this driver, most |
---|
69 | 79 | * comments will refer to this chipset, but are actually general and |
---|
70 | 80 | * concern all supported chipsets, unless mentioned otherwise. |
---|
71 | | - * |
---|
72 | | - * This program is free software; you can redistribute it and/or modify |
---|
73 | | - * it under the terms of the GNU General Public License as published by |
---|
74 | | - * the Free Software Foundation; either version 2 of the License, or |
---|
75 | | - * (at your option) any later version. |
---|
76 | | - * |
---|
77 | | - * This program is distributed in the hope that it will be useful, |
---|
78 | | - * but WITHOUT ANY WARRANTY; without even the implied warranty of |
---|
79 | | - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
---|
80 | | - * GNU General Public License for more details. |
---|
81 | | - * |
---|
82 | | - * You should have received a copy of the GNU General Public License |
---|
83 | | - * along with this program; if not, write to the Free Software |
---|
84 | | - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. |
---|
85 | 81 | */ |
---|
86 | 82 | |
---|
87 | 83 | #include <linux/module.h> |
---|
.. | .. |
---|
107 | 103 | * have address 0x4d. |
---|
108 | 104 | * MAX6647 has address 0x4e. |
---|
109 | 105 | * MAX6659 can have address 0x4c, 0x4d or 0x4e. |
---|
110 | | - * MAX6680 and MAX6681 can have address 0x18, 0x19, 0x1a, 0x29, 0x2a, 0x2b, |
---|
111 | | - * 0x4c, 0x4d or 0x4e. |
---|
| 106 | + * MAX6654, MAX6680, and MAX6681 can have address 0x18, 0x19, 0x1a, 0x29, |
---|
| 107 | + * 0x2a, 0x2b, 0x4c, 0x4d or 0x4e. |
---|
112 | 108 | * SA56004 can have address 0x48 through 0x4F. |
---|
113 | 109 | */ |
---|
114 | 110 | |
---|
.. | .. |
---|
117 | 113 | 0x4d, 0x4e, 0x4f, I2C_CLIENT_END }; |
---|
118 | 114 | |
---|
119 | 115 | enum chips { lm90, adm1032, lm99, lm86, max6657, max6659, adt7461, max6680, |
---|
120 | | - max6646, w83l771, max6696, sa56004, g781, tmp451 }; |
---|
| 116 | + max6646, w83l771, max6696, sa56004, g781, tmp451, tmp461, max6654 }; |
---|
121 | 117 | |
---|
122 | 118 | /* |
---|
123 | 119 | * The LM90 registers |
---|
.. | .. |
---|
158 | 154 | #define LM90_REG_R_TCRIT_HYST 0x21 |
---|
159 | 155 | #define LM90_REG_W_TCRIT_HYST 0x21 |
---|
160 | 156 | |
---|
161 | | -/* MAX6646/6647/6649/6657/6658/6659/6695/6696 registers */ |
---|
| 157 | +/* MAX6646/6647/6649/6654/6657/6658/6659/6695/6696 registers */ |
---|
162 | 158 | |
---|
163 | 159 | #define MAX6657_REG_R_LOCAL_TEMPL 0x11 |
---|
164 | 160 | #define MAX6696_REG_R_STATUS2 0x12 |
---|
.. | .. |
---|
173 | 169 | |
---|
174 | 170 | #define LM90_MAX_CONVRATE_MS 16000 /* Maximum conversion rate in ms */ |
---|
175 | 171 | |
---|
176 | | -/* TMP451 registers */ |
---|
| 172 | +/* TMP451/TMP461 registers */ |
---|
177 | 173 | #define TMP451_REG_R_LOCAL_TEMPL 0x15 |
---|
| 174 | +#define TMP451_REG_CONALERT 0x22 |
---|
| 175 | + |
---|
| 176 | +#define TMP461_REG_CHEN 0x16 |
---|
| 177 | +#define TMP461_REG_DFC 0x24 |
---|
178 | 178 | |
---|
179 | 179 | /* |
---|
180 | 180 | * Device flags |
---|
.. | .. |
---|
187 | 187 | #define LM90_HAVE_EMERGENCY_ALARM (1 << 5)/* emergency alarm */ |
---|
188 | 188 | #define LM90_HAVE_TEMP3 (1 << 6) /* 3rd temperature sensor */ |
---|
189 | 189 | #define LM90_HAVE_BROKEN_ALERT (1 << 7) /* Broken alert */ |
---|
190 | | -#define LM90_PAUSE_FOR_CONFIG (1 << 8) /* Pause conversion for config */ |
---|
| 190 | +#define LM90_HAVE_EXTENDED_TEMP (1 << 8) /* extended temperature support*/ |
---|
| 191 | +#define LM90_PAUSE_FOR_CONFIG (1 << 9) /* Pause conversion for config */ |
---|
| 192 | +#define LM90_HAVE_CRIT (1 << 10)/* Chip supports CRIT/OVERT register */ |
---|
| 193 | +#define LM90_HAVE_CRIT_ALRM_SWP (1 << 11)/* critical alarm bits swapped */ |
---|
191 | 194 | |
---|
192 | 195 | /* LM90 status */ |
---|
193 | 196 | #define LM90_STATUS_LTHRM (1 << 0) /* local THERM limit tripped */ |
---|
.. | .. |
---|
223 | 226 | { "max6646", max6646 }, |
---|
224 | 227 | { "max6647", max6646 }, |
---|
225 | 228 | { "max6649", max6646 }, |
---|
| 229 | + { "max6654", max6654 }, |
---|
226 | 230 | { "max6657", max6657 }, |
---|
227 | 231 | { "max6658", max6657 }, |
---|
228 | 232 | { "max6659", max6659 }, |
---|
.. | .. |
---|
234 | 238 | { "w83l771", w83l771 }, |
---|
235 | 239 | { "sa56004", sa56004 }, |
---|
236 | 240 | { "tmp451", tmp451 }, |
---|
| 241 | + { "tmp461", tmp461 }, |
---|
237 | 242 | { } |
---|
238 | 243 | }; |
---|
239 | 244 | MODULE_DEVICE_TABLE(i2c, lm90_id); |
---|
240 | 245 | |
---|
241 | | -static const struct of_device_id lm90_of_match[] = { |
---|
| 246 | +static const struct of_device_id __maybe_unused lm90_of_match[] = { |
---|
242 | 247 | { |
---|
243 | 248 | .compatible = "adi,adm1032", |
---|
244 | 249 | .data = (void *)adm1032 |
---|
.. | .. |
---|
284 | 289 | .data = (void *)max6646 |
---|
285 | 290 | }, |
---|
286 | 291 | { |
---|
| 292 | + .compatible = "dallas,max6654", |
---|
| 293 | + .data = (void *)max6654 |
---|
| 294 | + }, |
---|
| 295 | + { |
---|
287 | 296 | .compatible = "dallas,max6657", |
---|
288 | 297 | .data = (void *)max6657 |
---|
289 | 298 | }, |
---|
.. | .. |
---|
327 | 336 | .compatible = "ti,tmp451", |
---|
328 | 337 | .data = (void *)tmp451 |
---|
329 | 338 | }, |
---|
| 339 | + { |
---|
| 340 | + .compatible = "ti,tmp461", |
---|
| 341 | + .data = (void *)tmp461 |
---|
| 342 | + }, |
---|
330 | 343 | { }, |
---|
331 | 344 | }; |
---|
332 | 345 | MODULE_DEVICE_TABLE(of, lm90_of_match); |
---|
.. | .. |
---|
345 | 358 | static const struct lm90_params lm90_params[] = { |
---|
346 | 359 | [adm1032] = { |
---|
347 | 360 | .flags = LM90_HAVE_OFFSET | LM90_HAVE_REM_LIMIT_EXT |
---|
348 | | - | LM90_HAVE_BROKEN_ALERT, |
---|
| 361 | + | LM90_HAVE_BROKEN_ALERT | LM90_HAVE_CRIT, |
---|
349 | 362 | .alert_alarms = 0x7c, |
---|
350 | 363 | .max_convrate = 10, |
---|
351 | 364 | }, |
---|
352 | 365 | [adt7461] = { |
---|
353 | 366 | .flags = LM90_HAVE_OFFSET | LM90_HAVE_REM_LIMIT_EXT |
---|
354 | | - | LM90_HAVE_BROKEN_ALERT, |
---|
| 367 | + | LM90_HAVE_BROKEN_ALERT | LM90_HAVE_EXTENDED_TEMP |
---|
| 368 | + | LM90_HAVE_CRIT, |
---|
355 | 369 | .alert_alarms = 0x7c, |
---|
356 | 370 | .max_convrate = 10, |
---|
357 | 371 | }, |
---|
358 | 372 | [g781] = { |
---|
359 | 373 | .flags = LM90_HAVE_OFFSET | LM90_HAVE_REM_LIMIT_EXT |
---|
360 | | - | LM90_HAVE_BROKEN_ALERT, |
---|
| 374 | + | LM90_HAVE_BROKEN_ALERT | LM90_HAVE_CRIT, |
---|
361 | 375 | .alert_alarms = 0x7c, |
---|
362 | 376 | .max_convrate = 7, |
---|
363 | 377 | }, |
---|
364 | 378 | [lm86] = { |
---|
365 | | - .flags = LM90_HAVE_OFFSET | LM90_HAVE_REM_LIMIT_EXT, |
---|
| 379 | + .flags = LM90_HAVE_OFFSET | LM90_HAVE_REM_LIMIT_EXT |
---|
| 380 | + | LM90_HAVE_CRIT, |
---|
366 | 381 | .alert_alarms = 0x7b, |
---|
367 | 382 | .max_convrate = 9, |
---|
368 | 383 | }, |
---|
369 | 384 | [lm90] = { |
---|
370 | | - .flags = LM90_HAVE_OFFSET | LM90_HAVE_REM_LIMIT_EXT, |
---|
| 385 | + .flags = LM90_HAVE_OFFSET | LM90_HAVE_REM_LIMIT_EXT |
---|
| 386 | + | LM90_HAVE_CRIT, |
---|
371 | 387 | .alert_alarms = 0x7b, |
---|
372 | 388 | .max_convrate = 9, |
---|
373 | 389 | }, |
---|
374 | 390 | [lm99] = { |
---|
375 | | - .flags = LM90_HAVE_OFFSET | LM90_HAVE_REM_LIMIT_EXT, |
---|
| 391 | + .flags = LM90_HAVE_OFFSET | LM90_HAVE_REM_LIMIT_EXT |
---|
| 392 | + | LM90_HAVE_CRIT, |
---|
376 | 393 | .alert_alarms = 0x7b, |
---|
377 | 394 | .max_convrate = 9, |
---|
378 | 395 | }, |
---|
379 | 396 | [max6646] = { |
---|
| 397 | + .flags = LM90_HAVE_CRIT | LM90_HAVE_BROKEN_ALERT, |
---|
380 | 398 | .alert_alarms = 0x7c, |
---|
381 | 399 | .max_convrate = 6, |
---|
382 | 400 | .reg_local_ext = MAX6657_REG_R_LOCAL_TEMPL, |
---|
383 | 401 | }, |
---|
| 402 | + [max6654] = { |
---|
| 403 | + .flags = LM90_HAVE_BROKEN_ALERT, |
---|
| 404 | + .alert_alarms = 0x7c, |
---|
| 405 | + .max_convrate = 7, |
---|
| 406 | + .reg_local_ext = MAX6657_REG_R_LOCAL_TEMPL, |
---|
| 407 | + }, |
---|
384 | 408 | [max6657] = { |
---|
385 | | - .flags = LM90_PAUSE_FOR_CONFIG, |
---|
| 409 | + .flags = LM90_PAUSE_FOR_CONFIG | LM90_HAVE_CRIT, |
---|
386 | 410 | .alert_alarms = 0x7c, |
---|
387 | 411 | .max_convrate = 8, |
---|
388 | 412 | .reg_local_ext = MAX6657_REG_R_LOCAL_TEMPL, |
---|
389 | 413 | }, |
---|
390 | 414 | [max6659] = { |
---|
391 | | - .flags = LM90_HAVE_EMERGENCY, |
---|
| 415 | + .flags = LM90_HAVE_EMERGENCY | LM90_HAVE_CRIT, |
---|
392 | 416 | .alert_alarms = 0x7c, |
---|
393 | 417 | .max_convrate = 8, |
---|
394 | 418 | .reg_local_ext = MAX6657_REG_R_LOCAL_TEMPL, |
---|
395 | 419 | }, |
---|
396 | 420 | [max6680] = { |
---|
397 | | - .flags = LM90_HAVE_OFFSET, |
---|
| 421 | + .flags = LM90_HAVE_OFFSET | LM90_HAVE_CRIT |
---|
| 422 | + | LM90_HAVE_CRIT_ALRM_SWP | LM90_HAVE_BROKEN_ALERT, |
---|
398 | 423 | .alert_alarms = 0x7c, |
---|
399 | 424 | .max_convrate = 7, |
---|
400 | 425 | }, |
---|
401 | 426 | [max6696] = { |
---|
402 | 427 | .flags = LM90_HAVE_EMERGENCY |
---|
403 | | - | LM90_HAVE_EMERGENCY_ALARM | LM90_HAVE_TEMP3, |
---|
| 428 | + | LM90_HAVE_EMERGENCY_ALARM | LM90_HAVE_TEMP3 | LM90_HAVE_CRIT, |
---|
404 | 429 | .alert_alarms = 0x1c7c, |
---|
405 | 430 | .max_convrate = 6, |
---|
406 | 431 | .reg_local_ext = MAX6657_REG_R_LOCAL_TEMPL, |
---|
407 | 432 | }, |
---|
408 | 433 | [w83l771] = { |
---|
409 | | - .flags = LM90_HAVE_OFFSET | LM90_HAVE_REM_LIMIT_EXT, |
---|
| 434 | + .flags = LM90_HAVE_OFFSET | LM90_HAVE_REM_LIMIT_EXT | LM90_HAVE_CRIT, |
---|
410 | 435 | .alert_alarms = 0x7c, |
---|
411 | 436 | .max_convrate = 8, |
---|
412 | 437 | }, |
---|
413 | 438 | [sa56004] = { |
---|
414 | | - .flags = LM90_HAVE_OFFSET | LM90_HAVE_REM_LIMIT_EXT, |
---|
| 439 | + .flags = LM90_HAVE_OFFSET | LM90_HAVE_REM_LIMIT_EXT | LM90_HAVE_CRIT, |
---|
415 | 440 | .alert_alarms = 0x7b, |
---|
416 | 441 | .max_convrate = 9, |
---|
417 | 442 | .reg_local_ext = SA56004_REG_R_LOCAL_TEMPL, |
---|
418 | 443 | }, |
---|
419 | 444 | [tmp451] = { |
---|
420 | 445 | .flags = LM90_HAVE_OFFSET | LM90_HAVE_REM_LIMIT_EXT |
---|
421 | | - | LM90_HAVE_BROKEN_ALERT, |
---|
| 446 | + | LM90_HAVE_BROKEN_ALERT | LM90_HAVE_EXTENDED_TEMP | LM90_HAVE_CRIT, |
---|
| 447 | + .alert_alarms = 0x7c, |
---|
| 448 | + .max_convrate = 9, |
---|
| 449 | + .reg_local_ext = TMP451_REG_R_LOCAL_TEMPL, |
---|
| 450 | + }, |
---|
| 451 | + [tmp461] = { |
---|
| 452 | + .flags = LM90_HAVE_OFFSET | LM90_HAVE_REM_LIMIT_EXT |
---|
| 453 | + | LM90_HAVE_BROKEN_ALERT | LM90_HAVE_EXTENDED_TEMP | LM90_HAVE_CRIT, |
---|
422 | 454 | .alert_alarms = 0x7c, |
---|
423 | 455 | .max_convrate = 9, |
---|
424 | 456 | .reg_local_ext = TMP451_REG_R_LOCAL_TEMPL, |
---|
.. | .. |
---|
473 | 505 | |
---|
474 | 506 | unsigned int update_interval; /* in milliseconds */ |
---|
475 | 507 | |
---|
| 508 | + u8 config; /* Current configuration register value */ |
---|
476 | 509 | u8 config_orig; /* Original configuration register value */ |
---|
477 | 510 | u8 convrate_orig; /* Original conversion rate register value */ |
---|
478 | 511 | u16 alert_alarms; /* Which alarm bits trigger ALERT# */ |
---|
.. | .. |
---|
556 | 589 | return (newh << 8) | l; |
---|
557 | 590 | } |
---|
558 | 591 | |
---|
| 592 | +static int lm90_update_confreg(struct lm90_data *data, u8 config) |
---|
| 593 | +{ |
---|
| 594 | + if (data->config != config) { |
---|
| 595 | + int err; |
---|
| 596 | + |
---|
| 597 | + err = i2c_smbus_write_byte_data(data->client, |
---|
| 598 | + LM90_REG_W_CONFIG1, |
---|
| 599 | + config); |
---|
| 600 | + if (err) |
---|
| 601 | + return err; |
---|
| 602 | + data->config = config; |
---|
| 603 | + } |
---|
| 604 | + return 0; |
---|
| 605 | +} |
---|
| 606 | + |
---|
559 | 607 | /* |
---|
560 | 608 | * client->update_lock must be held when calling this function (unless we are |
---|
561 | 609 | * in detection or initialization steps), and while a remote channel other |
---|
.. | .. |
---|
564 | 612 | * various registers have different meanings as a result of selecting a |
---|
565 | 613 | * non-default remote channel. |
---|
566 | 614 | */ |
---|
567 | | -static inline int lm90_select_remote_channel(struct i2c_client *client, |
---|
568 | | - struct lm90_data *data, |
---|
569 | | - int channel) |
---|
| 615 | +static int lm90_select_remote_channel(struct lm90_data *data, int channel) |
---|
570 | 616 | { |
---|
571 | | - int config; |
---|
| 617 | + int err = 0; |
---|
572 | 618 | |
---|
573 | 619 | if (data->kind == max6696) { |
---|
574 | | - config = lm90_read_reg(client, LM90_REG_R_CONFIG1); |
---|
575 | | - if (config < 0) |
---|
576 | | - return config; |
---|
577 | | - config &= ~0x08; |
---|
| 620 | + u8 config = data->config & ~0x08; |
---|
| 621 | + |
---|
578 | 622 | if (channel) |
---|
579 | 623 | config |= 0x08; |
---|
580 | | - i2c_smbus_write_byte_data(client, LM90_REG_W_CONFIG1, |
---|
581 | | - config); |
---|
| 624 | + err = lm90_update_confreg(data, config); |
---|
582 | 625 | } |
---|
583 | | - return 0; |
---|
| 626 | + return err; |
---|
584 | 627 | } |
---|
585 | 628 | |
---|
586 | | -static int lm90_write_convrate(struct i2c_client *client, |
---|
587 | | - struct lm90_data *data, int val) |
---|
| 629 | +static int lm90_write_convrate(struct lm90_data *data, int val) |
---|
588 | 630 | { |
---|
| 631 | + u8 config = data->config; |
---|
589 | 632 | int err; |
---|
590 | | - int config_orig, config_stop; |
---|
591 | 633 | |
---|
592 | 634 | /* Save config and pause conversion */ |
---|
593 | 635 | if (data->flags & LM90_PAUSE_FOR_CONFIG) { |
---|
594 | | - config_orig = lm90_read_reg(client, LM90_REG_R_CONFIG1); |
---|
595 | | - if (config_orig < 0) |
---|
596 | | - return config_orig; |
---|
597 | | - config_stop = config_orig | 0x40; |
---|
598 | | - if (config_orig != config_stop) { |
---|
599 | | - err = i2c_smbus_write_byte_data(client, |
---|
600 | | - LM90_REG_W_CONFIG1, |
---|
601 | | - config_stop); |
---|
602 | | - if (err < 0) |
---|
603 | | - return err; |
---|
604 | | - } |
---|
| 636 | + err = lm90_update_confreg(data, config | 0x40); |
---|
| 637 | + if (err < 0) |
---|
| 638 | + return err; |
---|
605 | 639 | } |
---|
606 | 640 | |
---|
607 | 641 | /* Set conv rate */ |
---|
608 | | - err = i2c_smbus_write_byte_data(client, LM90_REG_W_CONVRATE, val); |
---|
| 642 | + err = i2c_smbus_write_byte_data(data->client, LM90_REG_W_CONVRATE, val); |
---|
609 | 643 | |
---|
610 | 644 | /* Revert change to config */ |
---|
611 | | - if (data->flags & LM90_PAUSE_FOR_CONFIG && config_orig != config_stop) |
---|
612 | | - i2c_smbus_write_byte_data(client, LM90_REG_W_CONFIG1, |
---|
613 | | - config_orig); |
---|
| 645 | + lm90_update_confreg(data, config); |
---|
614 | 646 | |
---|
615 | 647 | return err; |
---|
616 | 648 | } |
---|
.. | .. |
---|
635 | 667 | if (interval >= update_interval * 3 / 4) |
---|
636 | 668 | break; |
---|
637 | 669 | |
---|
638 | | - err = lm90_write_convrate(client, data, i); |
---|
| 670 | + err = lm90_write_convrate(data, i); |
---|
639 | 671 | data->update_interval = DIV_ROUND_CLOSEST(update_interval, 64); |
---|
640 | 672 | return err; |
---|
641 | 673 | } |
---|
.. | .. |
---|
646 | 678 | struct i2c_client *client = data->client; |
---|
647 | 679 | int val; |
---|
648 | 680 | |
---|
649 | | - val = lm90_read_reg(client, LM90_REG_R_LOCAL_CRIT); |
---|
650 | | - if (val < 0) |
---|
651 | | - return val; |
---|
652 | | - data->temp8[LOCAL_CRIT] = val; |
---|
| 681 | + if (data->flags & LM90_HAVE_CRIT) { |
---|
| 682 | + val = lm90_read_reg(client, LM90_REG_R_LOCAL_CRIT); |
---|
| 683 | + if (val < 0) |
---|
| 684 | + return val; |
---|
| 685 | + data->temp8[LOCAL_CRIT] = val; |
---|
653 | 686 | |
---|
654 | | - val = lm90_read_reg(client, LM90_REG_R_REMOTE_CRIT); |
---|
655 | | - if (val < 0) |
---|
656 | | - return val; |
---|
657 | | - data->temp8[REMOTE_CRIT] = val; |
---|
| 687 | + val = lm90_read_reg(client, LM90_REG_R_REMOTE_CRIT); |
---|
| 688 | + if (val < 0) |
---|
| 689 | + return val; |
---|
| 690 | + data->temp8[REMOTE_CRIT] = val; |
---|
658 | 691 | |
---|
659 | | - val = lm90_read_reg(client, LM90_REG_R_TCRIT_HYST); |
---|
660 | | - if (val < 0) |
---|
661 | | - return val; |
---|
662 | | - data->temp_hyst = val; |
---|
| 692 | + val = lm90_read_reg(client, LM90_REG_R_TCRIT_HYST); |
---|
| 693 | + if (val < 0) |
---|
| 694 | + return val; |
---|
| 695 | + data->temp_hyst = val; |
---|
| 696 | + } |
---|
663 | 697 | |
---|
664 | 698 | val = lm90_read_reg(client, LM90_REG_R_REMOTE_LOWH); |
---|
665 | 699 | if (val < 0) |
---|
.. | .. |
---|
706 | 740 | } |
---|
707 | 741 | |
---|
708 | 742 | if (data->kind == max6696) { |
---|
709 | | - val = lm90_select_remote_channel(client, data, 1); |
---|
| 743 | + val = lm90_select_remote_channel(data, 1); |
---|
710 | 744 | if (val < 0) |
---|
711 | 745 | return val; |
---|
712 | 746 | |
---|
.. | .. |
---|
730 | 764 | return val; |
---|
731 | 765 | data->temp11[REMOTE2_HIGH] = val << 8; |
---|
732 | 766 | |
---|
733 | | - lm90_select_remote_channel(client, data, 0); |
---|
| 767 | + lm90_select_remote_channel(data, 0); |
---|
734 | 768 | } |
---|
735 | 769 | |
---|
736 | 770 | return 0; |
---|
.. | .. |
---|
790 | 824 | data->alarms = val & ~LM90_STATUS_BUSY; |
---|
791 | 825 | |
---|
792 | 826 | if (data->kind == max6696) { |
---|
793 | | - val = lm90_select_remote_channel(client, data, 1); |
---|
| 827 | + val = lm90_select_remote_channel(data, 1); |
---|
794 | 828 | if (val < 0) |
---|
795 | 829 | return val; |
---|
796 | 830 | |
---|
797 | 831 | val = lm90_read16(client, LM90_REG_R_REMOTE_TEMPH, |
---|
798 | 832 | LM90_REG_R_REMOTE_TEMPL); |
---|
799 | 833 | if (val < 0) { |
---|
800 | | - lm90_select_remote_channel(client, data, 0); |
---|
| 834 | + lm90_select_remote_channel(data, 0); |
---|
801 | 835 | return val; |
---|
802 | 836 | } |
---|
803 | 837 | data->temp11[REMOTE2_TEMP] = val; |
---|
804 | 838 | |
---|
805 | | - lm90_select_remote_channel(client, data, 0); |
---|
| 839 | + lm90_select_remote_channel(data, 0); |
---|
806 | 840 | |
---|
807 | 841 | val = lm90_read_reg(client, MAX6696_REG_R_STATUS2); |
---|
808 | 842 | if (val < 0) |
---|
.. | .. |
---|
816 | 850 | */ |
---|
817 | 851 | if (!(data->config_orig & 0x80) && |
---|
818 | 852 | !(data->alarms & data->alert_alarms)) { |
---|
819 | | - val = lm90_read_reg(client, LM90_REG_R_CONFIG1); |
---|
820 | | - if (val < 0) |
---|
821 | | - return val; |
---|
822 | | - |
---|
823 | | - if (val & 0x80) { |
---|
| 853 | + if (data->config & 0x80) { |
---|
824 | 854 | dev_dbg(&client->dev, "Re-enabling ALERT#\n"); |
---|
825 | | - i2c_smbus_write_byte_data(client, |
---|
826 | | - LM90_REG_W_CONFIG1, |
---|
827 | | - val & ~0x80); |
---|
| 855 | + lm90_update_confreg(data, data->config & ~0x80); |
---|
828 | 856 | } |
---|
829 | 857 | } |
---|
830 | 858 | |
---|
.. | .. |
---|
999 | 1027 | s16 temp11 = data->temp11[index]; |
---|
1000 | 1028 | int temp; |
---|
1001 | 1029 | |
---|
1002 | | - if (data->kind == adt7461 || data->kind == tmp451) |
---|
| 1030 | + if (data->flags & LM90_HAVE_EXTENDED_TEMP) |
---|
1003 | 1031 | temp = temp_from_u16_adt7461(data, temp11); |
---|
1004 | 1032 | else if (data->kind == max6646) |
---|
1005 | 1033 | temp = temp_from_u16(temp11); |
---|
.. | .. |
---|
1033 | 1061 | if (data->kind == lm99 && index <= 2) |
---|
1034 | 1062 | val -= 16000; |
---|
1035 | 1063 | |
---|
1036 | | - if (data->kind == adt7461 || data->kind == tmp451) |
---|
| 1064 | + if (data->flags & LM90_HAVE_EXTENDED_TEMP) |
---|
1037 | 1065 | data->temp11[index] = temp_to_u16_adt7461(data, val); |
---|
1038 | 1066 | else if (data->kind == max6646) |
---|
1039 | 1067 | data->temp11[index] = temp_to_u8(val) << 8; |
---|
.. | .. |
---|
1042 | 1070 | else |
---|
1043 | 1071 | data->temp11[index] = temp_to_s8(val) << 8; |
---|
1044 | 1072 | |
---|
1045 | | - lm90_select_remote_channel(client, data, index >= 3); |
---|
| 1073 | + lm90_select_remote_channel(data, index >= 3); |
---|
1046 | 1074 | err = i2c_smbus_write_byte_data(client, regp->high, |
---|
1047 | 1075 | data->temp11[index] >> 8); |
---|
1048 | 1076 | if (err < 0) |
---|
.. | .. |
---|
1051 | 1079 | err = i2c_smbus_write_byte_data(client, regp->low, |
---|
1052 | 1080 | data->temp11[index] & 0xff); |
---|
1053 | 1081 | |
---|
1054 | | - lm90_select_remote_channel(client, data, 0); |
---|
| 1082 | + lm90_select_remote_channel(data, 0); |
---|
1055 | 1083 | return err; |
---|
1056 | 1084 | } |
---|
1057 | 1085 | |
---|
.. | .. |
---|
1060 | 1088 | s8 temp8 = data->temp8[index]; |
---|
1061 | 1089 | int temp; |
---|
1062 | 1090 | |
---|
1063 | | - if (data->kind == adt7461 || data->kind == tmp451) |
---|
| 1091 | + if (data->flags & LM90_HAVE_EXTENDED_TEMP) |
---|
1064 | 1092 | temp = temp_from_u8_adt7461(data, temp8); |
---|
1065 | 1093 | else if (data->kind == max6646) |
---|
1066 | 1094 | temp = temp_from_u8(temp8); |
---|
.. | .. |
---|
1093 | 1121 | if (data->kind == lm99 && index == 3) |
---|
1094 | 1122 | val -= 16000; |
---|
1095 | 1123 | |
---|
1096 | | - if (data->kind == adt7461 || data->kind == tmp451) |
---|
| 1124 | + if (data->flags & LM90_HAVE_EXTENDED_TEMP) |
---|
1097 | 1125 | data->temp8[index] = temp_to_u8_adt7461(data, val); |
---|
1098 | 1126 | else if (data->kind == max6646) |
---|
1099 | 1127 | data->temp8[index] = temp_to_u8(val); |
---|
1100 | 1128 | else |
---|
1101 | 1129 | data->temp8[index] = temp_to_s8(val); |
---|
1102 | 1130 | |
---|
1103 | | - lm90_select_remote_channel(client, data, index >= 6); |
---|
| 1131 | + lm90_select_remote_channel(data, index >= 6); |
---|
1104 | 1132 | err = i2c_smbus_write_byte_data(client, reg[index], data->temp8[index]); |
---|
1105 | | - lm90_select_remote_channel(client, data, 0); |
---|
| 1133 | + lm90_select_remote_channel(data, 0); |
---|
1106 | 1134 | |
---|
1107 | 1135 | return err; |
---|
1108 | 1136 | } |
---|
.. | .. |
---|
1111 | 1139 | { |
---|
1112 | 1140 | int temp; |
---|
1113 | 1141 | |
---|
1114 | | - if (data->kind == adt7461 || data->kind == tmp451) |
---|
| 1142 | + if (data->flags & LM90_HAVE_EXTENDED_TEMP) |
---|
1115 | 1143 | temp = temp_from_u8_adt7461(data, data->temp8[index]); |
---|
1116 | 1144 | else if (data->kind == max6646) |
---|
1117 | 1145 | temp = temp_from_u8(data->temp8[index]); |
---|
.. | .. |
---|
1131 | 1159 | int temp; |
---|
1132 | 1160 | int err; |
---|
1133 | 1161 | |
---|
1134 | | - if (data->kind == adt7461 || data->kind == tmp451) |
---|
| 1162 | + if (data->flags & LM90_HAVE_EXTENDED_TEMP) |
---|
1135 | 1163 | temp = temp_from_u8_adt7461(data, data->temp8[LOCAL_CRIT]); |
---|
1136 | 1164 | else if (data->kind == max6646) |
---|
1137 | 1165 | temp = temp_from_u8(data->temp8[LOCAL_CRIT]); |
---|
.. | .. |
---|
1167 | 1195 | static const u8 lm90_min_alarm_bits[3] = { 5, 3, 11 }; |
---|
1168 | 1196 | static const u8 lm90_max_alarm_bits[3] = { 6, 4, 12 }; |
---|
1169 | 1197 | static const u8 lm90_crit_alarm_bits[3] = { 0, 1, 9 }; |
---|
| 1198 | +static const u8 lm90_crit_alarm_bits_swapped[3] = { 1, 0, 9 }; |
---|
1170 | 1199 | static const u8 lm90_emergency_alarm_bits[3] = { 15, 13, 14 }; |
---|
1171 | 1200 | static const u8 lm90_fault_bits[3] = { 0, 2, 10 }; |
---|
1172 | 1201 | |
---|
.. | .. |
---|
1192 | 1221 | *val = (data->alarms >> lm90_max_alarm_bits[channel]) & 1; |
---|
1193 | 1222 | break; |
---|
1194 | 1223 | case hwmon_temp_crit_alarm: |
---|
1195 | | - *val = (data->alarms >> lm90_crit_alarm_bits[channel]) & 1; |
---|
| 1224 | + if (data->flags & LM90_HAVE_CRIT_ALRM_SWP) |
---|
| 1225 | + *val = (data->alarms >> lm90_crit_alarm_bits_swapped[channel]) & 1; |
---|
| 1226 | + else |
---|
| 1227 | + *val = (data->alarms >> lm90_crit_alarm_bits[channel]) & 1; |
---|
1196 | 1228 | break; |
---|
1197 | 1229 | case hwmon_temp_emergency_alarm: |
---|
1198 | 1230 | *val = (data->alarms >> lm90_emergency_alarm_bits[channel]) & 1; |
---|
.. | .. |
---|
1301 | 1333 | case hwmon_temp_emergency_alarm: |
---|
1302 | 1334 | case hwmon_temp_emergency_hyst: |
---|
1303 | 1335 | case hwmon_temp_fault: |
---|
1304 | | - return S_IRUGO; |
---|
| 1336 | + return 0444; |
---|
1305 | 1337 | case hwmon_temp_min: |
---|
1306 | 1338 | case hwmon_temp_max: |
---|
1307 | 1339 | case hwmon_temp_crit: |
---|
1308 | 1340 | case hwmon_temp_emergency: |
---|
1309 | 1341 | case hwmon_temp_offset: |
---|
1310 | | - return S_IRUGO | S_IWUSR; |
---|
| 1342 | + return 0644; |
---|
1311 | 1343 | case hwmon_temp_crit_hyst: |
---|
1312 | 1344 | if (channel == 0) |
---|
1313 | | - return S_IRUGO | S_IWUSR; |
---|
1314 | | - return S_IRUGO; |
---|
| 1345 | + return 0644; |
---|
| 1346 | + return 0444; |
---|
1315 | 1347 | default: |
---|
1316 | 1348 | return 0; |
---|
1317 | 1349 | } |
---|
.. | .. |
---|
1373 | 1405 | { |
---|
1374 | 1406 | switch (attr) { |
---|
1375 | 1407 | case hwmon_chip_update_interval: |
---|
1376 | | - return S_IRUGO | S_IWUSR; |
---|
| 1408 | + return 0644; |
---|
1377 | 1409 | case hwmon_chip_alarms: |
---|
1378 | | - return S_IRUGO; |
---|
| 1410 | + return 0444; |
---|
1379 | 1411 | default: |
---|
1380 | 1412 | return 0; |
---|
1381 | 1413 | } |
---|
.. | .. |
---|
1576 | 1608 | && (config1 & 0x3f) == 0x00 |
---|
1577 | 1609 | && convrate <= 0x07) { |
---|
1578 | 1610 | name = "max6646"; |
---|
| 1611 | + } else |
---|
| 1612 | + /* |
---|
| 1613 | + * The chip_id of the MAX6654 holds the revision of the chip. |
---|
| 1614 | + * The lowest 3 bits of the config1 register are unused and |
---|
| 1615 | + * should return zero when read. |
---|
| 1616 | + */ |
---|
| 1617 | + if (chip_id == 0x08 |
---|
| 1618 | + && (config1 & 0x07) == 0x00 |
---|
| 1619 | + && convrate <= 0x07) { |
---|
| 1620 | + name = "max6654"; |
---|
1579 | 1621 | } |
---|
1580 | 1622 | } else |
---|
1581 | 1623 | if (address == 0x4C |
---|
.. | .. |
---|
1608 | 1650 | && convrate <= 0x08) |
---|
1609 | 1651 | name = "g781"; |
---|
1610 | 1652 | } else |
---|
1611 | | - if (address == 0x4C |
---|
1612 | | - && man_id == 0x55) { /* Texas Instruments */ |
---|
1613 | | - int local_ext; |
---|
| 1653 | + if (man_id == 0x55 && chip_id == 0x00 && |
---|
| 1654 | + (config1 & 0x1B) == 0x00 && convrate <= 0x09) { |
---|
| 1655 | + int local_ext, conalert, chen, dfc; |
---|
1614 | 1656 | |
---|
1615 | 1657 | local_ext = i2c_smbus_read_byte_data(client, |
---|
1616 | 1658 | TMP451_REG_R_LOCAL_TEMPL); |
---|
| 1659 | + conalert = i2c_smbus_read_byte_data(client, |
---|
| 1660 | + TMP451_REG_CONALERT); |
---|
| 1661 | + chen = i2c_smbus_read_byte_data(client, TMP461_REG_CHEN); |
---|
| 1662 | + dfc = i2c_smbus_read_byte_data(client, TMP461_REG_DFC); |
---|
1617 | 1663 | |
---|
1618 | | - if (chip_id == 0x00 /* TMP451 */ |
---|
1619 | | - && (config1 & 0x1B) == 0x00 |
---|
1620 | | - && convrate <= 0x09 |
---|
1621 | | - && (local_ext & 0x0F) == 0x00) |
---|
1622 | | - name = "tmp451"; |
---|
| 1664 | + if ((local_ext & 0x0F) == 0x00 && |
---|
| 1665 | + (conalert & 0xf1) == 0x01 && |
---|
| 1666 | + (chen & 0xfc) == 0x00 && |
---|
| 1667 | + (dfc & 0xfc) == 0x00) { |
---|
| 1668 | + if (address == 0x4c && !(chen & 0x03)) |
---|
| 1669 | + name = "tmp451"; |
---|
| 1670 | + else if (address >= 0x48 && address <= 0x4f) |
---|
| 1671 | + name = "tmp461"; |
---|
| 1672 | + } |
---|
1623 | 1673 | } |
---|
1624 | 1674 | |
---|
1625 | 1675 | if (!name) { /* identification failed */ |
---|
.. | .. |
---|
1640 | 1690 | struct i2c_client *client = data->client; |
---|
1641 | 1691 | |
---|
1642 | 1692 | /* Restore initial configuration */ |
---|
1643 | | - lm90_write_convrate(client, data, data->convrate_orig); |
---|
| 1693 | + lm90_write_convrate(data, data->convrate_orig); |
---|
1644 | 1694 | i2c_smbus_write_byte_data(client, LM90_REG_W_CONFIG1, |
---|
1645 | 1695 | data->config_orig); |
---|
1646 | 1696 | } |
---|
.. | .. |
---|
1661 | 1711 | if (config < 0) |
---|
1662 | 1712 | return config; |
---|
1663 | 1713 | data->config_orig = config; |
---|
| 1714 | + data->config = config; |
---|
1664 | 1715 | |
---|
1665 | 1716 | lm90_set_convrate(client, data, 500); /* 500ms; 2Hz conversion rate */ |
---|
1666 | 1717 | |
---|
1667 | 1718 | /* Check Temperature Range Select */ |
---|
1668 | | - if (data->kind == adt7461 || data->kind == tmp451) { |
---|
| 1719 | + if (data->flags & LM90_HAVE_EXTENDED_TEMP) { |
---|
1669 | 1720 | if (config & 0x04) |
---|
1670 | 1721 | data->flags |= LM90_FLAG_ADT7461_EXT; |
---|
1671 | 1722 | } |
---|
.. | .. |
---|
1679 | 1730 | config |= 0x18; |
---|
1680 | 1731 | |
---|
1681 | 1732 | /* |
---|
| 1733 | + * Put MAX6654 into extended range (0x20, extend minimum range from |
---|
| 1734 | + * 0 degrees to -64 degrees). Note that extended resolution is not |
---|
| 1735 | + * possible on the MAX6654 unless conversion rate is set to 1 Hz or |
---|
| 1736 | + * slower, which is intentionally not done by default. |
---|
| 1737 | + */ |
---|
| 1738 | + if (data->kind == max6654) |
---|
| 1739 | + config |= 0x20; |
---|
| 1740 | + |
---|
| 1741 | + /* |
---|
1682 | 1742 | * Select external channel 0 for max6695/96 |
---|
1683 | 1743 | */ |
---|
1684 | 1744 | if (data->kind == max6696) |
---|
1685 | 1745 | config &= ~0x08; |
---|
1686 | 1746 | |
---|
1687 | 1747 | config &= 0xBF; /* run */ |
---|
1688 | | - if (config != data->config_orig) /* Only write if changed */ |
---|
1689 | | - i2c_smbus_write_byte_data(client, LM90_REG_W_CONFIG1, config); |
---|
| 1748 | + lm90_update_confreg(data, config); |
---|
1690 | 1749 | |
---|
1691 | 1750 | return devm_add_action_or_reset(&client->dev, lm90_restore_conf, data); |
---|
1692 | 1751 | } |
---|
.. | .. |
---|
1754 | 1813 | regulator_disable(regulator); |
---|
1755 | 1814 | } |
---|
1756 | 1815 | |
---|
1757 | | -static const u32 lm90_chip_config[] = { |
---|
1758 | | - HWMON_C_REGISTER_TZ | HWMON_C_UPDATE_INTERVAL | HWMON_C_ALARMS, |
---|
1759 | | - 0 |
---|
1760 | | -}; |
---|
1761 | | - |
---|
1762 | | -static const struct hwmon_channel_info lm90_chip_info = { |
---|
1763 | | - .type = hwmon_chip, |
---|
1764 | | - .config = lm90_chip_config, |
---|
1765 | | -}; |
---|
1766 | | - |
---|
1767 | 1816 | |
---|
1768 | 1817 | static const struct hwmon_ops lm90_ops = { |
---|
1769 | 1818 | .is_visible = lm90_is_visible, |
---|
.. | .. |
---|
1771 | 1820 | .write = lm90_write, |
---|
1772 | 1821 | }; |
---|
1773 | 1822 | |
---|
1774 | | -static int lm90_probe(struct i2c_client *client, |
---|
1775 | | - const struct i2c_device_id *id) |
---|
| 1823 | +static int lm90_probe(struct i2c_client *client) |
---|
1776 | 1824 | { |
---|
1777 | 1825 | struct device *dev = &client->dev; |
---|
1778 | | - struct i2c_adapter *adapter = to_i2c_adapter(dev->parent); |
---|
| 1826 | + struct i2c_adapter *adapter = client->adapter; |
---|
1779 | 1827 | struct hwmon_channel_info *info; |
---|
1780 | 1828 | struct regulator *regulator; |
---|
1781 | 1829 | struct device *hwmon_dev; |
---|
.. | .. |
---|
1808 | 1856 | if (client->dev.of_node) |
---|
1809 | 1857 | data->kind = (enum chips)of_device_get_match_data(&client->dev); |
---|
1810 | 1858 | else |
---|
1811 | | - data->kind = id->driver_data; |
---|
| 1859 | + data->kind = i2c_match_id(lm90_id, client)->driver_data; |
---|
1812 | 1860 | if (data->kind == adm1032) { |
---|
1813 | 1861 | if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE)) |
---|
1814 | 1862 | client->flags &= ~I2C_CLIENT_PEC; |
---|
.. | .. |
---|
1826 | 1874 | data->chip.ops = &lm90_ops; |
---|
1827 | 1875 | data->chip.info = data->info; |
---|
1828 | 1876 | |
---|
1829 | | - data->info[0] = &lm90_chip_info; |
---|
| 1877 | + data->info[0] = HWMON_CHANNEL_INFO(chip, |
---|
| 1878 | + HWMON_C_REGISTER_TZ | HWMON_C_UPDATE_INTERVAL | HWMON_C_ALARMS); |
---|
1830 | 1879 | data->info[1] = &data->temp_info; |
---|
1831 | 1880 | |
---|
1832 | 1881 | info = &data->temp_info; |
---|
.. | .. |
---|
1834 | 1883 | info->config = data->channel_config; |
---|
1835 | 1884 | |
---|
1836 | 1885 | data->channel_config[0] = HWMON_T_INPUT | HWMON_T_MIN | HWMON_T_MAX | |
---|
1837 | | - HWMON_T_CRIT | HWMON_T_CRIT_HYST | HWMON_T_MIN_ALARM | |
---|
1838 | | - HWMON_T_MAX_ALARM | HWMON_T_CRIT_ALARM; |
---|
| 1886 | + HWMON_T_MIN_ALARM | HWMON_T_MAX_ALARM; |
---|
1839 | 1887 | data->channel_config[1] = HWMON_T_INPUT | HWMON_T_MIN | HWMON_T_MAX | |
---|
1840 | | - HWMON_T_CRIT | HWMON_T_CRIT_HYST | HWMON_T_MIN_ALARM | |
---|
1841 | | - HWMON_T_MAX_ALARM | HWMON_T_CRIT_ALARM | HWMON_T_FAULT; |
---|
| 1888 | + HWMON_T_MIN_ALARM | HWMON_T_MAX_ALARM | HWMON_T_FAULT; |
---|
| 1889 | + |
---|
| 1890 | + if (data->flags & LM90_HAVE_CRIT) { |
---|
| 1891 | + data->channel_config[0] |= HWMON_T_CRIT | HWMON_T_CRIT_ALARM | HWMON_T_CRIT_HYST; |
---|
| 1892 | + data->channel_config[1] |= HWMON_T_CRIT | HWMON_T_CRIT_ALARM | HWMON_T_CRIT_HYST; |
---|
| 1893 | + } |
---|
1842 | 1894 | |
---|
1843 | 1895 | if (data->flags & LM90_HAVE_OFFSET) |
---|
1844 | 1896 | data->channel_config[1] |= HWMON_T_OFFSET; |
---|
.. | .. |
---|
1929 | 1981 | |
---|
1930 | 1982 | if ((data->flags & LM90_HAVE_BROKEN_ALERT) && |
---|
1931 | 1983 | (alarms & data->alert_alarms)) { |
---|
1932 | | - int config; |
---|
1933 | | - |
---|
1934 | 1984 | dev_dbg(&client->dev, "Disabling ALERT#\n"); |
---|
1935 | | - config = lm90_read_reg(client, LM90_REG_R_CONFIG1); |
---|
1936 | | - if (config >= 0) |
---|
1937 | | - i2c_smbus_write_byte_data(client, |
---|
1938 | | - LM90_REG_W_CONFIG1, |
---|
1939 | | - config | 0x80); |
---|
| 1985 | + lm90_update_confreg(data, data->config | 0x80); |
---|
1940 | 1986 | } |
---|
1941 | 1987 | } else { |
---|
1942 | 1988 | dev_info(&client->dev, "Everything OK\n"); |
---|
.. | .. |
---|
1949 | 1995 | .name = "lm90", |
---|
1950 | 1996 | .of_match_table = of_match_ptr(lm90_of_match), |
---|
1951 | 1997 | }, |
---|
1952 | | - .probe = lm90_probe, |
---|
| 1998 | + .probe_new = lm90_probe, |
---|
1953 | 1999 | .alert = lm90_alert, |
---|
1954 | 2000 | .id_table = lm90_id, |
---|
1955 | 2001 | .detect = lm90_detect, |
---|