aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/hwmon/lm63.c
diff options
context:
space:
mode:
authorJean Delvare <khali@linux-fr.org>2012-01-16 16:51:47 -0500
committerJean Delvare <khali@endymion.delvare>2012-01-16 16:51:47 -0500
commitd216f6809eb690b9a888c286cde68cda4d0c4cfa (patch)
tree46a83526ded3df6713a0d41514adb1ad465b969f /drivers/hwmon/lm63.c
parentd93ab7807063ade8ad4b3ba55347e333dbde4d52 (diff)
hwmon: (lm63) Expose automatic fan speed control lookup table
The LM63 and compatible devices have a lookup table to control the fan speed automatically. Expose it in sysfs. Values are cached for 5 seconds, independently of the other register values to avoid slowing down "sensors". We might make the table values writable in the future. Signed-off-by: Jean Delvare <khali@linux-fr.org> Tested-by: Guenter Roeck <guenter.roeck@ericsson.com> Acked-by: Guenter Roeck <guenter.roeck@ericsson.com>
Diffstat (limited to 'drivers/hwmon/lm63.c')
-rw-r--r--drivers/hwmon/lm63.c148
1 files changed, 134 insertions, 14 deletions
diff --git a/drivers/hwmon/lm63.c b/drivers/hwmon/lm63.c
index a5e4ba82af17..1c06a333ba20 100644
--- a/drivers/hwmon/lm63.c
+++ b/drivers/hwmon/lm63.c
@@ -75,6 +75,9 @@ static const unsigned short normal_i2c[] = { 0x18, 0x4c, 0x4e, I2C_CLIENT_END };
75 75
76#define LM63_REG_PWM_VALUE 0x4C 76#define LM63_REG_PWM_VALUE 0x4C
77#define LM63_REG_PWM_FREQ 0x4D 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))
78 81
79#define LM63_REG_LOCAL_TEMP 0x00 82#define LM63_REG_LOCAL_TEMP 0x00
80#define LM63_REG_LOCAL_HIGH 0x05 83#define LM63_REG_LOCAL_HIGH 0x05
@@ -192,7 +195,9 @@ struct lm63_data {
192 struct device *hwmon_dev; 195 struct device *hwmon_dev;
193 struct mutex update_lock; 196 struct mutex update_lock;
194 char valid; /* zero until following fields are valid */ 197 char valid; /* zero until following fields are valid */
198 char lut_valid; /* zero until lut fields are valid */
195 unsigned long last_updated; /* in jiffies */ 199 unsigned long last_updated; /* in jiffies */
200 unsigned long lut_last_updated; /* in jiffies */
196 enum chips kind; 201 enum chips kind;
197 int temp2_offset; 202 int temp2_offset;
198 203
@@ -204,18 +209,22 @@ struct lm63_data {
204 u16 fan[2]; /* 0: input 209 u16 fan[2]; /* 0: input
205 1: low limit */ 210 1: low limit */
206 u8 pwm1_freq; 211 u8 pwm1_freq;
207 u8 pwm1_value; 212 u8 pwm1[9]; /* 0: current output
208 s8 temp8[3]; /* 0: local input 213 1-8: lookup table */
214 s8 temp8[11]; /* 0: local input
209 1: local high limit 215 1: local high limit
210 2: remote critical limit */ 216 2: remote critical limit
217 3-10: lookup table */
211 s16 temp11[4]; /* 0: remote input 218 s16 temp11[4]; /* 0: remote input
212 1: remote low limit 219 1: remote low limit
213 2: remote high limit 220 2: remote high limit
214 3: remote offset */ 221 3: remote offset */
215 u16 temp11u; /* remote input (unsigned) */ 222 u16 temp11u; /* remote input (unsigned) */
216 u8 temp2_crit_hyst; 223 u8 temp2_crit_hyst;
224 u8 lut_temp_hyst;
217 u8 alarms; 225 u8 alarms;
218 bool pwm_highres; 226 bool pwm_highres;
227 bool lut_temp_highres;
219 bool remote_unsigned; /* true if unsigned remote upper limits */ 228 bool remote_unsigned; /* true if unsigned remote upper limits */
220 bool trutherm; 229 bool trutherm;
221}; 230};
@@ -227,6 +236,11 @@ static inline int temp8_from_reg(struct lm63_data *data, int nr)
227 return TEMP8_FROM_REG(data->temp8[nr]); 236 return TEMP8_FROM_REG(data->temp8[nr]);
228} 237}
229 238
239static inline int lut_temp_from_reg(struct lm63_data *data, int nr)
240{
241 return data->temp8[nr] * (data->lut_temp_highres ? 500 : 1000);
242}
243
230/* 244/*
231 * Sysfs callback functions and files 245 * Sysfs callback functions and files
232 */ 246 */
@@ -261,17 +275,19 @@ static ssize_t set_fan(struct device *dev, struct device_attribute *dummy,
261 return count; 275 return count;
262} 276}
263 277
264static ssize_t show_pwm1(struct device *dev, struct device_attribute *dummy, 278static ssize_t show_pwm1(struct device *dev, struct device_attribute *devattr,
265 char *buf) 279 char *buf)
266{ 280{
281 struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
267 struct lm63_data *data = lm63_update_device(dev); 282 struct lm63_data *data = lm63_update_device(dev);
283 int nr = attr->index;
268 int pwm; 284 int pwm;
269 285
270 if (data->pwm_highres) 286 if (data->pwm_highres)
271 pwm = data->pwm1_value; 287 pwm = data->pwm1[nr];
272 else 288 else
273 pwm = data->pwm1_value >= 2 * data->pwm1_freq ? 289 pwm = data->pwm1[nr] >= 2 * data->pwm1_freq ?
274 255 : (data->pwm1_value * 255 + data->pwm1_freq) / 290 255 : (data->pwm1[nr] * 255 + data->pwm1_freq) /
275 (2 * data->pwm1_freq); 291 (2 * data->pwm1_freq);
276 292
277 return sprintf(buf, "%d\n", pwm); 293 return sprintf(buf, "%d\n", pwm);
@@ -294,9 +310,9 @@ static ssize_t set_pwm1(struct device *dev, struct device_attribute *dummy,
294 310
295 val = SENSORS_LIMIT(val, 0, 255); 311 val = SENSORS_LIMIT(val, 0, 255);
296 mutex_lock(&data->update_lock); 312 mutex_lock(&data->update_lock);
297 data->pwm1_value = data->pwm_highres ? val : 313 data->pwm1[0] = data->pwm_highres ? val :
298 (val * data->pwm1_freq * 2 + 127) / 255; 314 (val * data->pwm1_freq * 2 + 127) / 255;
299 i2c_smbus_write_byte_data(client, LM63_REG_PWM_VALUE, data->pwm1_value); 315 i2c_smbus_write_byte_data(client, LM63_REG_PWM_VALUE, data->pwm1[0]);
300 mutex_unlock(&data->update_lock); 316 mutex_unlock(&data->update_lock);
301 return count; 317 return count;
302} 318}
@@ -333,6 +349,16 @@ static ssize_t show_remote_temp8(struct device *dev,
333 + data->temp2_offset); 349 + data->temp2_offset);
334} 350}
335 351
352static ssize_t show_lut_temp(struct device *dev,
353 struct device_attribute *devattr,
354 char *buf)
355{
356 struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
357 struct lm63_data *data = lm63_update_device(dev);
358 return sprintf(buf, "%d\n", lut_temp_from_reg(data, attr->index)
359 + data->temp2_offset);
360}
361
336static ssize_t set_temp8(struct device *dev, struct device_attribute *devattr, 362static ssize_t set_temp8(struct device *dev, struct device_attribute *devattr,
337 const char *buf, size_t count) 363 const char *buf, size_t count)
338{ 364{
@@ -440,6 +466,17 @@ static ssize_t show_temp2_crit_hyst(struct device *dev,
440 - TEMP8_FROM_REG(data->temp2_crit_hyst)); 466 - TEMP8_FROM_REG(data->temp2_crit_hyst));
441} 467}
442 468
469static ssize_t show_lut_temp_hyst(struct device *dev,
470 struct device_attribute *devattr, char *buf)
471{
472 struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
473 struct lm63_data *data = lm63_update_device(dev);
474
475 return sprintf(buf, "%d\n", lut_temp_from_reg(data, attr->index)
476 + data->temp2_offset
477 - TEMP8_FROM_REG(data->lut_temp_hyst));
478}
479
443/* 480/*
444 * And now the other way around, user-space provides an absolute 481 * And now the other way around, user-space provides an absolute
445 * hysteresis value and we have to store a relative one 482 * hysteresis value and we have to store a relative one
@@ -574,8 +611,48 @@ static SENSOR_DEVICE_ATTR(fan1_input, S_IRUGO, show_fan, NULL, 0);
574static SENSOR_DEVICE_ATTR(fan1_min, S_IWUSR | S_IRUGO, show_fan, 611static SENSOR_DEVICE_ATTR(fan1_min, S_IWUSR | S_IRUGO, show_fan,
575 set_fan, 1); 612 set_fan, 1);
576 613
577static DEVICE_ATTR(pwm1, S_IWUSR | S_IRUGO, show_pwm1, set_pwm1); 614static SENSOR_DEVICE_ATTR(pwm1, S_IWUSR | S_IRUGO, show_pwm1, set_pwm1, 0);
578static DEVICE_ATTR(pwm1_enable, S_IRUGO, show_pwm1_enable, NULL); 615static DEVICE_ATTR(pwm1_enable, S_IRUGO, show_pwm1_enable, NULL);
616static SENSOR_DEVICE_ATTR(pwm1_auto_point1_pwm, S_IRUGO, show_pwm1, NULL, 1);
617static SENSOR_DEVICE_ATTR(pwm1_auto_point1_temp, S_IRUGO,
618 show_lut_temp, NULL, 3);
619static SENSOR_DEVICE_ATTR(pwm1_auto_point1_temp_hyst, S_IRUGO,
620 show_lut_temp_hyst, NULL, 3);
621static SENSOR_DEVICE_ATTR(pwm1_auto_point2_pwm, S_IRUGO, show_pwm1, NULL, 2);
622static SENSOR_DEVICE_ATTR(pwm1_auto_point2_temp, S_IRUGO,
623 show_lut_temp, NULL, 4);
624static SENSOR_DEVICE_ATTR(pwm1_auto_point2_temp_hyst, S_IRUGO,
625 show_lut_temp_hyst, NULL, 4);
626static SENSOR_DEVICE_ATTR(pwm1_auto_point3_pwm, S_IRUGO, show_pwm1, NULL, 3);
627static SENSOR_DEVICE_ATTR(pwm1_auto_point3_temp, S_IRUGO,
628 show_lut_temp, NULL, 5);
629static SENSOR_DEVICE_ATTR(pwm1_auto_point3_temp_hyst, S_IRUGO,
630 show_lut_temp_hyst, NULL, 5);
631static SENSOR_DEVICE_ATTR(pwm1_auto_point4_pwm, S_IRUGO, show_pwm1, NULL, 4);
632static SENSOR_DEVICE_ATTR(pwm1_auto_point4_temp, S_IRUGO,
633 show_lut_temp, NULL, 6);
634static SENSOR_DEVICE_ATTR(pwm1_auto_point4_temp_hyst, S_IRUGO,
635 show_lut_temp_hyst, NULL, 6);
636static SENSOR_DEVICE_ATTR(pwm1_auto_point5_pwm, S_IRUGO, show_pwm1, NULL, 5);
637static SENSOR_DEVICE_ATTR(pwm1_auto_point5_temp, S_IRUGO,
638 show_lut_temp, NULL, 7);
639static SENSOR_DEVICE_ATTR(pwm1_auto_point5_temp_hyst, S_IRUGO,
640 show_lut_temp_hyst, NULL, 7);
641static SENSOR_DEVICE_ATTR(pwm1_auto_point6_pwm, S_IRUGO, show_pwm1, NULL, 6);
642static SENSOR_DEVICE_ATTR(pwm1_auto_point6_temp, S_IRUGO,
643 show_lut_temp, NULL, 8);
644static SENSOR_DEVICE_ATTR(pwm1_auto_point6_temp_hyst, S_IRUGO,
645 show_lut_temp_hyst, NULL, 8);
646static SENSOR_DEVICE_ATTR(pwm1_auto_point7_pwm, S_IRUGO, show_pwm1, NULL, 7);
647static SENSOR_DEVICE_ATTR(pwm1_auto_point7_temp, S_IRUGO,
648 show_lut_temp, NULL, 9);
649static SENSOR_DEVICE_ATTR(pwm1_auto_point7_temp_hyst, S_IRUGO,
650 show_lut_temp_hyst, NULL, 9);
651static SENSOR_DEVICE_ATTR(pwm1_auto_point8_pwm, S_IRUGO, show_pwm1, NULL, 8);
652static SENSOR_DEVICE_ATTR(pwm1_auto_point8_temp, S_IRUGO,
653 show_lut_temp, NULL, 10);
654static SENSOR_DEVICE_ATTR(pwm1_auto_point8_temp_hyst, S_IRUGO,
655 show_lut_temp_hyst, NULL, 10);
579 656
580static SENSOR_DEVICE_ATTR(temp1_input, S_IRUGO, show_local_temp8, NULL, 0); 657static SENSOR_DEVICE_ATTR(temp1_input, S_IRUGO, show_local_temp8, NULL, 0);
581static SENSOR_DEVICE_ATTR(temp1_max, S_IWUSR | S_IRUGO, show_local_temp8, 658static SENSOR_DEVICE_ATTR(temp1_max, S_IWUSR | S_IRUGO, show_local_temp8,
@@ -609,8 +686,33 @@ static DEVICE_ATTR(update_interval, S_IRUGO | S_IWUSR, show_update_interval,
609 set_update_interval); 686 set_update_interval);
610 687
611static struct attribute *lm63_attributes[] = { 688static struct attribute *lm63_attributes[] = {
612 &dev_attr_pwm1.attr, 689 &sensor_dev_attr_pwm1.dev_attr.attr,
613 &dev_attr_pwm1_enable.attr, 690 &dev_attr_pwm1_enable.attr,
691 &sensor_dev_attr_pwm1_auto_point1_pwm.dev_attr.attr,
692 &sensor_dev_attr_pwm1_auto_point1_temp.dev_attr.attr,
693 &sensor_dev_attr_pwm1_auto_point1_temp_hyst.dev_attr.attr,
694 &sensor_dev_attr_pwm1_auto_point2_pwm.dev_attr.attr,
695 &sensor_dev_attr_pwm1_auto_point2_temp.dev_attr.attr,
696 &sensor_dev_attr_pwm1_auto_point2_temp_hyst.dev_attr.attr,
697 &sensor_dev_attr_pwm1_auto_point3_pwm.dev_attr.attr,
698 &sensor_dev_attr_pwm1_auto_point3_temp.dev_attr.attr,
699 &sensor_dev_attr_pwm1_auto_point3_temp_hyst.dev_attr.attr,
700 &sensor_dev_attr_pwm1_auto_point4_pwm.dev_attr.attr,
701 &sensor_dev_attr_pwm1_auto_point4_temp.dev_attr.attr,
702 &sensor_dev_attr_pwm1_auto_point4_temp_hyst.dev_attr.attr,
703 &sensor_dev_attr_pwm1_auto_point5_pwm.dev_attr.attr,
704 &sensor_dev_attr_pwm1_auto_point5_temp.dev_attr.attr,
705 &sensor_dev_attr_pwm1_auto_point5_temp_hyst.dev_attr.attr,
706 &sensor_dev_attr_pwm1_auto_point6_pwm.dev_attr.attr,
707 &sensor_dev_attr_pwm1_auto_point6_temp.dev_attr.attr,
708 &sensor_dev_attr_pwm1_auto_point6_temp_hyst.dev_attr.attr,
709 &sensor_dev_attr_pwm1_auto_point7_pwm.dev_attr.attr,
710 &sensor_dev_attr_pwm1_auto_point7_temp.dev_attr.attr,
711 &sensor_dev_attr_pwm1_auto_point7_temp_hyst.dev_attr.attr,
712 &sensor_dev_attr_pwm1_auto_point8_pwm.dev_attr.attr,
713 &sensor_dev_attr_pwm1_auto_point8_temp.dev_attr.attr,
714 &sensor_dev_attr_pwm1_auto_point8_temp_hyst.dev_attr.attr,
715
614 &sensor_dev_attr_temp1_input.dev_attr.attr, 716 &sensor_dev_attr_temp1_input.dev_attr.attr,
615 &sensor_dev_attr_temp2_input.dev_attr.attr, 717 &sensor_dev_attr_temp2_input.dev_attr.attr,
616 &sensor_dev_attr_temp2_min.dev_attr.attr, 718 &sensor_dev_attr_temp2_min.dev_attr.attr,
@@ -834,6 +936,8 @@ static void lm63_init_client(struct i2c_client *client)
834 u8 config_enhanced 936 u8 config_enhanced
835 = i2c_smbus_read_byte_data(client, 937 = i2c_smbus_read_byte_data(client,
836 LM96163_REG_CONFIG_ENHANCED); 938 LM96163_REG_CONFIG_ENHANCED);
939 if (config_enhanced & 0x20)
940 data->lut_temp_highres = true;
837 if ((config_enhanced & 0x10) 941 if ((config_enhanced & 0x10)
838 && !(data->config_fan & 0x08) && data->pwm1_freq == 8) 942 && !(data->config_fan & 0x08) && data->pwm1_freq == 8)
839 data->pwm_highres = true; 943 data->pwm_highres = true;
@@ -872,6 +976,7 @@ static struct lm63_data *lm63_update_device(struct device *dev)
872 struct i2c_client *client = to_i2c_client(dev); 976 struct i2c_client *client = to_i2c_client(dev);
873 struct lm63_data *data = i2c_get_clientdata(client); 977 struct lm63_data *data = i2c_get_clientdata(client);
874 unsigned long next_update; 978 unsigned long next_update;
979 int i;
875 980
876 mutex_lock(&data->update_lock); 981 mutex_lock(&data->update_lock);
877 982
@@ -895,8 +1000,8 @@ static struct lm63_data *lm63_update_device(struct device *dev)
895 LM63_REG_PWM_FREQ); 1000 LM63_REG_PWM_FREQ);
896 if (data->pwm1_freq == 0) 1001 if (data->pwm1_freq == 0)
897 data->pwm1_freq = 1; 1002 data->pwm1_freq = 1;
898 data->pwm1_value = i2c_smbus_read_byte_data(client, 1003 data->pwm1[0] = i2c_smbus_read_byte_data(client,
899 LM63_REG_PWM_VALUE); 1004 LM63_REG_PWM_VALUE);
900 1005
901 data->temp8[0] = i2c_smbus_read_byte_data(client, 1006 data->temp8[0] = i2c_smbus_read_byte_data(client,
902 LM63_REG_LOCAL_TEMP); 1007 LM63_REG_LOCAL_TEMP);
@@ -939,6 +1044,21 @@ static struct lm63_data *lm63_update_device(struct device *dev)
939 data->valid = 1; 1044 data->valid = 1;
940 } 1045 }
941 1046
1047 if (time_after(jiffies, data->lut_last_updated + 5 * HZ) ||
1048 !data->lut_valid) {
1049 for (i = 0; i < 8; i++) {
1050 data->pwm1[1 + i] = i2c_smbus_read_byte_data(client,
1051 LM63_REG_LUT_PWM(i));
1052 data->temp8[3 + i] = i2c_smbus_read_byte_data(client,
1053 LM63_REG_LUT_TEMP(i));
1054 }
1055 data->lut_temp_hyst = i2c_smbus_read_byte_data(client,
1056 LM63_REG_LUT_TEMP_HYST);
1057
1058 data->lut_last_updated = jiffies;
1059 data->lut_valid = 1;
1060 }
1061
942 mutex_unlock(&data->update_lock); 1062 mutex_unlock(&data->update_lock);
943 1063
944 return data; 1064 return data;