Commit f496b2d4f181fa5fcdf24016b11caaa33eb12477
Committed by
Jean Delvare
1 parent
04738b2b2f
Exists in
master
and in
37 other branches
hwmon: (lm63) Add sensor type attribute for external sensor on LM96163
On LM96163, the external temperature sensor type is configurable to either a thermal diode or a 3904 transistor. The chip reports a wrong temperature if misconfigured. Add writable attribute to support it. Signed-off-by: Guenter Roeck <linux@roeck-us.net> Signed-off-by: Jean Delvare <khali@linux-fr.org>
Showing 2 changed files with 52 additions and 1 deletions Side-by-side Diff
Documentation/hwmon/lm63
... | ... | @@ -69,5 +69,6 @@ |
69 | 69 | support these GPIO lines at present. |
70 | 70 | |
71 | 71 | The LM96163 is an enhanced version of LM63 with improved temperature accuracy |
72 | -and better PWM resolution. | |
72 | +and better PWM resolution. For LM96163, the external temperature sensor type is | |
73 | +configurable as CPU embedded diode(1) or 3904 transistor(2). |
drivers/hwmon/lm63.c
... | ... | @@ -93,6 +93,7 @@ |
93 | 93 | #define LM63_REG_MAN_ID 0xFE |
94 | 94 | #define LM63_REG_CHIP_ID 0xFF |
95 | 95 | |
96 | +#define LM96163_REG_TRUTHERM 0x30 | |
96 | 97 | #define LM96163_REG_REMOTE_TEMP_U_MSB 0x31 |
97 | 98 | #define LM96163_REG_REMOTE_TEMP_U_LSB 0x32 |
98 | 99 | #define LM96163_REG_CONFIG_ENHANCED 0x45 |
... | ... | @@ -213,6 +214,7 @@ |
213 | 214 | u8 alarms; |
214 | 215 | bool pwm_highres; |
215 | 216 | bool remote_unsigned; /* true if unsigned remote upper limits */ |
217 | + bool trutherm; | |
216 | 218 | }; |
217 | 219 | |
218 | 220 | static inline int temp8_from_reg(struct lm63_data *data, int nr) |
... | ... | @@ -513,6 +515,41 @@ |
513 | 515 | return count; |
514 | 516 | } |
515 | 517 | |
518 | +static ssize_t show_type(struct device *dev, struct device_attribute *attr, | |
519 | + char *buf) | |
520 | +{ | |
521 | + struct i2c_client *client = to_i2c_client(dev); | |
522 | + struct lm63_data *data = i2c_get_clientdata(client); | |
523 | + | |
524 | + return sprintf(buf, data->trutherm ? "1\n" : "2\n"); | |
525 | +} | |
526 | + | |
527 | +static ssize_t set_type(struct device *dev, struct device_attribute *attr, | |
528 | + const char *buf, size_t count) | |
529 | +{ | |
530 | + struct i2c_client *client = to_i2c_client(dev); | |
531 | + struct lm63_data *data = i2c_get_clientdata(client); | |
532 | + unsigned long val; | |
533 | + int ret; | |
534 | + u8 reg; | |
535 | + | |
536 | + ret = kstrtoul(buf, 10, &val); | |
537 | + if (ret < 0) | |
538 | + return ret; | |
539 | + if (val != 1 && val != 2) | |
540 | + return -EINVAL; | |
541 | + | |
542 | + mutex_lock(&data->update_lock); | |
543 | + data->trutherm = val == 1; | |
544 | + reg = i2c_smbus_read_byte_data(client, LM96163_REG_TRUTHERM) & ~0x02; | |
545 | + i2c_smbus_write_byte_data(client, LM96163_REG_TRUTHERM, | |
546 | + reg | (data->trutherm ? 0x02 : 0x00)); | |
547 | + data->valid = 0; | |
548 | + mutex_unlock(&data->update_lock); | |
549 | + | |
550 | + return count; | |
551 | +} | |
552 | + | |
516 | 553 | static ssize_t show_alarms(struct device *dev, struct device_attribute *dummy, |
517 | 554 | char *buf) |
518 | 555 | { |
... | ... | @@ -553,6 +590,8 @@ |
553 | 590 | static DEVICE_ATTR(temp2_crit_hyst, S_IWUSR | S_IRUGO, show_temp2_crit_hyst, |
554 | 591 | set_temp2_crit_hyst); |
555 | 592 | |
593 | +static DEVICE_ATTR(temp2_type, S_IWUSR | S_IRUGO, show_type, set_type); | |
594 | + | |
556 | 595 | /* Individual alarm files */ |
557 | 596 | static SENSOR_DEVICE_ATTR(fan1_min_alarm, S_IRUGO, show_alarm, NULL, 0); |
558 | 597 | static SENSOR_DEVICE_ATTR(temp2_crit_alarm, S_IRUGO, show_alarm, NULL, 1); |
... | ... | @@ -712,6 +751,12 @@ |
712 | 751 | if (err) |
713 | 752 | goto exit_remove_files; |
714 | 753 | } |
754 | + if (data->kind == lm96163) { | |
755 | + err = device_create_file(&new_client->dev, | |
756 | + &dev_attr_temp2_type); | |
757 | + if (err) | |
758 | + goto exit_remove_files; | |
759 | + } | |
715 | 760 | |
716 | 761 | data->hwmon_dev = hwmon_device_register(&new_client->dev); |
717 | 762 | if (IS_ERR(data->hwmon_dev)) { |
... | ... | @@ -722,6 +767,7 @@ |
722 | 767 | return 0; |
723 | 768 | |
724 | 769 | exit_remove_files: |
770 | + device_remove_file(&new_client->dev, &dev_attr_temp2_type); | |
725 | 771 | sysfs_remove_group(&new_client->dev.kobj, &lm63_group); |
726 | 772 | sysfs_remove_group(&new_client->dev.kobj, &lm63_group_fan1); |
727 | 773 | exit_free: |
... | ... | @@ -763,6 +809,9 @@ |
763 | 809 | break; |
764 | 810 | case lm96163: |
765 | 811 | data->max_convrate_hz = LM96163_MAX_CONVRATE_HZ; |
812 | + data->trutherm | |
813 | + = i2c_smbus_read_byte_data(client, | |
814 | + LM96163_REG_TRUTHERM) & 0x02; | |
766 | 815 | break; |
767 | 816 | } |
768 | 817 | convrate = i2c_smbus_read_byte_data(client, LM63_REG_CONVRATE); |
... | ... | @@ -803,6 +852,7 @@ |
803 | 852 | struct lm63_data *data = i2c_get_clientdata(client); |
804 | 853 | |
805 | 854 | hwmon_device_unregister(data->hwmon_dev); |
855 | + device_remove_file(&client->dev, &dev_attr_temp2_type); | |
806 | 856 | sysfs_remove_group(&client->dev.kobj, &lm63_group); |
807 | 857 | sysfs_remove_group(&client->dev.kobj, &lm63_group_fan1); |
808 | 858 |