diff options
author | Guenter Roeck <linux@roeck-us.net> | 2012-01-16 16:51:46 -0500 |
---|---|---|
committer | Jean Delvare <khali@endymion.delvare> | 2012-01-16 16:51:46 -0500 |
commit | 04738b2b2f37c13bbe37b7695fec6c1c60d79c7a (patch) | |
tree | 77802752c8901e35eab6bfb1763e7160e37c7328 /drivers/hwmon | |
parent | 94e55df48a230162edc641e55c28d058f5b6cb76 (diff) |
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>
Diffstat (limited to 'drivers/hwmon')
-rw-r--r-- | drivers/hwmon/lm63.c | 92 |
1 files changed, 90 insertions, 2 deletions
diff --git a/drivers/hwmon/lm63.c b/drivers/hwmon/lm63.c index a9e6212ed54a..5f6da52a7219 100644 --- a/drivers/hwmon/lm63.c +++ b/drivers/hwmon/lm63.c | |||
@@ -61,6 +61,7 @@ static const unsigned short normal_i2c[] = { 0x18, 0x4c, 0x4e, I2C_CLIENT_END }; | |||
61 | */ | 61 | */ |
62 | 62 | ||
63 | #define LM63_REG_CONFIG1 0x03 | 63 | #define LM63_REG_CONFIG1 0x03 |
64 | #define LM63_REG_CONVRATE 0x04 | ||
64 | #define LM63_REG_CONFIG2 0xBF | 65 | #define LM63_REG_CONFIG2 0xBF |
65 | #define LM63_REG_CONFIG_FAN 0x4A | 66 | #define LM63_REG_CONFIG_FAN 0x4A |
66 | 67 | ||
@@ -96,6 +97,11 @@ static const unsigned short normal_i2c[] = { 0x18, 0x4c, 0x4e, I2C_CLIENT_END }; | |||
96 | #define LM96163_REG_REMOTE_TEMP_U_LSB 0x32 | 97 | #define LM96163_REG_REMOTE_TEMP_U_LSB 0x32 |
97 | #define LM96163_REG_CONFIG_ENHANCED 0x45 | 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 | * Conversions and various macros | 106 | * Conversions and various macros |
101 | * For tachometer counts, the LM63 uses 16-bit values. | 107 | * For tachometer counts, the LM63 uses 16-bit values. |
@@ -132,6 +138,9 @@ static const unsigned short normal_i2c[] = { 0x18, 0x4c, 0x4e, I2C_CLIENT_END }; | |||
132 | (val) >= 127000 ? 127 : \ | 138 | (val) >= 127000 ? 127 : \ |
133 | ((val) + 500) / 1000) | 139 | ((val) + 500) / 1000) |
134 | 140 | ||
141 | #define UPDATE_INTERVAL(max, rate) \ | ||
142 | ((1000 << (LM63_MAX_CONVRATE - (rate))) / (max)) | ||
143 | |||
135 | /* | 144 | /* |
136 | * Functions declaration | 145 | * Functions declaration |
137 | */ | 146 | */ |
@@ -180,9 +189,12 @@ struct lm63_data { | |||
180 | struct mutex update_lock; | 189 | struct mutex update_lock; |
181 | char valid; /* zero until following fields are valid */ | 190 | char valid; /* zero until following fields are valid */ |
182 | unsigned long last_updated; /* in jiffies */ | 191 | unsigned long last_updated; /* in jiffies */ |
183 | int kind; | 192 | enum chips kind; |
184 | int temp2_offset; | 193 | int temp2_offset; |
185 | 194 | ||
195 | int update_interval; /* in milliseconds */ | ||
196 | int max_convrate_hz; | ||
197 | |||
186 | /* registers values */ | 198 | /* registers values */ |
187 | u8 config, config_fan; | 199 | u8 config, config_fan; |
188 | u16 fan[2]; /* 0: input | 200 | u16 fan[2]; /* 0: input |
@@ -449,6 +461,58 @@ static ssize_t set_temp2_crit_hyst(struct device *dev, | |||
449 | return count; | 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 | static ssize_t show_alarms(struct device *dev, struct device_attribute *dummy, | 516 | static ssize_t show_alarms(struct device *dev, struct device_attribute *dummy, |
453 | char *buf) | 517 | char *buf) |
454 | { | 518 | { |
@@ -499,6 +563,9 @@ static SENSOR_DEVICE_ATTR(temp1_max_alarm, S_IRUGO, show_alarm, NULL, 6); | |||
499 | /* Raw alarm file for compatibility */ | 563 | /* Raw alarm file for compatibility */ |
500 | static DEVICE_ATTR(alarms, S_IRUGO, show_alarms, NULL); | 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 | static struct attribute *lm63_attributes[] = { | 569 | static struct attribute *lm63_attributes[] = { |
503 | &dev_attr_pwm1.attr, | 570 | &dev_attr_pwm1.attr, |
504 | &dev_attr_pwm1_enable.attr, | 571 | &dev_attr_pwm1_enable.attr, |
@@ -517,6 +584,7 @@ static struct attribute *lm63_attributes[] = { | |||
517 | &sensor_dev_attr_temp2_max_alarm.dev_attr.attr, | 584 | &sensor_dev_attr_temp2_max_alarm.dev_attr.attr, |
518 | &sensor_dev_attr_temp1_max_alarm.dev_attr.attr, | 585 | &sensor_dev_attr_temp1_max_alarm.dev_attr.attr, |
519 | &dev_attr_alarms.attr, | 586 | &dev_attr_alarms.attr, |
587 | &dev_attr_update_interval.attr, | ||
520 | NULL | 588 | NULL |
521 | }; | 589 | }; |
522 | 590 | ||
@@ -669,6 +737,7 @@ exit: | |||
669 | static void lm63_init_client(struct i2c_client *client) | 737 | static void lm63_init_client(struct i2c_client *client) |
670 | { | 738 | { |
671 | struct lm63_data *data = i2c_get_clientdata(client); | 739 | struct lm63_data *data = i2c_get_clientdata(client); |
740 | u8 convrate; | ||
672 | 741 | ||
673 | data->config = i2c_smbus_read_byte_data(client, LM63_REG_CONFIG1); | 742 | data->config = i2c_smbus_read_byte_data(client, LM63_REG_CONFIG1); |
674 | data->config_fan = i2c_smbus_read_byte_data(client, | 743 | data->config_fan = i2c_smbus_read_byte_data(client, |
@@ -687,6 +756,21 @@ static void lm63_init_client(struct i2c_client *client) | |||
687 | if (data->pwm1_freq == 0) | 756 | if (data->pwm1_freq == 0) |
688 | data->pwm1_freq = 1; | 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 | * For LM96163, check if high resolution PWM | 775 | * For LM96163, check if high resolution PWM |
692 | * and unsigned temperature format is enabled. | 776 | * and unsigned temperature format is enabled. |
@@ -730,10 +814,14 @@ static struct lm63_data *lm63_update_device(struct device *dev) | |||
730 | { | 814 | { |
731 | struct i2c_client *client = to_i2c_client(dev); | 815 | struct i2c_client *client = to_i2c_client(dev); |
732 | struct lm63_data *data = i2c_get_clientdata(client); | 816 | struct lm63_data *data = i2c_get_clientdata(client); |
817 | unsigned long next_update; | ||
733 | 818 | ||
734 | mutex_lock(&data->update_lock); | 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 | if (data->config & 0x04) { /* tachometer enabled */ | 825 | if (data->config & 0x04) { /* tachometer enabled */ |
738 | /* order matters for fan1_input */ | 826 | /* order matters for fan1_input */ |
739 | data->fan[0] = i2c_smbus_read_byte_data(client, | 827 | data->fan[0] = i2c_smbus_read_byte_data(client, |