Commit adfeb6e9f46ded31b46fe406ad0dd6a9b4e0f7fe
Exists in
master
and in
6 other branches
Merge branch 'hwmon-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/jdelvare/staging
* 'hwmon-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/jdelvare/staging: hwmon: (sysfs-interface) Update tempX_type attribute to be more generic hwmon: (adm1031) Fix coding style issues hwmon: (it87) Add IT8728F support hwmon: (coretemp) Add missing section annotations hwmon: (lm90) Add range check to set_update_interval hwmon: (lm63) Support extended lookup table of LM96163 hwmon: (lm63) Expose automatic fan speed control lookup table hwmon: (lm63) Fix incorrect comment about I2C address hwmon: (lm63) LM64 has a dedicated pin for tachometer hwmon: (lm63) Add sensor type attribute for external sensor on LM96163 hwmon: (lm63) Add support for update_interval sysfs attribute hwmon: (lm63) Add support for writing the external critical temperature hwmon: (lm63) Add support for unsigned upper temperature limits hwmon: (lm63) Add support for LM96163 hwmon: (lm63) Add support for external temperature offset register hwmon: (lm63) Fix checkpatch errors hwmon: (max1111) Change sysfs interface to in[0-3]_input in millivolts
Showing 10 changed files Side-by-side Diff
Documentation/hwmon/it87
... | ... | @@ -26,6 +26,10 @@ |
26 | 26 | Prefix: 'it8721' |
27 | 27 | Addresses scanned: from Super I/O config space (8 I/O ports) |
28 | 28 | Datasheet: Not publicly available |
29 | + * IT8728F | |
30 | + Prefix: 'it8728' | |
31 | + Addresses scanned: from Super I/O config space (8 I/O ports) | |
32 | + Datasheet: Not publicly available | |
29 | 33 | * SiS950 [clone of IT8705F] |
30 | 34 | Prefix: 'it87' |
31 | 35 | Addresses scanned: from Super I/O config space (8 I/O ports) |
... | ... | @@ -71,7 +75,7 @@ |
71 | 75 | ----------- |
72 | 76 | |
73 | 77 | This driver implements support for the IT8705F, IT8712F, IT8716F, |
74 | -IT8718F, IT8720F, IT8721F, IT8726F, IT8758E and SiS950 chips. | |
78 | +IT8718F, IT8720F, IT8721F, IT8726F, IT8728F, IT8758E and SiS950 chips. | |
75 | 79 | |
76 | 80 | These chips are 'Super I/O chips', supporting floppy disks, infrared ports, |
77 | 81 | joysticks and other miscellaneous stuff. For hardware monitoring, they |
... | ... | @@ -105,6 +109,9 @@ |
105 | 109 | for AMD power sequencing. Therefore the chip will appear as IT8716F |
106 | 110 | to userspace applications. |
107 | 111 | |
112 | +The IT8728F is considered compatible with the IT8721F, until a datasheet | |
113 | +becomes available (hopefully.) | |
114 | + | |
108 | 115 | Temperatures are measured in degrees Celsius. An alarm is triggered once |
109 | 116 | when the Overtemperature Shutdown limit is crossed. |
110 | 117 | |
... | ... | @@ -121,8 +128,8 @@ |
121 | 128 | maximum limit. Note that minimum in this case always means 'closest to |
122 | 129 | zero'; this is important for negative voltage measurements. All voltage |
123 | 130 | inputs can measure voltages between 0 and 4.08 volts, with a resolution of |
124 | -0.016 volt (except IT8721F/IT8758E: 0.012 volt.) The battery voltage in8 does | |
125 | -not have limit registers. | |
131 | +0.016 volt (except IT8721F/IT8758E and IT8728F: 0.012 volt.) The battery | |
132 | +voltage in8 does not have limit registers. | |
126 | 133 | |
127 | 134 | On the IT8721F/IT8758E, some voltage inputs are internal and scaled inside |
128 | 135 | the chip (in7, in8 and optionally in3). The driver handles this transparently |
Documentation/hwmon/lm63
... | ... | @@ -12,6 +12,11 @@ |
12 | 12 | Addresses scanned: I2C 0x18 and 0x4e |
13 | 13 | Datasheet: Publicly available at the National Semiconductor website |
14 | 14 | http://www.national.com/pf/LM/LM64.html |
15 | + * National Semiconductor LM96163 | |
16 | + Prefix: 'lm96163' | |
17 | + Addresses scanned: I2C 0x4c | |
18 | + Datasheet: Publicly available at the National Semiconductor website | |
19 | + http://www.national.com/pf/LM/LM96163.html | |
15 | 20 | |
16 | 21 | Author: Jean Delvare <khali@linux-fr.org> |
17 | 22 | |
18 | 23 | |
19 | 24 | |
... | ... | @@ -49,17 +54,25 @@ |
49 | 54 | Note that the pin used for fan monitoring is shared with an alert out |
50 | 55 | function. Depending on how the board designer wanted to use the chip, fan |
51 | 56 | speed monitoring will or will not be possible. The proper chip configuration |
52 | -is left to the BIOS, and the driver will blindly trust it. | |
57 | +is left to the BIOS, and the driver will blindly trust it. Only the original | |
58 | +LM63 suffers from this limitation, the LM64 and LM96163 have separate pins | |
59 | +for fan monitoring and alert out. On the LM64, monitoring is always enabled; | |
60 | +on the LM96163 it can be disabled. | |
53 | 61 | |
54 | 62 | A PWM output can be used to control the speed of the fan. The LM63 has two |
55 | 63 | PWM modes: manual and automatic. Automatic mode is not fully implemented yet |
56 | 64 | (you cannot define your custom PWM/temperature curve), and mode change isn't |
57 | 65 | supported either. |
58 | 66 | |
59 | -The lm63 driver will not update its values more frequently than every | |
60 | -second; reading them more often will do no harm, but will return 'old' | |
61 | -values. | |
67 | +The lm63 driver will not update its values more frequently than configured with | |
68 | +the update_interval sysfs attribute; reading them more often will do no harm, | |
69 | +but will return 'old' values. Values in the automatic fan control lookup table | |
70 | +(attributes pwm1_auto_*) have their own independent lifetime of 5 seconds. | |
62 | 71 | |
63 | 72 | The LM64 is effectively an LM63 with GPIO lines. The driver does not |
64 | 73 | support these GPIO lines at present. |
74 | + | |
75 | +The LM96163 is an enhanced version of LM63 with improved temperature accuracy | |
76 | +and better PWM resolution. For LM96163, the external temperature sensor type is | |
77 | +configurable as CPU embedded diode(1) or 3904 transistor(2). |
Documentation/hwmon/sysfs-interface
drivers/hwmon/Kconfig
... | ... | @@ -474,8 +474,8 @@ |
474 | 474 | select HWMON_VID |
475 | 475 | help |
476 | 476 | If you say yes here you get support for ITE IT8705F, IT8712F, |
477 | - IT8716F, IT8718F, IT8720F, IT8721F, IT8726F and IT8758E sensor | |
478 | - chips, and the SiS960 clone. | |
477 | + IT8716F, IT8718F, IT8720F, IT8721F, IT8726F, IT8728F and IT8758E | |
478 | + sensor chips, and the SiS960 clone. | |
479 | 479 | |
480 | 480 | This driver can also be built as a module. If so, the module |
481 | 481 | will be called it87. |
482 | 482 | |
... | ... | @@ -515,11 +515,11 @@ |
515 | 515 | will be called lineage-pem. |
516 | 516 | |
517 | 517 | config SENSORS_LM63 |
518 | - tristate "National Semiconductor LM63 and LM64" | |
518 | + tristate "National Semiconductor LM63 and compatibles" | |
519 | 519 | depends on I2C |
520 | 520 | help |
521 | 521 | If you say yes here you get support for the National |
522 | - Semiconductor LM63 and LM64 remote diode digital temperature | |
522 | + Semiconductor LM63, LM64, and LM96163 remote diode digital temperature | |
523 | 523 | sensors with integrated fan control. Such chips are found |
524 | 524 | on the Tyan S4882 (Thunder K8QS Pro) motherboard, among |
525 | 525 | others. |
drivers/hwmon/adm1031.c
... | ... | @@ -155,7 +155,8 @@ |
155 | 155 | #define TEMP_OFFSET_FROM_REG(val) TEMP_FROM_REG((val) < 0 ? \ |
156 | 156 | (val) | 0x70 : (val)) |
157 | 157 | |
158 | -#define FAN_FROM_REG(reg, div) ((reg) ? (11250 * 60) / ((reg) * (div)) : 0) | |
158 | +#define FAN_FROM_REG(reg, div) ((reg) ? \ | |
159 | + (11250 * 60) / ((reg) * (div)) : 0) | |
159 | 160 | |
160 | 161 | static int FAN_TO_REG(int reg, int div) |
161 | 162 | { |
... | ... | @@ -174,8 +175,8 @@ |
174 | 175 | (((reg) & 0x1F) | (((val) << 5) & 0xe0)) |
175 | 176 | |
176 | 177 | #define AUTO_TEMP_MIN_TO_REG(val, reg) \ |
177 | - ((((val)/500) & 0xf8)|((reg) & 0x7)) | |
178 | -#define AUTO_TEMP_RANGE_FROM_REG(reg) (5000 * (1<< ((reg)&0x7))) | |
178 | + ((((val) / 500) & 0xf8) | ((reg) & 0x7)) | |
179 | +#define AUTO_TEMP_RANGE_FROM_REG(reg) (5000 * (1 << ((reg) & 0x7))) | |
179 | 180 | #define AUTO_TEMP_MIN_FROM_REG(reg) (1000 * ((((reg) >> 3) & 0x1f) << 2)) |
180 | 181 | |
181 | 182 | #define AUTO_TEMP_MIN_FROM_REG_DEG(reg) ((((reg) >> 3) & 0x1f) << 2) |
... | ... | @@ -202,7 +203,7 @@ |
202 | 203 | |
203 | 204 | /* FAN auto control */ |
204 | 205 | #define GET_FAN_AUTO_BITFIELD(data, idx) \ |
205 | - (*(data)->chan_select_table)[FAN_CHAN_FROM_REG((data)->conf1)][idx%2] | |
206 | + (*(data)->chan_select_table)[FAN_CHAN_FROM_REG((data)->conf1)][idx % 2] | |
206 | 207 | |
207 | 208 | /* The tables below contains the possible values for the auto fan |
208 | 209 | * control bitfields. the index in the table is the register value. |
... | ... | @@ -230,7 +231,7 @@ |
230 | 231 | */ |
231 | 232 | static int |
232 | 233 | get_fan_auto_nearest(struct adm1031_data *data, |
233 | - int chan, u8 val, u8 reg, u8 * new_reg) | |
234 | + int chan, u8 val, u8 reg, u8 *new_reg) | |
234 | 235 | { |
235 | 236 | int i; |
236 | 237 | int first_match = -1, exact_match = -1; |
237 | 238 | |
238 | 239 | |
239 | 240 | |
... | ... | @@ -258,13 +259,13 @@ |
258 | 259 | } |
259 | 260 | } |
260 | 261 | |
261 | - if (exact_match >= 0) { | |
262 | + if (exact_match >= 0) | |
262 | 263 | *new_reg = exact_match; |
263 | - } else if (first_match >= 0) { | |
264 | + else if (first_match >= 0) | |
264 | 265 | *new_reg = first_match; |
265 | - } else { | |
266 | + else | |
266 | 267 | return -EINVAL; |
267 | - } | |
268 | + | |
268 | 269 | return 0; |
269 | 270 | } |
270 | 271 | |
271 | 272 | |
272 | 273 | |
273 | 274 | |
... | ... | @@ -283,23 +284,28 @@ |
283 | 284 | struct i2c_client *client = to_i2c_client(dev); |
284 | 285 | struct adm1031_data *data = i2c_get_clientdata(client); |
285 | 286 | int nr = to_sensor_dev_attr(attr)->index; |
286 | - int val = simple_strtol(buf, NULL, 10); | |
287 | + long val; | |
287 | 288 | u8 reg; |
288 | 289 | int ret; |
289 | 290 | u8 old_fan_mode; |
290 | 291 | |
292 | + ret = kstrtol(buf, 10, &val); | |
293 | + if (ret) | |
294 | + return ret; | |
295 | + | |
291 | 296 | old_fan_mode = data->conf1; |
292 | 297 | |
293 | 298 | mutex_lock(&data->update_lock); |
294 | 299 | |
295 | - if ((ret = get_fan_auto_nearest(data, nr, val, data->conf1, ®))) { | |
300 | + ret = get_fan_auto_nearest(data, nr, val, data->conf1, ®); | |
301 | + if (ret) { | |
296 | 302 | mutex_unlock(&data->update_lock); |
297 | 303 | return ret; |
298 | 304 | } |
299 | 305 | data->conf1 = FAN_CHAN_TO_REG(reg, data->conf1); |
300 | 306 | if ((data->conf1 & ADM1031_CONF1_AUTO_MODE) ^ |
301 | 307 | (old_fan_mode & ADM1031_CONF1_AUTO_MODE)) { |
302 | - if (data->conf1 & ADM1031_CONF1_AUTO_MODE){ | |
308 | + if (data->conf1 & ADM1031_CONF1_AUTO_MODE) { | |
303 | 309 | /* Switch to Auto Fan Mode |
304 | 310 | * Save PWM registers |
305 | 311 | * Set PWM registers to 33% Both */ |
306 | 312 | |
... | ... | @@ -350,8 +356,13 @@ |
350 | 356 | struct i2c_client *client = to_i2c_client(dev); |
351 | 357 | struct adm1031_data *data = i2c_get_clientdata(client); |
352 | 358 | int nr = to_sensor_dev_attr(attr)->index; |
353 | - int val = simple_strtol(buf, NULL, 10); | |
359 | + long val; | |
360 | + int ret; | |
354 | 361 | |
362 | + ret = kstrtol(buf, 10, &val); | |
363 | + if (ret) | |
364 | + return ret; | |
365 | + | |
355 | 366 | mutex_lock(&data->update_lock); |
356 | 367 | data->auto_temp[nr] = AUTO_TEMP_MIN_TO_REG(val, data->auto_temp[nr]); |
357 | 368 | adm1031_write_value(client, ADM1031_REG_AUTO_TEMP(nr), |
358 | 369 | |
359 | 370 | |
... | ... | @@ -374,10 +385,16 @@ |
374 | 385 | struct i2c_client *client = to_i2c_client(dev); |
375 | 386 | struct adm1031_data *data = i2c_get_clientdata(client); |
376 | 387 | int nr = to_sensor_dev_attr(attr)->index; |
377 | - int val = simple_strtol(buf, NULL, 10); | |
388 | + long val; | |
389 | + int ret; | |
378 | 390 | |
391 | + ret = kstrtol(buf, 10, &val); | |
392 | + if (ret) | |
393 | + return ret; | |
394 | + | |
379 | 395 | mutex_lock(&data->update_lock); |
380 | - data->temp_max[nr] = AUTO_TEMP_MAX_TO_REG(val, data->auto_temp[nr], data->pwm[nr]); | |
396 | + data->temp_max[nr] = AUTO_TEMP_MAX_TO_REG(val, data->auto_temp[nr], | |
397 | + data->pwm[nr]); | |
381 | 398 | adm1031_write_value(client, ADM1031_REG_AUTO_TEMP(nr), |
382 | 399 | data->temp_max[nr]); |
383 | 400 | mutex_unlock(&data->update_lock); |
384 | 401 | |
... | ... | @@ -410,9 +427,13 @@ |
410 | 427 | struct i2c_client *client = to_i2c_client(dev); |
411 | 428 | struct adm1031_data *data = i2c_get_clientdata(client); |
412 | 429 | int nr = to_sensor_dev_attr(attr)->index; |
413 | - int val = simple_strtol(buf, NULL, 10); | |
414 | - int reg; | |
430 | + long val; | |
431 | + int ret, reg; | |
415 | 432 | |
433 | + ret = kstrtol(buf, 10, &val); | |
434 | + if (ret) | |
435 | + return ret; | |
436 | + | |
416 | 437 | mutex_lock(&data->update_lock); |
417 | 438 | if ((data->conf1 & ADM1031_CONF1_AUTO_MODE) && |
418 | 439 | (((val>>4) & 0xf) != 5)) { |
419 | 440 | |
... | ... | @@ -449,9 +470,13 @@ |
449 | 470 | |
450 | 471 | if (data->conf1 & ADM1031_CONF1_AUTO_MODE) { |
451 | 472 | switch (data->conf1 & 0x60) { |
452 | - case 0x00: /* remote temp1 controls fan1 remote temp2 controls fan2 */ | |
473 | + case 0x00: | |
474 | + /* | |
475 | + * remote temp1 controls fan1, | |
476 | + * remote temp2 controls fan2 | |
477 | + */ | |
453 | 478 | res = data->temp[chan+1] >= |
454 | - AUTO_TEMP_MIN_FROM_REG_DEG(data->auto_temp[chan+1]); | |
479 | + AUTO_TEMP_MIN_FROM_REG_DEG(data->auto_temp[chan+1]); | |
455 | 480 | break; |
456 | 481 | case 0x20: /* remote temp1 controls both fans */ |
457 | 482 | res = |
458 | 483 | |
... | ... | @@ -515,8 +540,13 @@ |
515 | 540 | struct i2c_client *client = to_i2c_client(dev); |
516 | 541 | struct adm1031_data *data = i2c_get_clientdata(client); |
517 | 542 | int nr = to_sensor_dev_attr(attr)->index; |
518 | - int val = simple_strtol(buf, NULL, 10); | |
543 | + long val; | |
544 | + int ret; | |
519 | 545 | |
546 | + ret = kstrtol(buf, 10, &val); | |
547 | + if (ret) | |
548 | + return ret; | |
549 | + | |
520 | 550 | mutex_lock(&data->update_lock); |
521 | 551 | if (val) { |
522 | 552 | data->fan_min[nr] = |
523 | 553 | |
524 | 554 | |
... | ... | @@ -534,11 +564,16 @@ |
534 | 564 | struct i2c_client *client = to_i2c_client(dev); |
535 | 565 | struct adm1031_data *data = i2c_get_clientdata(client); |
536 | 566 | int nr = to_sensor_dev_attr(attr)->index; |
537 | - int val = simple_strtol(buf, NULL, 10); | |
567 | + long val; | |
538 | 568 | u8 tmp; |
539 | 569 | int old_div; |
540 | 570 | int new_min; |
571 | + int ret; | |
541 | 572 | |
573 | + ret = kstrtol(buf, 10, &val); | |
574 | + if (ret) | |
575 | + return ret; | |
576 | + | |
542 | 577 | tmp = val == 8 ? 0xc0 : |
543 | 578 | val == 4 ? 0x80 : |
544 | 579 | val == 2 ? 0x40 : |
545 | 580 | |
... | ... | @@ -631,9 +666,13 @@ |
631 | 666 | struct i2c_client *client = to_i2c_client(dev); |
632 | 667 | struct adm1031_data *data = i2c_get_clientdata(client); |
633 | 668 | int nr = to_sensor_dev_attr(attr)->index; |
634 | - int val; | |
669 | + long val; | |
670 | + int ret; | |
635 | 671 | |
636 | - val = simple_strtol(buf, NULL, 10); | |
672 | + ret = kstrtol(buf, 10, &val); | |
673 | + if (ret) | |
674 | + return ret; | |
675 | + | |
637 | 676 | val = SENSORS_LIMIT(val, -15000, 15000); |
638 | 677 | mutex_lock(&data->update_lock); |
639 | 678 | data->temp_offset[nr] = TEMP_OFFSET_TO_REG(val); |
640 | 679 | |
... | ... | @@ -648,9 +687,13 @@ |
648 | 687 | struct i2c_client *client = to_i2c_client(dev); |
649 | 688 | struct adm1031_data *data = i2c_get_clientdata(client); |
650 | 689 | int nr = to_sensor_dev_attr(attr)->index; |
651 | - int val; | |
690 | + long val; | |
691 | + int ret; | |
652 | 692 | |
653 | - val = simple_strtol(buf, NULL, 10); | |
693 | + ret = kstrtol(buf, 10, &val); | |
694 | + if (ret) | |
695 | + return ret; | |
696 | + | |
654 | 697 | val = SENSORS_LIMIT(val, -55000, nr == 0 ? 127750 : 127875); |
655 | 698 | mutex_lock(&data->update_lock); |
656 | 699 | data->temp_min[nr] = TEMP_TO_REG(val); |
657 | 700 | |
... | ... | @@ -665,9 +708,13 @@ |
665 | 708 | struct i2c_client *client = to_i2c_client(dev); |
666 | 709 | struct adm1031_data *data = i2c_get_clientdata(client); |
667 | 710 | int nr = to_sensor_dev_attr(attr)->index; |
668 | - int val; | |
711 | + long val; | |
712 | + int ret; | |
669 | 713 | |
670 | - val = simple_strtol(buf, NULL, 10); | |
714 | + ret = kstrtol(buf, 10, &val); | |
715 | + if (ret) | |
716 | + return ret; | |
717 | + | |
671 | 718 | val = SENSORS_LIMIT(val, -55000, nr == 0 ? 127750 : 127875); |
672 | 719 | mutex_lock(&data->update_lock); |
673 | 720 | data->temp_max[nr] = TEMP_TO_REG(val); |
674 | 721 | |
... | ... | @@ -682,9 +729,13 @@ |
682 | 729 | struct i2c_client *client = to_i2c_client(dev); |
683 | 730 | struct adm1031_data *data = i2c_get_clientdata(client); |
684 | 731 | int nr = to_sensor_dev_attr(attr)->index; |
685 | - int val; | |
732 | + long val; | |
733 | + int ret; | |
686 | 734 | |
687 | - val = simple_strtol(buf, NULL, 10); | |
735 | + ret = kstrtol(buf, 10, &val); | |
736 | + if (ret) | |
737 | + return ret; | |
738 | + | |
688 | 739 | val = SENSORS_LIMIT(val, -55000, nr == 0 ? 127750 : 127875); |
689 | 740 | mutex_lock(&data->update_lock); |
690 | 741 | data->temp_crit[nr] = TEMP_TO_REG(val); |
... | ... | @@ -711,7 +762,8 @@ |
711 | 762 | temp_reg(3); |
712 | 763 | |
713 | 764 | /* Alarms */ |
714 | -static ssize_t show_alarms(struct device *dev, struct device_attribute *attr, char *buf) | |
765 | +static ssize_t show_alarms(struct device *dev, struct device_attribute *attr, | |
766 | + char *buf) | |
715 | 767 | { |
716 | 768 | struct adm1031_data *data = adm1031_update_device(dev); |
717 | 769 | return sprintf(buf, "%d\n", data->alarm); |
718 | 770 | |
... | ... | @@ -919,12 +971,13 @@ |
919 | 971 | adm1031_init_client(client); |
920 | 972 | |
921 | 973 | /* Register sysfs hooks */ |
922 | - if ((err = sysfs_create_group(&client->dev.kobj, &adm1031_group))) | |
974 | + err = sysfs_create_group(&client->dev.kobj, &adm1031_group); | |
975 | + if (err) | |
923 | 976 | goto exit_free; |
924 | 977 | |
925 | 978 | if (data->chip_type == adm1031) { |
926 | - if ((err = sysfs_create_group(&client->dev.kobj, | |
927 | - &adm1031_group_opt))) | |
979 | + err = sysfs_create_group(&client->dev.kobj, &adm1031_group_opt); | |
980 | + if (err) | |
928 | 981 | goto exit_remove; |
929 | 982 | } |
930 | 983 | |
931 | 984 | |
... | ... | @@ -970,14 +1023,13 @@ |
970 | 1023 | } |
971 | 1024 | /* Initialize the ADM1031 chip (enables fan speed reading ) */ |
972 | 1025 | read_val = adm1031_read_value(client, ADM1031_REG_CONF2); |
973 | - if ((read_val | mask) != read_val) { | |
974 | - adm1031_write_value(client, ADM1031_REG_CONF2, read_val | mask); | |
975 | - } | |
1026 | + if ((read_val | mask) != read_val) | |
1027 | + adm1031_write_value(client, ADM1031_REG_CONF2, read_val | mask); | |
976 | 1028 | |
977 | 1029 | read_val = adm1031_read_value(client, ADM1031_REG_CONF1); |
978 | 1030 | if ((read_val | ADM1031_CONF1_MONITOR_ENABLE) != read_val) { |
979 | - adm1031_write_value(client, ADM1031_REG_CONF1, read_val | | |
980 | - ADM1031_CONF1_MONITOR_ENABLE); | |
1031 | + adm1031_write_value(client, ADM1031_REG_CONF1, | |
1032 | + read_val | ADM1031_CONF1_MONITOR_ENABLE); | |
981 | 1033 | } |
982 | 1034 | |
983 | 1035 | /* Read the chip's update rate */ |
... | ... | @@ -1024,8 +1076,7 @@ |
1024 | 1076 | /* oldh is actually newer */ |
1025 | 1077 | if (newh != oldh) |
1026 | 1078 | dev_warn(&client->dev, |
1027 | - "Remote temperature may be " | |
1028 | - "wrong.\n"); | |
1079 | + "Remote temperature may be wrong.\n"); | |
1029 | 1080 | #endif |
1030 | 1081 | } |
1031 | 1082 | data->temp[chan] = newh; |
1032 | 1083 | |
1033 | 1084 | |
1034 | 1085 | |
1035 | 1086 | |
1036 | 1087 | |
1037 | 1088 | |
... | ... | @@ -1052,22 +1103,24 @@ |
1052 | 1103 | data->conf2 = adm1031_read_value(client, ADM1031_REG_CONF2); |
1053 | 1104 | |
1054 | 1105 | data->alarm = adm1031_read_value(client, ADM1031_REG_STATUS(0)) |
1055 | - | (adm1031_read_value(client, ADM1031_REG_STATUS(1)) | |
1056 | - << 8); | |
1057 | - if (data->chip_type == adm1030) { | |
1106 | + | (adm1031_read_value(client, ADM1031_REG_STATUS(1)) << 8); | |
1107 | + if (data->chip_type == adm1030) | |
1058 | 1108 | data->alarm &= 0xc0ff; |
1059 | - } | |
1060 | 1109 | |
1061 | - for (chan=0; chan<(data->chip_type == adm1030 ? 1 : 2); chan++) { | |
1110 | + for (chan = 0; chan < (data->chip_type == adm1030 ? 1 : 2); | |
1111 | + chan++) { | |
1062 | 1112 | data->fan_div[chan] = |
1063 | - adm1031_read_value(client, ADM1031_REG_FAN_DIV(chan)); | |
1113 | + adm1031_read_value(client, | |
1114 | + ADM1031_REG_FAN_DIV(chan)); | |
1064 | 1115 | data->fan_min[chan] = |
1065 | - adm1031_read_value(client, ADM1031_REG_FAN_MIN(chan)); | |
1116 | + adm1031_read_value(client, | |
1117 | + ADM1031_REG_FAN_MIN(chan)); | |
1066 | 1118 | data->fan[chan] = |
1067 | - adm1031_read_value(client, ADM1031_REG_FAN_SPEED(chan)); | |
1119 | + adm1031_read_value(client, | |
1120 | + ADM1031_REG_FAN_SPEED(chan)); | |
1068 | 1121 | data->pwm[chan] = |
1069 | - 0xf & (adm1031_read_value(client, ADM1031_REG_PWM) >> | |
1070 | - (4*chan)); | |
1122 | + (adm1031_read_value(client, | |
1123 | + ADM1031_REG_PWM) >> (4 * chan)) & 0x0f; | |
1071 | 1124 | } |
1072 | 1125 | data->last_updated = jiffies; |
1073 | 1126 | data->valid = 1; |
drivers/hwmon/coretemp.c
... | ... | @@ -190,7 +190,8 @@ |
190 | 190 | return tdata->valid ? sprintf(buf, "%d\n", tdata->temp) : -EAGAIN; |
191 | 191 | } |
192 | 192 | |
193 | -static int adjust_tjmax(struct cpuinfo_x86 *c, u32 id, struct device *dev) | |
193 | +static int __cpuinit adjust_tjmax(struct cpuinfo_x86 *c, u32 id, | |
194 | + struct device *dev) | |
194 | 195 | { |
195 | 196 | /* The 100C is default for both mobile and non mobile CPUs */ |
196 | 197 | |
... | ... | @@ -284,7 +285,8 @@ |
284 | 285 | return tjmax; |
285 | 286 | } |
286 | 287 | |
287 | -static int get_tjmax(struct cpuinfo_x86 *c, u32 id, struct device *dev) | |
288 | +static int __cpuinit get_tjmax(struct cpuinfo_x86 *c, u32 id, | |
289 | + struct device *dev) | |
288 | 290 | { |
289 | 291 | int err; |
290 | 292 | u32 eax, edx; |
... | ... | @@ -323,7 +325,8 @@ |
323 | 325 | return adjust_tjmax(c, id, dev); |
324 | 326 | } |
325 | 327 | |
326 | -static int create_name_attr(struct platform_data *pdata, struct device *dev) | |
328 | +static int __devinit create_name_attr(struct platform_data *pdata, | |
329 | + struct device *dev) | |
327 | 330 | { |
328 | 331 | sysfs_attr_init(&pdata->name_attr.attr); |
329 | 332 | pdata->name_attr.attr.name = "name"; |
... | ... | @@ -332,8 +335,8 @@ |
332 | 335 | return device_create_file(dev, &pdata->name_attr); |
333 | 336 | } |
334 | 337 | |
335 | -static int create_core_attrs(struct temp_data *tdata, struct device *dev, | |
336 | - int attr_no) | |
338 | +static int __cpuinit create_core_attrs(struct temp_data *tdata, | |
339 | + struct device *dev, int attr_no) | |
337 | 340 | { |
338 | 341 | int err, i; |
339 | 342 | static ssize_t (*const rd_ptr[TOTAL_ATTRS]) (struct device *dev, |
... | ... | @@ -383,7 +386,7 @@ |
383 | 386 | return 0; |
384 | 387 | } |
385 | 388 | |
386 | -static struct platform_device *coretemp_get_pdev(unsigned int cpu) | |
389 | +static struct platform_device __cpuinit *coretemp_get_pdev(unsigned int cpu) | |
387 | 390 | { |
388 | 391 | u16 phys_proc_id = TO_PHYS_ID(cpu); |
389 | 392 | struct pdev_entry *p; |
... | ... | @@ -400,7 +403,8 @@ |
400 | 403 | return NULL; |
401 | 404 | } |
402 | 405 | |
403 | -static struct temp_data *init_temp_data(unsigned int cpu, int pkg_flag) | |
406 | +static struct temp_data __cpuinit *init_temp_data(unsigned int cpu, | |
407 | + int pkg_flag) | |
404 | 408 | { |
405 | 409 | struct temp_data *tdata; |
406 | 410 | |
... | ... | @@ -418,7 +422,7 @@ |
418 | 422 | return tdata; |
419 | 423 | } |
420 | 424 | |
421 | -static int create_core_data(struct platform_device *pdev, | |
425 | +static int __cpuinit create_core_data(struct platform_device *pdev, | |
422 | 426 | unsigned int cpu, int pkg_flag) |
423 | 427 | { |
424 | 428 | struct temp_data *tdata; |
... | ... | @@ -489,7 +493,7 @@ |
489 | 493 | return err; |
490 | 494 | } |
491 | 495 | |
492 | -static void coretemp_add_core(unsigned int cpu, int pkg_flag) | |
496 | +static void __cpuinit coretemp_add_core(unsigned int cpu, int pkg_flag) | |
493 | 497 | { |
494 | 498 | struct platform_device *pdev = coretemp_get_pdev(cpu); |
495 | 499 | int err; |
... | ... | @@ -618,7 +622,7 @@ |
618 | 622 | return err; |
619 | 623 | } |
620 | 624 | |
621 | -static void coretemp_device_remove(unsigned int cpu) | |
625 | +static void __cpuinit coretemp_device_remove(unsigned int cpu) | |
622 | 626 | { |
623 | 627 | struct pdev_entry *p, *n; |
624 | 628 | u16 phys_proc_id = TO_PHYS_ID(cpu); |
... | ... | @@ -634,7 +638,7 @@ |
634 | 638 | mutex_unlock(&pdev_list_mutex); |
635 | 639 | } |
636 | 640 | |
637 | -static bool is_any_core_online(struct platform_data *pdata) | |
641 | +static bool __cpuinit is_any_core_online(struct platform_data *pdata) | |
638 | 642 | { |
639 | 643 | int i; |
640 | 644 |
drivers/hwmon/it87.c
... | ... | @@ -17,6 +17,7 @@ |
17 | 17 | * IT8720F Super I/O chip w/LPC interface |
18 | 18 | * IT8721F Super I/O chip w/LPC interface |
19 | 19 | * IT8726F Super I/O chip w/LPC interface |
20 | + * IT8728F Super I/O chip w/LPC interface | |
20 | 21 | * IT8758E Super I/O chip w/LPC interface |
21 | 22 | * Sis950 A clone of the IT8705F |
22 | 23 | * |
... | ... | @@ -58,7 +59,7 @@ |
58 | 59 | |
59 | 60 | #define DRVNAME "it87" |
60 | 61 | |
61 | -enum chips { it87, it8712, it8716, it8718, it8720, it8721 }; | |
62 | +enum chips { it87, it8712, it8716, it8718, it8720, it8721, it8728 }; | |
62 | 63 | |
63 | 64 | static unsigned short force_id; |
64 | 65 | module_param(force_id, ushort, 0); |
... | ... | @@ -135,6 +136,7 @@ |
135 | 136 | #define IT8720F_DEVID 0x8720 |
136 | 137 | #define IT8721F_DEVID 0x8721 |
137 | 138 | #define IT8726F_DEVID 0x8726 |
139 | +#define IT8728F_DEVID 0x8728 | |
138 | 140 | #define IT87_ACT_REG 0x30 |
139 | 141 | #define IT87_BASE_REG 0x60 |
140 | 142 | |
141 | 143 | |
... | ... | @@ -274,11 +276,31 @@ |
274 | 276 | s8 auto_temp[3][5]; /* [nr][0] is point1_temp_hyst */ |
275 | 277 | }; |
276 | 278 | |
279 | +static inline int has_12mv_adc(const struct it87_data *data) | |
280 | +{ | |
281 | + /* | |
282 | + * IT8721F and later have a 12 mV ADC, also with internal scaling | |
283 | + * on selected inputs. | |
284 | + */ | |
285 | + return data->type == it8721 | |
286 | + || data->type == it8728; | |
287 | +} | |
288 | + | |
289 | +static inline int has_newer_autopwm(const struct it87_data *data) | |
290 | +{ | |
291 | + /* | |
292 | + * IT8721F and later have separate registers for the temperature | |
293 | + * mapping and the manual duty cycle. | |
294 | + */ | |
295 | + return data->type == it8721 | |
296 | + || data->type == it8728; | |
297 | +} | |
298 | + | |
277 | 299 | static u8 in_to_reg(const struct it87_data *data, int nr, long val) |
278 | 300 | { |
279 | 301 | long lsb; |
280 | 302 | |
281 | - if (data->type == it8721) { | |
303 | + if (has_12mv_adc(data)) { | |
282 | 304 | if (data->in_scaled & (1 << nr)) |
283 | 305 | lsb = 24; |
284 | 306 | else |
... | ... | @@ -292,7 +314,7 @@ |
292 | 314 | |
293 | 315 | static int in_from_reg(const struct it87_data *data, int nr, int val) |
294 | 316 | { |
295 | - if (data->type == it8721) { | |
317 | + if (has_12mv_adc(data)) { | |
296 | 318 | if (data->in_scaled & (1 << nr)) |
297 | 319 | return val * 24; |
298 | 320 | else |
... | ... | @@ -329,7 +351,7 @@ |
329 | 351 | |
330 | 352 | static u8 pwm_to_reg(const struct it87_data *data, long val) |
331 | 353 | { |
332 | - if (data->type == it8721) | |
354 | + if (has_newer_autopwm(data)) | |
333 | 355 | return val; |
334 | 356 | else |
335 | 357 | return val >> 1; |
... | ... | @@ -337,7 +359,7 @@ |
337 | 359 | |
338 | 360 | static int pwm_from_reg(const struct it87_data *data, u8 reg) |
339 | 361 | { |
340 | - if (data->type == it8721) | |
362 | + if (has_newer_autopwm(data)) | |
341 | 363 | return reg; |
342 | 364 | else |
343 | 365 | return (reg & 0x7f) << 1; |
... | ... | @@ -374,7 +396,8 @@ |
374 | 396 | || data->type == it8716 |
375 | 397 | || data->type == it8718 |
376 | 398 | || data->type == it8720 |
377 | - || data->type == it8721; | |
399 | + || data->type == it8721 | |
400 | + || data->type == it8728; | |
378 | 401 | } |
379 | 402 | |
380 | 403 | static inline int has_old_autopwm(const struct it87_data *data) |
... | ... | @@ -842,7 +865,7 @@ |
842 | 865 | data->fan_main_ctrl); |
843 | 866 | } else { |
844 | 867 | if (val == 1) /* Manual mode */ |
845 | - data->pwm_ctrl[nr] = data->type == it8721 ? | |
868 | + data->pwm_ctrl[nr] = has_newer_autopwm(data) ? | |
846 | 869 | data->pwm_temp_map[nr] : |
847 | 870 | data->pwm_duty[nr]; |
848 | 871 | else /* Automatic mode */ |
... | ... | @@ -870,7 +893,7 @@ |
870 | 893 | return -EINVAL; |
871 | 894 | |
872 | 895 | mutex_lock(&data->update_lock); |
873 | - if (data->type == it8721) { | |
896 | + if (has_newer_autopwm(data)) { | |
874 | 897 | /* If we are in automatic mode, the PWM duty cycle register |
875 | 898 | * is read-only so we can't write the value */ |
876 | 899 | if (data->pwm_ctrl[nr] & 0x80) { |
... | ... | @@ -1311,8 +1334,8 @@ |
1311 | 1334 | struct it87_data *data = dev_get_drvdata(dev); |
1312 | 1335 | int nr = to_sensor_dev_attr(attr)->index; |
1313 | 1336 | |
1314 | - return sprintf(buf, "%s\n", data->type == it8721 ? labels_it8721[nr] | |
1315 | - : labels[nr]); | |
1337 | + return sprintf(buf, "%s\n", has_12mv_adc(data) ? labels_it8721[nr] | |
1338 | + : labels[nr]); | |
1316 | 1339 | } |
1317 | 1340 | static SENSOR_DEVICE_ATTR(in3_label, S_IRUGO, show_label, NULL, 0); |
1318 | 1341 | static SENSOR_DEVICE_ATTR(in7_label, S_IRUGO, show_label, NULL, 1); |
... | ... | @@ -1605,6 +1628,9 @@ |
1605 | 1628 | case IT8721F_DEVID: |
1606 | 1629 | sio_data->type = it8721; |
1607 | 1630 | break; |
1631 | + case IT8728F_DEVID: | |
1632 | + sio_data->type = it8728; | |
1633 | + break; | |
1608 | 1634 | case 0xffff: /* No device at all */ |
1609 | 1635 | goto exit; |
1610 | 1636 | default: |
... | ... | @@ -1646,8 +1672,11 @@ |
1646 | 1672 | superio_select(GPIO); |
1647 | 1673 | |
1648 | 1674 | reg = superio_inb(IT87_SIO_GPIO3_REG); |
1649 | - if (sio_data->type == it8721) { | |
1650 | - /* The IT8721F/IT8758E doesn't have VID pins at all */ | |
1675 | + if (sio_data->type == it8721 || sio_data->type == it8728) { | |
1676 | + /* | |
1677 | + * The IT8721F/IT8758E doesn't have VID pins at all, | |
1678 | + * not sure about the IT8728F. | |
1679 | + */ | |
1651 | 1680 | sio_data->skip_vid = 1; |
1652 | 1681 | } else { |
1653 | 1682 | /* We need at least 4 VID pins */ |
... | ... | @@ -1692,7 +1721,8 @@ |
1692 | 1721 | } |
1693 | 1722 | if (reg & (1 << 0)) |
1694 | 1723 | sio_data->internal |= (1 << 0); |
1695 | - if ((reg & (1 << 1)) || sio_data->type == it8721) | |
1724 | + if ((reg & (1 << 1)) || sio_data->type == it8721 || | |
1725 | + sio_data->type == it8728) | |
1696 | 1726 | sio_data->internal |= (1 << 1); |
1697 | 1727 | |
1698 | 1728 | sio_data->beep_pin = superio_inb(IT87_SIO_BEEP_PIN_REG) & 0x3f; |
... | ... | @@ -1770,6 +1800,7 @@ |
1770 | 1800 | "it8718", |
1771 | 1801 | "it8720", |
1772 | 1802 | "it8721", |
1803 | + "it8728", | |
1773 | 1804 | }; |
1774 | 1805 | |
1775 | 1806 | res = platform_get_resource(pdev, IORESOURCE_IO, 0); |
... | ... | @@ -1807,7 +1838,7 @@ |
1807 | 1838 | enable_pwm_interface = it87_check_pwm(dev); |
1808 | 1839 | |
1809 | 1840 | /* Starting with IT8721F, we handle scaling of internal voltages */ |
1810 | - if (data->type == it8721) { | |
1841 | + if (has_12mv_adc(data)) { | |
1811 | 1842 | if (sio_data->internal & (1 << 0)) |
1812 | 1843 | data->in_scaled |= (1 << 3); /* in3 is AVCC */ |
1813 | 1844 | if (sio_data->internal & (1 << 1)) |
... | ... | @@ -2093,7 +2124,7 @@ |
2093 | 2124 | static void it87_update_pwm_ctrl(struct it87_data *data, int nr) |
2094 | 2125 | { |
2095 | 2126 | data->pwm_ctrl[nr] = it87_read_value(data, IT87_REG_PWM(nr)); |
2096 | - if (data->type == it8721) { | |
2127 | + if (has_newer_autopwm(data)) { | |
2097 | 2128 | data->pwm_temp_map[nr] = data->pwm_ctrl[nr] & 0x03; |
2098 | 2129 | data->pwm_duty[nr] = it87_read_value(data, |
2099 | 2130 | IT87_REG_PWM_DUTY(nr)); |
drivers/hwmon/lm63.c
... | ... | @@ -47,10 +47,14 @@ |
47 | 47 | #include <linux/err.h> |
48 | 48 | #include <linux/mutex.h> |
49 | 49 | #include <linux/sysfs.h> |
50 | +#include <linux/types.h> | |
50 | 51 | |
51 | 52 | /* |
52 | 53 | * Addresses to scan |
53 | - * Address is fully defined internally and cannot be changed. | |
54 | + * Address is fully defined internally and cannot be changed except for | |
55 | + * LM64 which has one pin dedicated to address selection. | |
56 | + * LM63 and LM96163 have address 0x4c. | |
57 | + * LM64 can have address 0x18 or 0x4e. | |
54 | 58 | */ |
55 | 59 | |
56 | 60 | static const unsigned short normal_i2c[] = { 0x18, 0x4c, 0x4e, I2C_CLIENT_END }; |
... | ... | @@ -60,6 +64,7 @@ |
60 | 64 | */ |
61 | 65 | |
62 | 66 | #define LM63_REG_CONFIG1 0x03 |
67 | +#define LM63_REG_CONVRATE 0x04 | |
63 | 68 | #define LM63_REG_CONFIG2 0xBF |
64 | 69 | #define LM63_REG_CONFIG_FAN 0x4A |
65 | 70 | |
... | ... | @@ -70,6 +75,9 @@ |
70 | 75 | |
71 | 76 | #define LM63_REG_PWM_VALUE 0x4C |
72 | 77 | #define LM63_REG_PWM_FREQ 0x4D |
78 | +#define LM63_REG_LUT_TEMP_HYST 0x4F | |
79 | +#define LM63_REG_LUT_TEMP(nr) (0x50 + 2 * (nr)) | |
80 | +#define LM63_REG_LUT_PWM(nr) (0x51 + 2 * (nr)) | |
73 | 81 | |
74 | 82 | #define LM63_REG_LOCAL_TEMP 0x00 |
75 | 83 | #define LM63_REG_LOCAL_HIGH 0x05 |
... | ... | @@ -91,6 +99,16 @@ |
91 | 99 | #define LM63_REG_MAN_ID 0xFE |
92 | 100 | #define LM63_REG_CHIP_ID 0xFF |
93 | 101 | |
102 | +#define LM96163_REG_TRUTHERM 0x30 | |
103 | +#define LM96163_REG_REMOTE_TEMP_U_MSB 0x31 | |
104 | +#define LM96163_REG_REMOTE_TEMP_U_LSB 0x32 | |
105 | +#define LM96163_REG_CONFIG_ENHANCED 0x45 | |
106 | + | |
107 | +#define LM63_MAX_CONVRATE 9 | |
108 | + | |
109 | +#define LM63_MAX_CONVRATE_HZ 32 | |
110 | +#define LM96163_MAX_CONVRATE_HZ 26 | |
111 | + | |
94 | 112 | /* |
95 | 113 | * Conversions and various macros |
96 | 114 | * For tachometer counts, the LM63 uses 16-bit values. |
97 | 115 | |
98 | 116 | |
... | ... | @@ -112,15 +130,24 @@ |
112 | 130 | (val) >= 127000 ? 127 : \ |
113 | 131 | (val) < 0 ? ((val) - 500) / 1000 : \ |
114 | 132 | ((val) + 500) / 1000) |
133 | +#define TEMP8U_TO_REG(val) ((val) <= 0 ? 0 : \ | |
134 | + (val) >= 255000 ? 255 : \ | |
135 | + ((val) + 500) / 1000) | |
115 | 136 | #define TEMP11_FROM_REG(reg) ((reg) / 32 * 125) |
116 | 137 | #define TEMP11_TO_REG(val) ((val) <= -128000 ? 0x8000 : \ |
117 | 138 | (val) >= 127875 ? 0x7FE0 : \ |
118 | 139 | (val) < 0 ? ((val) - 62) / 125 * 32 : \ |
119 | 140 | ((val) + 62) / 125 * 32) |
141 | +#define TEMP11U_TO_REG(val) ((val) <= 0 ? 0 : \ | |
142 | + (val) >= 255875 ? 0xFFE0 : \ | |
143 | + ((val) + 62) / 125 * 32) | |
120 | 144 | #define HYST_TO_REG(val) ((val) <= 0 ? 0 : \ |
121 | 145 | (val) >= 127000 ? 127 : \ |
122 | 146 | ((val) + 500) / 1000) |
123 | 147 | |
148 | +#define UPDATE_INTERVAL(max, rate) \ | |
149 | + ((1000 << (LM63_MAX_CONVRATE - (rate))) / (max)) | |
150 | + | |
124 | 151 | /* |
125 | 152 | * Functions declaration |
126 | 153 | */ |
... | ... | @@ -134,7 +161,7 @@ |
134 | 161 | static int lm63_detect(struct i2c_client *client, struct i2c_board_info *info); |
135 | 162 | static void lm63_init_client(struct i2c_client *client); |
136 | 163 | |
137 | -enum chips { lm63, lm64 }; | |
164 | +enum chips { lm63, lm64, lm96163 }; | |
138 | 165 | |
139 | 166 | /* |
140 | 167 | * Driver data (common to all clients) |
... | ... | @@ -143,6 +170,7 @@ |
143 | 170 | static const struct i2c_device_id lm63_id[] = { |
144 | 171 | { "lm63", lm63 }, |
145 | 172 | { "lm64", lm64 }, |
173 | + { "lm96163", lm96163 }, | |
146 | 174 | { } |
147 | 175 | }; |
148 | 176 | MODULE_DEVICE_TABLE(i2c, lm63_id); |
149 | 177 | |
150 | 178 | |
151 | 179 | |
152 | 180 | |
153 | 181 | |
154 | 182 | |
155 | 183 | |
156 | 184 | |
... | ... | @@ -167,26 +195,53 @@ |
167 | 195 | struct device *hwmon_dev; |
168 | 196 | struct mutex update_lock; |
169 | 197 | char valid; /* zero until following fields are valid */ |
198 | + char lut_valid; /* zero until lut fields are valid */ | |
170 | 199 | unsigned long last_updated; /* in jiffies */ |
171 | - int kind; | |
200 | + unsigned long lut_last_updated; /* in jiffies */ | |
201 | + enum chips kind; | |
172 | 202 | int temp2_offset; |
173 | 203 | |
204 | + int update_interval; /* in milliseconds */ | |
205 | + int max_convrate_hz; | |
206 | + int lut_size; /* 8 or 12 */ | |
207 | + | |
174 | 208 | /* registers values */ |
175 | 209 | u8 config, config_fan; |
176 | 210 | u16 fan[2]; /* 0: input |
177 | 211 | 1: low limit */ |
178 | 212 | u8 pwm1_freq; |
179 | - u8 pwm1_value; | |
180 | - s8 temp8[3]; /* 0: local input | |
213 | + u8 pwm1[13]; /* 0: current output | |
214 | + 1-12: lookup table */ | |
215 | + s8 temp8[15]; /* 0: local input | |
181 | 216 | 1: local high limit |
182 | - 2: remote critical limit */ | |
183 | - s16 temp11[3]; /* 0: remote input | |
217 | + 2: remote critical limit | |
218 | + 3-14: lookup table */ | |
219 | + s16 temp11[4]; /* 0: remote input | |
184 | 220 | 1: remote low limit |
185 | - 2: remote high limit */ | |
221 | + 2: remote high limit | |
222 | + 3: remote offset */ | |
223 | + u16 temp11u; /* remote input (unsigned) */ | |
186 | 224 | u8 temp2_crit_hyst; |
225 | + u8 lut_temp_hyst; | |
187 | 226 | u8 alarms; |
227 | + bool pwm_highres; | |
228 | + bool lut_temp_highres; | |
229 | + bool remote_unsigned; /* true if unsigned remote upper limits */ | |
230 | + bool trutherm; | |
188 | 231 | }; |
189 | 232 | |
233 | +static inline int temp8_from_reg(struct lm63_data *data, int nr) | |
234 | +{ | |
235 | + if (data->remote_unsigned) | |
236 | + return TEMP8_FROM_REG((u8)data->temp8[nr]); | |
237 | + return TEMP8_FROM_REG(data->temp8[nr]); | |
238 | +} | |
239 | + | |
240 | +static inline int lut_temp_from_reg(struct lm63_data *data, int nr) | |
241 | +{ | |
242 | + return data->temp8[nr] * (data->lut_temp_highres ? 500 : 1000); | |
243 | +} | |
244 | + | |
190 | 245 | /* |
191 | 246 | * Sysfs callback functions and files |
192 | 247 | */ |
193 | 248 | |
... | ... | @@ -204,8 +259,13 @@ |
204 | 259 | { |
205 | 260 | struct i2c_client *client = to_i2c_client(dev); |
206 | 261 | struct lm63_data *data = i2c_get_clientdata(client); |
207 | - unsigned long val = simple_strtoul(buf, NULL, 10); | |
262 | + unsigned long val; | |
263 | + int err; | |
208 | 264 | |
265 | + err = kstrtoul(buf, 10, &val); | |
266 | + if (err) | |
267 | + return err; | |
268 | + | |
209 | 269 | mutex_lock(&data->update_lock); |
210 | 270 | data->fan[1] = FAN_TO_REG(val); |
211 | 271 | i2c_smbus_write_byte_data(client, LM63_REG_TACH_LIMIT_LSB, |
212 | 272 | |
213 | 273 | |
... | ... | @@ -216,13 +276,22 @@ |
216 | 276 | return count; |
217 | 277 | } |
218 | 278 | |
219 | -static ssize_t show_pwm1(struct device *dev, struct device_attribute *dummy, | |
279 | +static ssize_t show_pwm1(struct device *dev, struct device_attribute *devattr, | |
220 | 280 | char *buf) |
221 | 281 | { |
282 | + struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); | |
222 | 283 | struct lm63_data *data = lm63_update_device(dev); |
223 | - return sprintf(buf, "%d\n", data->pwm1_value >= 2 * data->pwm1_freq ? | |
224 | - 255 : (data->pwm1_value * 255 + data->pwm1_freq) / | |
225 | - (2 * data->pwm1_freq)); | |
284 | + int nr = attr->index; | |
285 | + int pwm; | |
286 | + | |
287 | + if (data->pwm_highres) | |
288 | + pwm = data->pwm1[nr]; | |
289 | + else | |
290 | + pwm = data->pwm1[nr] >= 2 * data->pwm1_freq ? | |
291 | + 255 : (data->pwm1[nr] * 255 + data->pwm1_freq) / | |
292 | + (2 * data->pwm1_freq); | |
293 | + | |
294 | + return sprintf(buf, "%d\n", pwm); | |
226 | 295 | } |
227 | 296 | |
228 | 297 | static ssize_t set_pwm1(struct device *dev, struct device_attribute *dummy, |
229 | 298 | |
230 | 299 | |
231 | 300 | |
... | ... | @@ -231,22 +300,26 @@ |
231 | 300 | struct i2c_client *client = to_i2c_client(dev); |
232 | 301 | struct lm63_data *data = i2c_get_clientdata(client); |
233 | 302 | unsigned long val; |
234 | - | |
303 | + int err; | |
304 | + | |
235 | 305 | if (!(data->config_fan & 0x20)) /* register is read-only */ |
236 | 306 | return -EPERM; |
237 | 307 | |
238 | - val = simple_strtoul(buf, NULL, 10); | |
308 | + err = kstrtoul(buf, 10, &val); | |
309 | + if (err) | |
310 | + return err; | |
311 | + | |
312 | + val = SENSORS_LIMIT(val, 0, 255); | |
239 | 313 | mutex_lock(&data->update_lock); |
240 | - data->pwm1_value = val <= 0 ? 0 : | |
241 | - val >= 255 ? 2 * data->pwm1_freq : | |
242 | - (val * data->pwm1_freq * 2 + 127) / 255; | |
243 | - i2c_smbus_write_byte_data(client, LM63_REG_PWM_VALUE, data->pwm1_value); | |
314 | + data->pwm1[0] = data->pwm_highres ? val : | |
315 | + (val * data->pwm1_freq * 2 + 127) / 255; | |
316 | + i2c_smbus_write_byte_data(client, LM63_REG_PWM_VALUE, data->pwm1[0]); | |
244 | 317 | mutex_unlock(&data->update_lock); |
245 | 318 | return count; |
246 | 319 | } |
247 | 320 | |
248 | -static ssize_t show_pwm1_enable(struct device *dev, struct device_attribute *dummy, | |
249 | - char *buf) | |
321 | +static ssize_t show_pwm1_enable(struct device *dev, | |
322 | + struct device_attribute *dummy, char *buf) | |
250 | 323 | { |
251 | 324 | struct lm63_data *data = lm63_update_device(dev); |
252 | 325 | return sprintf(buf, "%d\n", data->config_fan & 0x20 ? 1 : 2); |
253 | 326 | |
254 | 327 | |
255 | 328 | |
256 | 329 | |
257 | 330 | |
... | ... | @@ -273,21 +346,47 @@ |
273 | 346 | { |
274 | 347 | struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); |
275 | 348 | struct lm63_data *data = lm63_update_device(dev); |
276 | - return sprintf(buf, "%d\n", TEMP8_FROM_REG(data->temp8[attr->index]) | |
349 | + return sprintf(buf, "%d\n", temp8_from_reg(data, attr->index) | |
277 | 350 | + data->temp2_offset); |
278 | 351 | } |
279 | 352 | |
280 | -static ssize_t set_local_temp8(struct device *dev, | |
281 | - struct device_attribute *dummy, | |
282 | - const char *buf, size_t count) | |
353 | +static ssize_t show_lut_temp(struct device *dev, | |
354 | + struct device_attribute *devattr, | |
355 | + char *buf) | |
283 | 356 | { |
357 | + struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); | |
358 | + struct lm63_data *data = lm63_update_device(dev); | |
359 | + return sprintf(buf, "%d\n", lut_temp_from_reg(data, attr->index) | |
360 | + + data->temp2_offset); | |
361 | +} | |
362 | + | |
363 | +static ssize_t set_temp8(struct device *dev, struct device_attribute *devattr, | |
364 | + const char *buf, size_t count) | |
365 | +{ | |
366 | + struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); | |
284 | 367 | struct i2c_client *client = to_i2c_client(dev); |
285 | 368 | struct lm63_data *data = i2c_get_clientdata(client); |
286 | - long val = simple_strtol(buf, NULL, 10); | |
369 | + int nr = attr->index; | |
370 | + int reg = nr == 2 ? LM63_REG_REMOTE_TCRIT : LM63_REG_LOCAL_HIGH; | |
371 | + long val; | |
372 | + int err; | |
373 | + int temp; | |
287 | 374 | |
375 | + err = kstrtol(buf, 10, &val); | |
376 | + if (err) | |
377 | + return err; | |
378 | + | |
288 | 379 | mutex_lock(&data->update_lock); |
289 | - data->temp8[1] = TEMP8_TO_REG(val); | |
290 | - i2c_smbus_write_byte_data(client, LM63_REG_LOCAL_HIGH, data->temp8[1]); | |
380 | + if (nr == 2) { | |
381 | + if (data->remote_unsigned) | |
382 | + temp = TEMP8U_TO_REG(val - data->temp2_offset); | |
383 | + else | |
384 | + temp = TEMP8_TO_REG(val - data->temp2_offset); | |
385 | + } else { | |
386 | + temp = TEMP8_TO_REG(val); | |
387 | + } | |
388 | + data->temp8[nr] = temp; | |
389 | + i2c_smbus_write_byte_data(client, reg, temp); | |
291 | 390 | mutex_unlock(&data->update_lock); |
292 | 391 | return count; |
293 | 392 | } |
294 | 393 | |
295 | 394 | |
296 | 395 | |
297 | 396 | |
298 | 397 | |
... | ... | @@ -297,28 +396,56 @@ |
297 | 396 | { |
298 | 397 | struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); |
299 | 398 | struct lm63_data *data = lm63_update_device(dev); |
300 | - return sprintf(buf, "%d\n", TEMP11_FROM_REG(data->temp11[attr->index]) | |
301 | - + data->temp2_offset); | |
399 | + int nr = attr->index; | |
400 | + int temp; | |
401 | + | |
402 | + if (!nr) { | |
403 | + /* | |
404 | + * Use unsigned temperature unless its value is zero. | |
405 | + * If it is zero, use signed temperature. | |
406 | + */ | |
407 | + if (data->temp11u) | |
408 | + temp = TEMP11_FROM_REG(data->temp11u); | |
409 | + else | |
410 | + temp = TEMP11_FROM_REG(data->temp11[nr]); | |
411 | + } else { | |
412 | + if (data->remote_unsigned && nr == 2) | |
413 | + temp = TEMP11_FROM_REG((u16)data->temp11[nr]); | |
414 | + else | |
415 | + temp = TEMP11_FROM_REG(data->temp11[nr]); | |
416 | + } | |
417 | + return sprintf(buf, "%d\n", temp + data->temp2_offset); | |
302 | 418 | } |
303 | 419 | |
304 | 420 | static ssize_t set_temp11(struct device *dev, struct device_attribute *devattr, |
305 | 421 | const char *buf, size_t count) |
306 | 422 | { |
307 | - static const u8 reg[4] = { | |
423 | + static const u8 reg[6] = { | |
308 | 424 | LM63_REG_REMOTE_LOW_MSB, |
309 | 425 | LM63_REG_REMOTE_LOW_LSB, |
310 | 426 | LM63_REG_REMOTE_HIGH_MSB, |
311 | 427 | LM63_REG_REMOTE_HIGH_LSB, |
428 | + LM63_REG_REMOTE_OFFSET_MSB, | |
429 | + LM63_REG_REMOTE_OFFSET_LSB, | |
312 | 430 | }; |
313 | 431 | |
314 | 432 | struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); |
315 | 433 | struct i2c_client *client = to_i2c_client(dev); |
316 | 434 | struct lm63_data *data = i2c_get_clientdata(client); |
317 | - long val = simple_strtol(buf, NULL, 10); | |
435 | + long val; | |
436 | + int err; | |
318 | 437 | int nr = attr->index; |
319 | 438 | |
439 | + err = kstrtol(buf, 10, &val); | |
440 | + if (err) | |
441 | + return err; | |
442 | + | |
320 | 443 | mutex_lock(&data->update_lock); |
321 | - data->temp11[nr] = TEMP11_TO_REG(val - data->temp2_offset); | |
444 | + if (data->remote_unsigned && nr == 2) | |
445 | + data->temp11[nr] = TEMP11U_TO_REG(val - data->temp2_offset); | |
446 | + else | |
447 | + data->temp11[nr] = TEMP11_TO_REG(val - data->temp2_offset); | |
448 | + | |
322 | 449 | i2c_smbus_write_byte_data(client, reg[(nr - 1) * 2], |
323 | 450 | data->temp11[nr] >> 8); |
324 | 451 | i2c_smbus_write_byte_data(client, reg[(nr - 1) * 2 + 1], |
325 | 452 | |
326 | 453 | |
327 | 454 | |
328 | 455 | |
329 | 456 | |
330 | 457 | |
... | ... | @@ -327,35 +454,143 @@ |
327 | 454 | return count; |
328 | 455 | } |
329 | 456 | |
330 | -/* Hysteresis register holds a relative value, while we want to present | |
331 | - an absolute to user-space */ | |
332 | -static ssize_t show_temp2_crit_hyst(struct device *dev, struct device_attribute *dummy, | |
333 | - char *buf) | |
457 | +/* | |
458 | + * Hysteresis register holds a relative value, while we want to present | |
459 | + * an absolute to user-space | |
460 | + */ | |
461 | +static ssize_t show_temp2_crit_hyst(struct device *dev, | |
462 | + struct device_attribute *dummy, char *buf) | |
334 | 463 | { |
335 | 464 | struct lm63_data *data = lm63_update_device(dev); |
336 | - return sprintf(buf, "%d\n", TEMP8_FROM_REG(data->temp8[2]) | |
465 | + return sprintf(buf, "%d\n", temp8_from_reg(data, 2) | |
337 | 466 | + data->temp2_offset |
338 | 467 | - TEMP8_FROM_REG(data->temp2_crit_hyst)); |
339 | 468 | } |
340 | 469 | |
341 | -/* And now the other way around, user-space provides an absolute | |
342 | - hysteresis value and we have to store a relative one */ | |
343 | -static ssize_t set_temp2_crit_hyst(struct device *dev, struct device_attribute *dummy, | |
470 | +static ssize_t show_lut_temp_hyst(struct device *dev, | |
471 | + struct device_attribute *devattr, char *buf) | |
472 | +{ | |
473 | + struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); | |
474 | + struct lm63_data *data = lm63_update_device(dev); | |
475 | + | |
476 | + return sprintf(buf, "%d\n", lut_temp_from_reg(data, attr->index) | |
477 | + + data->temp2_offset | |
478 | + - TEMP8_FROM_REG(data->lut_temp_hyst)); | |
479 | +} | |
480 | + | |
481 | +/* | |
482 | + * And now the other way around, user-space provides an absolute | |
483 | + * hysteresis value and we have to store a relative one | |
484 | + */ | |
485 | +static ssize_t set_temp2_crit_hyst(struct device *dev, | |
486 | + struct device_attribute *dummy, | |
344 | 487 | const char *buf, size_t count) |
345 | 488 | { |
346 | 489 | struct i2c_client *client = to_i2c_client(dev); |
347 | 490 | struct lm63_data *data = i2c_get_clientdata(client); |
348 | - long val = simple_strtol(buf, NULL, 10); | |
491 | + long val; | |
492 | + int err; | |
349 | 493 | long hyst; |
350 | 494 | |
495 | + err = kstrtol(buf, 10, &val); | |
496 | + if (err) | |
497 | + return err; | |
498 | + | |
351 | 499 | mutex_lock(&data->update_lock); |
352 | - hyst = TEMP8_FROM_REG(data->temp8[2]) + data->temp2_offset - val; | |
500 | + hyst = temp8_from_reg(data, 2) + data->temp2_offset - val; | |
353 | 501 | i2c_smbus_write_byte_data(client, LM63_REG_REMOTE_TCRIT_HYST, |
354 | 502 | HYST_TO_REG(hyst)); |
355 | 503 | mutex_unlock(&data->update_lock); |
356 | 504 | return count; |
357 | 505 | } |
358 | 506 | |
507 | +/* | |
508 | + * Set conversion rate. | |
509 | + * client->update_lock must be held when calling this function. | |
510 | + */ | |
511 | +static void lm63_set_convrate(struct i2c_client *client, struct lm63_data *data, | |
512 | + unsigned int interval) | |
513 | +{ | |
514 | + int i; | |
515 | + unsigned int update_interval; | |
516 | + | |
517 | + /* Shift calculations to avoid rounding errors */ | |
518 | + interval <<= 6; | |
519 | + | |
520 | + /* find the nearest update rate */ | |
521 | + update_interval = (1 << (LM63_MAX_CONVRATE + 6)) * 1000 | |
522 | + / data->max_convrate_hz; | |
523 | + for (i = 0; i < LM63_MAX_CONVRATE; i++, update_interval >>= 1) | |
524 | + if (interval >= update_interval * 3 / 4) | |
525 | + break; | |
526 | + | |
527 | + i2c_smbus_write_byte_data(client, LM63_REG_CONVRATE, i); | |
528 | + data->update_interval = UPDATE_INTERVAL(data->max_convrate_hz, i); | |
529 | +} | |
530 | + | |
531 | +static ssize_t show_update_interval(struct device *dev, | |
532 | + struct device_attribute *attr, char *buf) | |
533 | +{ | |
534 | + struct lm63_data *data = dev_get_drvdata(dev); | |
535 | + | |
536 | + return sprintf(buf, "%u\n", data->update_interval); | |
537 | +} | |
538 | + | |
539 | +static ssize_t set_update_interval(struct device *dev, | |
540 | + struct device_attribute *attr, | |
541 | + const char *buf, size_t count) | |
542 | +{ | |
543 | + struct i2c_client *client = to_i2c_client(dev); | |
544 | + struct lm63_data *data = i2c_get_clientdata(client); | |
545 | + unsigned long val; | |
546 | + int err; | |
547 | + | |
548 | + err = kstrtoul(buf, 10, &val); | |
549 | + if (err) | |
550 | + return err; | |
551 | + | |
552 | + mutex_lock(&data->update_lock); | |
553 | + lm63_set_convrate(client, data, SENSORS_LIMIT(val, 0, 100000)); | |
554 | + mutex_unlock(&data->update_lock); | |
555 | + | |
556 | + return count; | |
557 | +} | |
558 | + | |
559 | +static ssize_t show_type(struct device *dev, struct device_attribute *attr, | |
560 | + char *buf) | |
561 | +{ | |
562 | + struct i2c_client *client = to_i2c_client(dev); | |
563 | + struct lm63_data *data = i2c_get_clientdata(client); | |
564 | + | |
565 | + return sprintf(buf, data->trutherm ? "1\n" : "2\n"); | |
566 | +} | |
567 | + | |
568 | +static ssize_t set_type(struct device *dev, struct device_attribute *attr, | |
569 | + const char *buf, size_t count) | |
570 | +{ | |
571 | + struct i2c_client *client = to_i2c_client(dev); | |
572 | + struct lm63_data *data = i2c_get_clientdata(client); | |
573 | + unsigned long val; | |
574 | + int ret; | |
575 | + u8 reg; | |
576 | + | |
577 | + ret = kstrtoul(buf, 10, &val); | |
578 | + if (ret < 0) | |
579 | + return ret; | |
580 | + if (val != 1 && val != 2) | |
581 | + return -EINVAL; | |
582 | + | |
583 | + mutex_lock(&data->update_lock); | |
584 | + data->trutherm = val == 1; | |
585 | + reg = i2c_smbus_read_byte_data(client, LM96163_REG_TRUTHERM) & ~0x02; | |
586 | + i2c_smbus_write_byte_data(client, LM96163_REG_TRUTHERM, | |
587 | + reg | (data->trutherm ? 0x02 : 0x00)); | |
588 | + data->valid = 0; | |
589 | + mutex_unlock(&data->update_lock); | |
590 | + | |
591 | + return count; | |
592 | +} | |
593 | + | |
359 | 594 | static ssize_t show_alarms(struct device *dev, struct device_attribute *dummy, |
360 | 595 | char *buf) |
361 | 596 | { |
362 | 597 | |
363 | 598 | |
364 | 599 | |
365 | 600 | |
366 | 601 | |
... | ... | @@ -377,27 +612,87 @@ |
377 | 612 | static SENSOR_DEVICE_ATTR(fan1_min, S_IWUSR | S_IRUGO, show_fan, |
378 | 613 | set_fan, 1); |
379 | 614 | |
380 | -static DEVICE_ATTR(pwm1, S_IWUSR | S_IRUGO, show_pwm1, set_pwm1); | |
615 | +static SENSOR_DEVICE_ATTR(pwm1, S_IWUSR | S_IRUGO, show_pwm1, set_pwm1, 0); | |
381 | 616 | static DEVICE_ATTR(pwm1_enable, S_IRUGO, show_pwm1_enable, NULL); |
617 | +static SENSOR_DEVICE_ATTR(pwm1_auto_point1_pwm, S_IRUGO, show_pwm1, NULL, 1); | |
618 | +static SENSOR_DEVICE_ATTR(pwm1_auto_point1_temp, S_IRUGO, | |
619 | + show_lut_temp, NULL, 3); | |
620 | +static SENSOR_DEVICE_ATTR(pwm1_auto_point1_temp_hyst, S_IRUGO, | |
621 | + show_lut_temp_hyst, NULL, 3); | |
622 | +static SENSOR_DEVICE_ATTR(pwm1_auto_point2_pwm, S_IRUGO, show_pwm1, NULL, 2); | |
623 | +static SENSOR_DEVICE_ATTR(pwm1_auto_point2_temp, S_IRUGO, | |
624 | + show_lut_temp, NULL, 4); | |
625 | +static SENSOR_DEVICE_ATTR(pwm1_auto_point2_temp_hyst, S_IRUGO, | |
626 | + show_lut_temp_hyst, NULL, 4); | |
627 | +static SENSOR_DEVICE_ATTR(pwm1_auto_point3_pwm, S_IRUGO, show_pwm1, NULL, 3); | |
628 | +static SENSOR_DEVICE_ATTR(pwm1_auto_point3_temp, S_IRUGO, | |
629 | + show_lut_temp, NULL, 5); | |
630 | +static SENSOR_DEVICE_ATTR(pwm1_auto_point3_temp_hyst, S_IRUGO, | |
631 | + show_lut_temp_hyst, NULL, 5); | |
632 | +static SENSOR_DEVICE_ATTR(pwm1_auto_point4_pwm, S_IRUGO, show_pwm1, NULL, 4); | |
633 | +static SENSOR_DEVICE_ATTR(pwm1_auto_point4_temp, S_IRUGO, | |
634 | + show_lut_temp, NULL, 6); | |
635 | +static SENSOR_DEVICE_ATTR(pwm1_auto_point4_temp_hyst, S_IRUGO, | |
636 | + show_lut_temp_hyst, NULL, 6); | |
637 | +static SENSOR_DEVICE_ATTR(pwm1_auto_point5_pwm, S_IRUGO, show_pwm1, NULL, 5); | |
638 | +static SENSOR_DEVICE_ATTR(pwm1_auto_point5_temp, S_IRUGO, | |
639 | + show_lut_temp, NULL, 7); | |
640 | +static SENSOR_DEVICE_ATTR(pwm1_auto_point5_temp_hyst, S_IRUGO, | |
641 | + show_lut_temp_hyst, NULL, 7); | |
642 | +static SENSOR_DEVICE_ATTR(pwm1_auto_point6_pwm, S_IRUGO, show_pwm1, NULL, 6); | |
643 | +static SENSOR_DEVICE_ATTR(pwm1_auto_point6_temp, S_IRUGO, | |
644 | + show_lut_temp, NULL, 8); | |
645 | +static SENSOR_DEVICE_ATTR(pwm1_auto_point6_temp_hyst, S_IRUGO, | |
646 | + show_lut_temp_hyst, NULL, 8); | |
647 | +static SENSOR_DEVICE_ATTR(pwm1_auto_point7_pwm, S_IRUGO, show_pwm1, NULL, 7); | |
648 | +static SENSOR_DEVICE_ATTR(pwm1_auto_point7_temp, S_IRUGO, | |
649 | + show_lut_temp, NULL, 9); | |
650 | +static SENSOR_DEVICE_ATTR(pwm1_auto_point7_temp_hyst, S_IRUGO, | |
651 | + show_lut_temp_hyst, NULL, 9); | |
652 | +static SENSOR_DEVICE_ATTR(pwm1_auto_point8_pwm, S_IRUGO, show_pwm1, NULL, 8); | |
653 | +static SENSOR_DEVICE_ATTR(pwm1_auto_point8_temp, S_IRUGO, | |
654 | + show_lut_temp, NULL, 10); | |
655 | +static SENSOR_DEVICE_ATTR(pwm1_auto_point8_temp_hyst, S_IRUGO, | |
656 | + show_lut_temp_hyst, NULL, 10); | |
657 | +static SENSOR_DEVICE_ATTR(pwm1_auto_point9_pwm, S_IRUGO, show_pwm1, NULL, 9); | |
658 | +static SENSOR_DEVICE_ATTR(pwm1_auto_point9_temp, S_IRUGO, | |
659 | + show_lut_temp, NULL, 11); | |
660 | +static SENSOR_DEVICE_ATTR(pwm1_auto_point9_temp_hyst, S_IRUGO, | |
661 | + show_lut_temp_hyst, NULL, 11); | |
662 | +static SENSOR_DEVICE_ATTR(pwm1_auto_point10_pwm, S_IRUGO, show_pwm1, NULL, 10); | |
663 | +static SENSOR_DEVICE_ATTR(pwm1_auto_point10_temp, S_IRUGO, | |
664 | + show_lut_temp, NULL, 12); | |
665 | +static SENSOR_DEVICE_ATTR(pwm1_auto_point10_temp_hyst, S_IRUGO, | |
666 | + show_lut_temp_hyst, NULL, 12); | |
667 | +static SENSOR_DEVICE_ATTR(pwm1_auto_point11_pwm, S_IRUGO, show_pwm1, NULL, 11); | |
668 | +static SENSOR_DEVICE_ATTR(pwm1_auto_point11_temp, S_IRUGO, | |
669 | + show_lut_temp, NULL, 13); | |
670 | +static SENSOR_DEVICE_ATTR(pwm1_auto_point11_temp_hyst, S_IRUGO, | |
671 | + show_lut_temp_hyst, NULL, 13); | |
672 | +static SENSOR_DEVICE_ATTR(pwm1_auto_point12_pwm, S_IRUGO, show_pwm1, NULL, 12); | |
673 | +static SENSOR_DEVICE_ATTR(pwm1_auto_point12_temp, S_IRUGO, | |
674 | + show_lut_temp, NULL, 14); | |
675 | +static SENSOR_DEVICE_ATTR(pwm1_auto_point12_temp_hyst, S_IRUGO, | |
676 | + show_lut_temp_hyst, NULL, 14); | |
382 | 677 | |
383 | 678 | static SENSOR_DEVICE_ATTR(temp1_input, S_IRUGO, show_local_temp8, NULL, 0); |
384 | 679 | static SENSOR_DEVICE_ATTR(temp1_max, S_IWUSR | S_IRUGO, show_local_temp8, |
385 | - set_local_temp8, 1); | |
680 | + set_temp8, 1); | |
386 | 681 | |
387 | 682 | static SENSOR_DEVICE_ATTR(temp2_input, S_IRUGO, show_temp11, NULL, 0); |
388 | 683 | static SENSOR_DEVICE_ATTR(temp2_min, S_IWUSR | S_IRUGO, show_temp11, |
389 | 684 | set_temp11, 1); |
390 | 685 | static SENSOR_DEVICE_ATTR(temp2_max, S_IWUSR | S_IRUGO, show_temp11, |
391 | 686 | set_temp11, 2); |
392 | -/* | |
393 | - * On LM63, temp2_crit can be set only once, which should be job | |
394 | - * of the bootloader. | |
395 | - */ | |
687 | +static SENSOR_DEVICE_ATTR(temp2_offset, S_IWUSR | S_IRUGO, show_temp11, | |
688 | + set_temp11, 3); | |
396 | 689 | static SENSOR_DEVICE_ATTR(temp2_crit, S_IRUGO, show_remote_temp8, |
397 | - NULL, 2); | |
690 | + set_temp8, 2); | |
398 | 691 | static DEVICE_ATTR(temp2_crit_hyst, S_IWUSR | S_IRUGO, show_temp2_crit_hyst, |
399 | 692 | set_temp2_crit_hyst); |
400 | 693 | |
694 | +static DEVICE_ATTR(temp2_type, S_IWUSR | S_IRUGO, show_type, set_type); | |
695 | + | |
401 | 696 | /* Individual alarm files */ |
402 | 697 | static SENSOR_DEVICE_ATTR(fan1_min_alarm, S_IRUGO, show_alarm, NULL, 0); |
403 | 698 | static SENSOR_DEVICE_ATTR(temp2_crit_alarm, S_IRUGO, show_alarm, NULL, 1); |
404 | 699 | |
405 | 700 | |
406 | 701 | |
... | ... | @@ -408,14 +703,43 @@ |
408 | 703 | /* Raw alarm file for compatibility */ |
409 | 704 | static DEVICE_ATTR(alarms, S_IRUGO, show_alarms, NULL); |
410 | 705 | |
706 | +static DEVICE_ATTR(update_interval, S_IRUGO | S_IWUSR, show_update_interval, | |
707 | + set_update_interval); | |
708 | + | |
411 | 709 | static struct attribute *lm63_attributes[] = { |
412 | - &dev_attr_pwm1.attr, | |
710 | + &sensor_dev_attr_pwm1.dev_attr.attr, | |
413 | 711 | &dev_attr_pwm1_enable.attr, |
712 | + &sensor_dev_attr_pwm1_auto_point1_pwm.dev_attr.attr, | |
713 | + &sensor_dev_attr_pwm1_auto_point1_temp.dev_attr.attr, | |
714 | + &sensor_dev_attr_pwm1_auto_point1_temp_hyst.dev_attr.attr, | |
715 | + &sensor_dev_attr_pwm1_auto_point2_pwm.dev_attr.attr, | |
716 | + &sensor_dev_attr_pwm1_auto_point2_temp.dev_attr.attr, | |
717 | + &sensor_dev_attr_pwm1_auto_point2_temp_hyst.dev_attr.attr, | |
718 | + &sensor_dev_attr_pwm1_auto_point3_pwm.dev_attr.attr, | |
719 | + &sensor_dev_attr_pwm1_auto_point3_temp.dev_attr.attr, | |
720 | + &sensor_dev_attr_pwm1_auto_point3_temp_hyst.dev_attr.attr, | |
721 | + &sensor_dev_attr_pwm1_auto_point4_pwm.dev_attr.attr, | |
722 | + &sensor_dev_attr_pwm1_auto_point4_temp.dev_attr.attr, | |
723 | + &sensor_dev_attr_pwm1_auto_point4_temp_hyst.dev_attr.attr, | |
724 | + &sensor_dev_attr_pwm1_auto_point5_pwm.dev_attr.attr, | |
725 | + &sensor_dev_attr_pwm1_auto_point5_temp.dev_attr.attr, | |
726 | + &sensor_dev_attr_pwm1_auto_point5_temp_hyst.dev_attr.attr, | |
727 | + &sensor_dev_attr_pwm1_auto_point6_pwm.dev_attr.attr, | |
728 | + &sensor_dev_attr_pwm1_auto_point6_temp.dev_attr.attr, | |
729 | + &sensor_dev_attr_pwm1_auto_point6_temp_hyst.dev_attr.attr, | |
730 | + &sensor_dev_attr_pwm1_auto_point7_pwm.dev_attr.attr, | |
731 | + &sensor_dev_attr_pwm1_auto_point7_temp.dev_attr.attr, | |
732 | + &sensor_dev_attr_pwm1_auto_point7_temp_hyst.dev_attr.attr, | |
733 | + &sensor_dev_attr_pwm1_auto_point8_pwm.dev_attr.attr, | |
734 | + &sensor_dev_attr_pwm1_auto_point8_temp.dev_attr.attr, | |
735 | + &sensor_dev_attr_pwm1_auto_point8_temp_hyst.dev_attr.attr, | |
736 | + | |
414 | 737 | &sensor_dev_attr_temp1_input.dev_attr.attr, |
415 | 738 | &sensor_dev_attr_temp2_input.dev_attr.attr, |
416 | 739 | &sensor_dev_attr_temp2_min.dev_attr.attr, |
417 | 740 | &sensor_dev_attr_temp1_max.dev_attr.attr, |
418 | 741 | &sensor_dev_attr_temp2_max.dev_attr.attr, |
742 | + &sensor_dev_attr_temp2_offset.dev_attr.attr, | |
419 | 743 | &sensor_dev_attr_temp2_crit.dev_attr.attr, |
420 | 744 | &dev_attr_temp2_crit_hyst.attr, |
421 | 745 | |
422 | 746 | |
423 | 747 | |
... | ... | @@ -425,10 +749,54 @@ |
425 | 749 | &sensor_dev_attr_temp2_max_alarm.dev_attr.attr, |
426 | 750 | &sensor_dev_attr_temp1_max_alarm.dev_attr.attr, |
427 | 751 | &dev_attr_alarms.attr, |
752 | + &dev_attr_update_interval.attr, | |
428 | 753 | NULL |
429 | 754 | }; |
430 | 755 | |
756 | +static struct attribute *lm63_attributes_extra_lut[] = { | |
757 | + &sensor_dev_attr_pwm1_auto_point9_pwm.dev_attr.attr, | |
758 | + &sensor_dev_attr_pwm1_auto_point9_temp.dev_attr.attr, | |
759 | + &sensor_dev_attr_pwm1_auto_point9_temp_hyst.dev_attr.attr, | |
760 | + &sensor_dev_attr_pwm1_auto_point10_pwm.dev_attr.attr, | |
761 | + &sensor_dev_attr_pwm1_auto_point10_temp.dev_attr.attr, | |
762 | + &sensor_dev_attr_pwm1_auto_point10_temp_hyst.dev_attr.attr, | |
763 | + &sensor_dev_attr_pwm1_auto_point11_pwm.dev_attr.attr, | |
764 | + &sensor_dev_attr_pwm1_auto_point11_temp.dev_attr.attr, | |
765 | + &sensor_dev_attr_pwm1_auto_point11_temp_hyst.dev_attr.attr, | |
766 | + &sensor_dev_attr_pwm1_auto_point12_pwm.dev_attr.attr, | |
767 | + &sensor_dev_attr_pwm1_auto_point12_temp.dev_attr.attr, | |
768 | + &sensor_dev_attr_pwm1_auto_point12_temp_hyst.dev_attr.attr, | |
769 | + NULL | |
770 | +}; | |
771 | + | |
772 | +static const struct attribute_group lm63_group_extra_lut = { | |
773 | + .attrs = lm63_attributes_extra_lut, | |
774 | +}; | |
775 | + | |
776 | +/* | |
777 | + * On LM63, temp2_crit can be set only once, which should be job | |
778 | + * of the bootloader. | |
779 | + * On LM64, temp2_crit can always be set. | |
780 | + * On LM96163, temp2_crit can be set if bit 1 of the configuration | |
781 | + * register is true. | |
782 | + */ | |
783 | +static umode_t lm63_attribute_mode(struct kobject *kobj, | |
784 | + struct attribute *attr, int index) | |
785 | +{ | |
786 | + struct device *dev = container_of(kobj, struct device, kobj); | |
787 | + struct i2c_client *client = to_i2c_client(dev); | |
788 | + struct lm63_data *data = i2c_get_clientdata(client); | |
789 | + | |
790 | + if (attr == &sensor_dev_attr_temp2_crit.dev_attr.attr | |
791 | + && (data->kind == lm64 || | |
792 | + (data->kind == lm96163 && (data->config & 0x02)))) | |
793 | + return attr->mode | S_IWUSR; | |
794 | + | |
795 | + return attr->mode; | |
796 | +} | |
797 | + | |
431 | 798 | static const struct attribute_group lm63_group = { |
799 | + .is_visible = lm63_attribute_mode, | |
432 | 800 | .attrs = lm63_attributes, |
433 | 801 | }; |
434 | 802 | |
... | ... | @@ -487,6 +855,8 @@ |
487 | 855 | strlcpy(info->type, "lm63", I2C_NAME_SIZE); |
488 | 856 | else if (chip_id == 0x51 && (address == 0x18 || address == 0x4e)) |
489 | 857 | strlcpy(info->type, "lm64", I2C_NAME_SIZE); |
858 | + else if (chip_id == 0x49 && address == 0x4c) | |
859 | + strlcpy(info->type, "lm96163", I2C_NAME_SIZE); | |
490 | 860 | else |
491 | 861 | return -ENODEV; |
492 | 862 | |
493 | 863 | |
494 | 864 | |
495 | 865 | |
... | ... | @@ -518,15 +888,27 @@ |
518 | 888 | lm63_init_client(new_client); |
519 | 889 | |
520 | 890 | /* Register sysfs hooks */ |
521 | - if ((err = sysfs_create_group(&new_client->dev.kobj, | |
522 | - &lm63_group))) | |
891 | + err = sysfs_create_group(&new_client->dev.kobj, &lm63_group); | |
892 | + if (err) | |
523 | 893 | goto exit_free; |
524 | 894 | if (data->config & 0x04) { /* tachometer enabled */ |
525 | - if ((err = sysfs_create_group(&new_client->dev.kobj, | |
526 | - &lm63_group_fan1))) | |
895 | + err = sysfs_create_group(&new_client->dev.kobj, | |
896 | + &lm63_group_fan1); | |
897 | + if (err) | |
527 | 898 | goto exit_remove_files; |
528 | 899 | } |
900 | + if (data->kind == lm96163) { | |
901 | + err = device_create_file(&new_client->dev, | |
902 | + &dev_attr_temp2_type); | |
903 | + if (err) | |
904 | + goto exit_remove_files; | |
529 | 905 | |
906 | + err = sysfs_create_group(&new_client->dev.kobj, | |
907 | + &lm63_group_extra_lut); | |
908 | + if (err) | |
909 | + goto exit_remove_files; | |
910 | + } | |
911 | + | |
530 | 912 | data->hwmon_dev = hwmon_device_register(&new_client->dev); |
531 | 913 | if (IS_ERR(data->hwmon_dev)) { |
532 | 914 | err = PTR_ERR(data->hwmon_dev); |
533 | 915 | |
534 | 916 | |
... | ... | @@ -538,17 +920,25 @@ |
538 | 920 | exit_remove_files: |
539 | 921 | sysfs_remove_group(&new_client->dev.kobj, &lm63_group); |
540 | 922 | sysfs_remove_group(&new_client->dev.kobj, &lm63_group_fan1); |
923 | + if (data->kind == lm96163) { | |
924 | + device_remove_file(&new_client->dev, &dev_attr_temp2_type); | |
925 | + sysfs_remove_group(&new_client->dev.kobj, | |
926 | + &lm63_group_extra_lut); | |
927 | + } | |
541 | 928 | exit_free: |
542 | 929 | kfree(data); |
543 | 930 | exit: |
544 | 931 | return err; |
545 | 932 | } |
546 | 933 | |
547 | -/* Idealy we shouldn't have to initialize anything, since the BIOS | |
548 | - should have taken care of everything */ | |
934 | +/* | |
935 | + * Ideally we shouldn't have to initialize anything, since the BIOS | |
936 | + * should have taken care of everything | |
937 | + */ | |
549 | 938 | static void lm63_init_client(struct i2c_client *client) |
550 | 939 | { |
551 | 940 | struct lm63_data *data = i2c_get_clientdata(client); |
941 | + u8 convrate; | |
552 | 942 | |
553 | 943 | data->config = i2c_smbus_read_byte_data(client, LM63_REG_CONFIG1); |
554 | 944 | data->config_fan = i2c_smbus_read_byte_data(client, |
555 | 945 | |
556 | 946 | |
... | ... | @@ -561,16 +951,57 @@ |
561 | 951 | i2c_smbus_write_byte_data(client, LM63_REG_CONFIG1, |
562 | 952 | data->config); |
563 | 953 | } |
954 | + /* Tachometer is always enabled on LM64 */ | |
955 | + if (data->kind == lm64) | |
956 | + data->config |= 0x04; | |
564 | 957 | |
565 | 958 | /* We may need pwm1_freq before ever updating the client data */ |
566 | 959 | data->pwm1_freq = i2c_smbus_read_byte_data(client, LM63_REG_PWM_FREQ); |
567 | 960 | if (data->pwm1_freq == 0) |
568 | 961 | data->pwm1_freq = 1; |
569 | 962 | |
963 | + switch (data->kind) { | |
964 | + case lm63: | |
965 | + case lm64: | |
966 | + data->max_convrate_hz = LM63_MAX_CONVRATE_HZ; | |
967 | + data->lut_size = 8; | |
968 | + break; | |
969 | + case lm96163: | |
970 | + data->max_convrate_hz = LM96163_MAX_CONVRATE_HZ; | |
971 | + data->lut_size = 12; | |
972 | + data->trutherm | |
973 | + = i2c_smbus_read_byte_data(client, | |
974 | + LM96163_REG_TRUTHERM) & 0x02; | |
975 | + break; | |
976 | + } | |
977 | + convrate = i2c_smbus_read_byte_data(client, LM63_REG_CONVRATE); | |
978 | + if (unlikely(convrate > LM63_MAX_CONVRATE)) | |
979 | + convrate = LM63_MAX_CONVRATE; | |
980 | + data->update_interval = UPDATE_INTERVAL(data->max_convrate_hz, | |
981 | + convrate); | |
982 | + | |
983 | + /* | |
984 | + * For LM96163, check if high resolution PWM | |
985 | + * and unsigned temperature format is enabled. | |
986 | + */ | |
987 | + if (data->kind == lm96163) { | |
988 | + u8 config_enhanced | |
989 | + = i2c_smbus_read_byte_data(client, | |
990 | + LM96163_REG_CONFIG_ENHANCED); | |
991 | + if (config_enhanced & 0x20) | |
992 | + data->lut_temp_highres = true; | |
993 | + if ((config_enhanced & 0x10) | |
994 | + && !(data->config_fan & 0x08) && data->pwm1_freq == 8) | |
995 | + data->pwm_highres = true; | |
996 | + if (config_enhanced & 0x08) | |
997 | + data->remote_unsigned = true; | |
998 | + } | |
999 | + | |
570 | 1000 | /* Show some debug info about the LM63 configuration */ |
571 | - dev_dbg(&client->dev, "Alert/tach pin configured for %s\n", | |
572 | - (data->config & 0x04) ? "tachometer input" : | |
573 | - "alert output"); | |
1001 | + if (data->kind == lm63) | |
1002 | + dev_dbg(&client->dev, "Alert/tach pin configured for %s\n", | |
1003 | + (data->config & 0x04) ? "tachometer input" : | |
1004 | + "alert output"); | |
574 | 1005 | dev_dbg(&client->dev, "PWM clock %s kHz, output frequency %u Hz\n", |
575 | 1006 | (data->config_fan & 0x08) ? "1.4" : "360", |
576 | 1007 | ((data->config_fan & 0x08) ? 700 : 180000) / data->pwm1_freq); |
... | ... | @@ -586,6 +1017,10 @@ |
586 | 1017 | hwmon_device_unregister(data->hwmon_dev); |
587 | 1018 | sysfs_remove_group(&client->dev.kobj, &lm63_group); |
588 | 1019 | sysfs_remove_group(&client->dev.kobj, &lm63_group_fan1); |
1020 | + if (data->kind == lm96163) { | |
1021 | + device_remove_file(&client->dev, &dev_attr_temp2_type); | |
1022 | + sysfs_remove_group(&client->dev.kobj, &lm63_group_extra_lut); | |
1023 | + } | |
589 | 1024 | |
590 | 1025 | kfree(data); |
591 | 1026 | return 0; |
592 | 1027 | |
... | ... | @@ -595,10 +1030,15 @@ |
595 | 1030 | { |
596 | 1031 | struct i2c_client *client = to_i2c_client(dev); |
597 | 1032 | struct lm63_data *data = i2c_get_clientdata(client); |
1033 | + unsigned long next_update; | |
1034 | + int i; | |
598 | 1035 | |
599 | 1036 | mutex_lock(&data->update_lock); |
600 | 1037 | |
601 | - if (time_after(jiffies, data->last_updated + HZ) || !data->valid) { | |
1038 | + next_update = data->last_updated | |
1039 | + + msecs_to_jiffies(data->update_interval) + 1; | |
1040 | + | |
1041 | + if (time_after(jiffies, next_update) || !data->valid) { | |
602 | 1042 | if (data->config & 0x04) { /* tachometer enabled */ |
603 | 1043 | /* order matters for fan1_input */ |
604 | 1044 | data->fan[0] = i2c_smbus_read_byte_data(client, |
... | ... | @@ -615,8 +1055,8 @@ |
615 | 1055 | LM63_REG_PWM_FREQ); |
616 | 1056 | if (data->pwm1_freq == 0) |
617 | 1057 | data->pwm1_freq = 1; |
618 | - data->pwm1_value = i2c_smbus_read_byte_data(client, | |
619 | - LM63_REG_PWM_VALUE); | |
1058 | + data->pwm1[0] = i2c_smbus_read_byte_data(client, | |
1059 | + LM63_REG_PWM_VALUE); | |
620 | 1060 | |
621 | 1061 | data->temp8[0] = i2c_smbus_read_byte_data(client, |
622 | 1062 | LM63_REG_LOCAL_TEMP); |
... | ... | @@ -636,6 +1076,17 @@ |
636 | 1076 | LM63_REG_REMOTE_HIGH_MSB) << 8) |
637 | 1077 | | i2c_smbus_read_byte_data(client, |
638 | 1078 | LM63_REG_REMOTE_HIGH_LSB); |
1079 | + data->temp11[3] = (i2c_smbus_read_byte_data(client, | |
1080 | + LM63_REG_REMOTE_OFFSET_MSB) << 8) | |
1081 | + | i2c_smbus_read_byte_data(client, | |
1082 | + LM63_REG_REMOTE_OFFSET_LSB); | |
1083 | + | |
1084 | + if (data->kind == lm96163) | |
1085 | + data->temp11u = (i2c_smbus_read_byte_data(client, | |
1086 | + LM96163_REG_REMOTE_TEMP_U_MSB) << 8) | |
1087 | + | i2c_smbus_read_byte_data(client, | |
1088 | + LM96163_REG_REMOTE_TEMP_U_LSB); | |
1089 | + | |
639 | 1090 | data->temp8[2] = i2c_smbus_read_byte_data(client, |
640 | 1091 | LM63_REG_REMOTE_TCRIT); |
641 | 1092 | data->temp2_crit_hyst = i2c_smbus_read_byte_data(client, |
... | ... | @@ -646,6 +1097,21 @@ |
646 | 1097 | |
647 | 1098 | data->last_updated = jiffies; |
648 | 1099 | data->valid = 1; |
1100 | + } | |
1101 | + | |
1102 | + if (time_after(jiffies, data->lut_last_updated + 5 * HZ) || | |
1103 | + !data->lut_valid) { | |
1104 | + for (i = 0; i < data->lut_size; i++) { | |
1105 | + data->pwm1[1 + i] = i2c_smbus_read_byte_data(client, | |
1106 | + LM63_REG_LUT_PWM(i)); | |
1107 | + data->temp8[3 + i] = i2c_smbus_read_byte_data(client, | |
1108 | + LM63_REG_LUT_TEMP(i)); | |
1109 | + } | |
1110 | + data->lut_temp_hyst = i2c_smbus_read_byte_data(client, | |
1111 | + LM63_REG_LUT_TEMP_HYST); | |
1112 | + | |
1113 | + data->lut_last_updated = jiffies; | |
1114 | + data->lut_valid = 1; | |
649 | 1115 | } |
650 | 1116 | |
651 | 1117 | mutex_unlock(&data->update_lock); |
drivers/hwmon/lm90.c
drivers/hwmon/max1111.c
... | ... | @@ -106,11 +106,14 @@ |
106 | 106 | if (ret < 0) |
107 | 107 | return ret; |
108 | 108 | |
109 | - return sprintf(buf, "%d\n", ret); | |
109 | + /* assume the reference voltage to be 2.048V, with an 8-bit sample, | |
110 | + * the LSB weight is 8mV | |
111 | + */ | |
112 | + return sprintf(buf, "%d\n", ret * 8); | |
110 | 113 | } |
111 | 114 | |
112 | 115 | #define MAX1111_ADC_ATTR(_id) \ |
113 | - SENSOR_DEVICE_ATTR(adc##_id##_in, S_IRUGO, show_adc, NULL, _id) | |
116 | + SENSOR_DEVICE_ATTR(in##_id##_input, S_IRUGO, show_adc, NULL, _id) | |
114 | 117 | |
115 | 118 | static DEVICE_ATTR(name, S_IRUGO, show_name, NULL); |
116 | 119 | static MAX1111_ADC_ATTR(0); |
... | ... | @@ -120,10 +123,10 @@ |
120 | 123 | |
121 | 124 | static struct attribute *max1111_attributes[] = { |
122 | 125 | &dev_attr_name.attr, |
123 | - &sensor_dev_attr_adc0_in.dev_attr.attr, | |
124 | - &sensor_dev_attr_adc1_in.dev_attr.attr, | |
125 | - &sensor_dev_attr_adc2_in.dev_attr.attr, | |
126 | - &sensor_dev_attr_adc3_in.dev_attr.attr, | |
126 | + &sensor_dev_attr_in0_input.dev_attr.attr, | |
127 | + &sensor_dev_attr_in1_input.dev_attr.attr, | |
128 | + &sensor_dev_attr_in2_input.dev_attr.attr, | |
129 | + &sensor_dev_attr_in3_input.dev_attr.attr, | |
127 | 130 | NULL, |
128 | 131 | }; |
129 | 132 |