Commit 04738b2b2f37c13bbe37b7695fec6c1c60d79c7a
Committed by
Jean Delvare
1 parent
94e55df48a
Exists in
master
and in
6 other branches
hwmon: (lm63) Add support for update_interval sysfs attribute
The update interval is configurable on LM63 and compatibles. Add support for it. Signed-off-by: Guenter Roeck <linux@roeck-us.net> Signed-off-by: Jean Delvare <khali@linux-fr.org>
Showing 2 changed files with 93 additions and 5 deletions Side-by-side Diff
Documentation/hwmon/lm63
... | ... | @@ -61,9 +61,9 @@ |
61 | 61 | (you cannot define your custom PWM/temperature curve), and mode change isn't |
62 | 62 | supported either. |
63 | 63 | |
64 | -The lm63 driver will not update its values more frequently than every | |
65 | -second; reading them more often will do no harm, but will return 'old' | |
66 | -values. | |
64 | +The lm63 driver will not update its values more frequently than configured with | |
65 | +the update_interval sysfs attribute; reading them more often will do no harm, | |
66 | +but will return 'old' values. | |
67 | 67 | |
68 | 68 | The LM64 is effectively an LM63 with GPIO lines. The driver does not |
69 | 69 | support these GPIO lines at present. |
drivers/hwmon/lm63.c
... | ... | @@ -61,6 +61,7 @@ |
61 | 61 | */ |
62 | 62 | |
63 | 63 | #define LM63_REG_CONFIG1 0x03 |
64 | +#define LM63_REG_CONVRATE 0x04 | |
64 | 65 | #define LM63_REG_CONFIG2 0xBF |
65 | 66 | #define LM63_REG_CONFIG_FAN 0x4A |
66 | 67 | |
... | ... | @@ -96,6 +97,11 @@ |
96 | 97 | #define LM96163_REG_REMOTE_TEMP_U_LSB 0x32 |
97 | 98 | #define LM96163_REG_CONFIG_ENHANCED 0x45 |
98 | 99 | |
100 | +#define LM63_MAX_CONVRATE 9 | |
101 | + | |
102 | +#define LM63_MAX_CONVRATE_HZ 32 | |
103 | +#define LM96163_MAX_CONVRATE_HZ 26 | |
104 | + | |
99 | 105 | /* |
100 | 106 | * Conversions and various macros |
101 | 107 | * For tachometer counts, the LM63 uses 16-bit values. |
... | ... | @@ -132,6 +138,9 @@ |
132 | 138 | (val) >= 127000 ? 127 : \ |
133 | 139 | ((val) + 500) / 1000) |
134 | 140 | |
141 | +#define UPDATE_INTERVAL(max, rate) \ | |
142 | + ((1000 << (LM63_MAX_CONVRATE - (rate))) / (max)) | |
143 | + | |
135 | 144 | /* |
136 | 145 | * Functions declaration |
137 | 146 | */ |
138 | 147 | |
... | ... | @@ -180,9 +189,12 @@ |
180 | 189 | struct mutex update_lock; |
181 | 190 | char valid; /* zero until following fields are valid */ |
182 | 191 | unsigned long last_updated; /* in jiffies */ |
183 | - int kind; | |
192 | + enum chips kind; | |
184 | 193 | int temp2_offset; |
185 | 194 | |
195 | + int update_interval; /* in milliseconds */ | |
196 | + int max_convrate_hz; | |
197 | + | |
186 | 198 | /* registers values */ |
187 | 199 | u8 config, config_fan; |
188 | 200 | u16 fan[2]; /* 0: input |
... | ... | @@ -449,6 +461,58 @@ |
449 | 461 | return count; |
450 | 462 | } |
451 | 463 | |
464 | +/* | |
465 | + * Set conversion rate. | |
466 | + * client->update_lock must be held when calling this function. | |
467 | + */ | |
468 | +static void lm63_set_convrate(struct i2c_client *client, struct lm63_data *data, | |
469 | + unsigned int interval) | |
470 | +{ | |
471 | + int i; | |
472 | + unsigned int update_interval; | |
473 | + | |
474 | + /* Shift calculations to avoid rounding errors */ | |
475 | + interval <<= 6; | |
476 | + | |
477 | + /* find the nearest update rate */ | |
478 | + update_interval = (1 << (LM63_MAX_CONVRATE + 6)) * 1000 | |
479 | + / data->max_convrate_hz; | |
480 | + for (i = 0; i < LM63_MAX_CONVRATE; i++, update_interval >>= 1) | |
481 | + if (interval >= update_interval * 3 / 4) | |
482 | + break; | |
483 | + | |
484 | + i2c_smbus_write_byte_data(client, LM63_REG_CONVRATE, i); | |
485 | + data->update_interval = UPDATE_INTERVAL(data->max_convrate_hz, i); | |
486 | +} | |
487 | + | |
488 | +static ssize_t show_update_interval(struct device *dev, | |
489 | + struct device_attribute *attr, char *buf) | |
490 | +{ | |
491 | + struct lm63_data *data = dev_get_drvdata(dev); | |
492 | + | |
493 | + return sprintf(buf, "%u\n", data->update_interval); | |
494 | +} | |
495 | + | |
496 | +static ssize_t set_update_interval(struct device *dev, | |
497 | + struct device_attribute *attr, | |
498 | + const char *buf, size_t count) | |
499 | +{ | |
500 | + struct i2c_client *client = to_i2c_client(dev); | |
501 | + struct lm63_data *data = i2c_get_clientdata(client); | |
502 | + unsigned long val; | |
503 | + int err; | |
504 | + | |
505 | + err = kstrtoul(buf, 10, &val); | |
506 | + if (err) | |
507 | + return err; | |
508 | + | |
509 | + mutex_lock(&data->update_lock); | |
510 | + lm63_set_convrate(client, data, SENSORS_LIMIT(val, 0, 100000)); | |
511 | + mutex_unlock(&data->update_lock); | |
512 | + | |
513 | + return count; | |
514 | +} | |
515 | + | |
452 | 516 | static ssize_t show_alarms(struct device *dev, struct device_attribute *dummy, |
453 | 517 | char *buf) |
454 | 518 | { |
... | ... | @@ -499,6 +563,9 @@ |
499 | 563 | /* Raw alarm file for compatibility */ |
500 | 564 | static DEVICE_ATTR(alarms, S_IRUGO, show_alarms, NULL); |
501 | 565 | |
566 | +static DEVICE_ATTR(update_interval, S_IRUGO | S_IWUSR, show_update_interval, | |
567 | + set_update_interval); | |
568 | + | |
502 | 569 | static struct attribute *lm63_attributes[] = { |
503 | 570 | &dev_attr_pwm1.attr, |
504 | 571 | &dev_attr_pwm1_enable.attr, |
... | ... | @@ -517,6 +584,7 @@ |
517 | 584 | &sensor_dev_attr_temp2_max_alarm.dev_attr.attr, |
518 | 585 | &sensor_dev_attr_temp1_max_alarm.dev_attr.attr, |
519 | 586 | &dev_attr_alarms.attr, |
587 | + &dev_attr_update_interval.attr, | |
520 | 588 | NULL |
521 | 589 | }; |
522 | 590 | |
... | ... | @@ -669,6 +737,7 @@ |
669 | 737 | static void lm63_init_client(struct i2c_client *client) |
670 | 738 | { |
671 | 739 | struct lm63_data *data = i2c_get_clientdata(client); |
740 | + u8 convrate; | |
672 | 741 | |
673 | 742 | data->config = i2c_smbus_read_byte_data(client, LM63_REG_CONFIG1); |
674 | 743 | data->config_fan = i2c_smbus_read_byte_data(client, |
... | ... | @@ -687,6 +756,21 @@ |
687 | 756 | if (data->pwm1_freq == 0) |
688 | 757 | data->pwm1_freq = 1; |
689 | 758 | |
759 | + switch (data->kind) { | |
760 | + case lm63: | |
761 | + case lm64: | |
762 | + data->max_convrate_hz = LM63_MAX_CONVRATE_HZ; | |
763 | + break; | |
764 | + case lm96163: | |
765 | + data->max_convrate_hz = LM96163_MAX_CONVRATE_HZ; | |
766 | + break; | |
767 | + } | |
768 | + convrate = i2c_smbus_read_byte_data(client, LM63_REG_CONVRATE); | |
769 | + if (unlikely(convrate > LM63_MAX_CONVRATE)) | |
770 | + convrate = LM63_MAX_CONVRATE; | |
771 | + data->update_interval = UPDATE_INTERVAL(data->max_convrate_hz, | |
772 | + convrate); | |
773 | + | |
690 | 774 | /* |
691 | 775 | * For LM96163, check if high resolution PWM |
692 | 776 | * and unsigned temperature format is enabled. |
693 | 777 | |
... | ... | @@ -730,10 +814,14 @@ |
730 | 814 | { |
731 | 815 | struct i2c_client *client = to_i2c_client(dev); |
732 | 816 | struct lm63_data *data = i2c_get_clientdata(client); |
817 | + unsigned long next_update; | |
733 | 818 | |
734 | 819 | mutex_lock(&data->update_lock); |
735 | 820 | |
736 | - if (time_after(jiffies, data->last_updated + HZ) || !data->valid) { | |
821 | + next_update = data->last_updated | |
822 | + + msecs_to_jiffies(data->update_interval) + 1; | |
823 | + | |
824 | + if (time_after(jiffies, next_update) || !data->valid) { | |
737 | 825 | if (data->config & 0x04) { /* tachometer enabled */ |
738 | 826 | /* order matters for fan1_input */ |
739 | 827 | data->fan[0] = i2c_smbus_read_byte_data(client, |