diff options
author | Christian Engelmayer <christian.engelmayer@frequentis.com> | 2009-06-15 12:39:52 -0400 |
---|---|---|
committer | Jean Delvare <khali@linux-fr.org> | 2009-06-15 12:39:52 -0400 |
commit | 52b5226f481c09cc499cc28b1e9347d314b340f1 (patch) | |
tree | 96cd3e3cdc6fc8128aaad252807abf86aaf7b368 /drivers | |
parent | 09475d32e652fe60901fe8c9cd50f3f6db0c4933 (diff) |
hwmon: (max6650) Add support for alarms
Export the alarm flags provided by the MAX6650/MAX6651 fan-speed regulator
and monitor chips via sysfs.
Signed-off-by: Christian Engelmayer <christian.engelmayer@frequentis.com>
Acked-by: Hans de Goede <hdegoede@redhat.com>
Signed-off-by: Jean Delvare <khali@linux-fr.org>
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/hwmon/max6650.c | 86 |
1 files changed, 85 insertions, 1 deletions
diff --git a/drivers/hwmon/max6650.c b/drivers/hwmon/max6650.c index f27af6a9da41..86142a858238 100644 --- a/drivers/hwmon/max6650.c +++ b/drivers/hwmon/max6650.c | |||
@@ -12,7 +12,7 @@ | |||
12 | * also work with the MAX6651. It does not distinguish max6650 and max6651 | 12 | * also work with the MAX6651. It does not distinguish max6650 and max6651 |
13 | * chips. | 13 | * chips. |
14 | * | 14 | * |
15 | * Tha datasheet was last seen at: | 15 | * The datasheet was last seen at: |
16 | * | 16 | * |
17 | * http://pdfserv.maxim-ic.com/en/ds/MAX6650-MAX6651.pdf | 17 | * http://pdfserv.maxim-ic.com/en/ds/MAX6650-MAX6651.pdf |
18 | * | 18 | * |
@@ -98,6 +98,16 @@ I2C_CLIENT_INSMOD_1(max6650); | |||
98 | #define MAX6650_CFG_MODE_OPEN_LOOP 0x30 | 98 | #define MAX6650_CFG_MODE_OPEN_LOOP 0x30 |
99 | #define MAX6650_COUNT_MASK 0x03 | 99 | #define MAX6650_COUNT_MASK 0x03 |
100 | 100 | ||
101 | /* | ||
102 | * Alarm status register bits | ||
103 | */ | ||
104 | |||
105 | #define MAX6650_ALRM_MAX 0x01 | ||
106 | #define MAX6650_ALRM_MIN 0x02 | ||
107 | #define MAX6650_ALRM_TACH 0x04 | ||
108 | #define MAX6650_ALRM_GPIO1 0x08 | ||
109 | #define MAX6650_ALRM_GPIO2 0x10 | ||
110 | |||
101 | /* Minimum and maximum values of the FAN-RPM */ | 111 | /* Minimum and maximum values of the FAN-RPM */ |
102 | #define FAN_RPM_MIN 240 | 112 | #define FAN_RPM_MIN 240 |
103 | #define FAN_RPM_MAX 30000 | 113 | #define FAN_RPM_MAX 30000 |
@@ -151,6 +161,7 @@ struct max6650_data | |||
151 | u8 tach[4]; | 161 | u8 tach[4]; |
152 | u8 count; | 162 | u8 count; |
153 | u8 dac; | 163 | u8 dac; |
164 | u8 alarm; | ||
154 | }; | 165 | }; |
155 | 166 | ||
156 | static ssize_t get_fan(struct device *dev, struct device_attribute *devattr, | 167 | static ssize_t get_fan(struct device *dev, struct device_attribute *devattr, |
@@ -418,6 +429,33 @@ static ssize_t set_div(struct device *dev, struct device_attribute *devattr, | |||
418 | return count; | 429 | return count; |
419 | } | 430 | } |
420 | 431 | ||
432 | /* | ||
433 | * Get alarm stati: | ||
434 | * Possible values: | ||
435 | * 0 = no alarm | ||
436 | * 1 = alarm | ||
437 | */ | ||
438 | |||
439 | static ssize_t get_alarm(struct device *dev, struct device_attribute *devattr, | ||
440 | char *buf) | ||
441 | { | ||
442 | struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); | ||
443 | struct max6650_data *data = max6650_update_device(dev); | ||
444 | struct i2c_client *client = to_i2c_client(dev); | ||
445 | int alarm = 0; | ||
446 | |||
447 | if (data->alarm & attr->index) { | ||
448 | mutex_lock(&data->update_lock); | ||
449 | alarm = 1; | ||
450 | data->alarm &= ~attr->index; | ||
451 | data->alarm |= i2c_smbus_read_byte_data(client, | ||
452 | MAX6650_REG_ALARM); | ||
453 | mutex_unlock(&data->update_lock); | ||
454 | } | ||
455 | |||
456 | return sprintf(buf, "%d\n", alarm); | ||
457 | } | ||
458 | |||
421 | static SENSOR_DEVICE_ATTR(fan1_input, S_IRUGO, get_fan, NULL, 0); | 459 | static SENSOR_DEVICE_ATTR(fan1_input, S_IRUGO, get_fan, NULL, 0); |
422 | static SENSOR_DEVICE_ATTR(fan2_input, S_IRUGO, get_fan, NULL, 1); | 460 | static SENSOR_DEVICE_ATTR(fan2_input, S_IRUGO, get_fan, NULL, 1); |
423 | static SENSOR_DEVICE_ATTR(fan3_input, S_IRUGO, get_fan, NULL, 2); | 461 | static SENSOR_DEVICE_ATTR(fan3_input, S_IRUGO, get_fan, NULL, 2); |
@@ -426,7 +464,41 @@ static DEVICE_ATTR(fan1_target, S_IWUSR | S_IRUGO, get_target, set_target); | |||
426 | static DEVICE_ATTR(fan1_div, S_IWUSR | S_IRUGO, get_div, set_div); | 464 | static DEVICE_ATTR(fan1_div, S_IWUSR | S_IRUGO, get_div, set_div); |
427 | static DEVICE_ATTR(pwm1_enable, S_IWUSR | S_IRUGO, get_enable, set_enable); | 465 | static DEVICE_ATTR(pwm1_enable, S_IWUSR | S_IRUGO, get_enable, set_enable); |
428 | static DEVICE_ATTR(pwm1, S_IWUSR | S_IRUGO, get_pwm, set_pwm); | 466 | static DEVICE_ATTR(pwm1, S_IWUSR | S_IRUGO, get_pwm, set_pwm); |
467 | static SENSOR_DEVICE_ATTR(fan1_max_alarm, S_IRUGO, get_alarm, NULL, | ||
468 | MAX6650_ALRM_MAX); | ||
469 | static SENSOR_DEVICE_ATTR(fan1_min_alarm, S_IRUGO, get_alarm, NULL, | ||
470 | MAX6650_ALRM_MIN); | ||
471 | static SENSOR_DEVICE_ATTR(fan1_fault, S_IRUGO, get_alarm, NULL, | ||
472 | MAX6650_ALRM_TACH); | ||
473 | static SENSOR_DEVICE_ATTR(gpio1_alarm, S_IRUGO, get_alarm, NULL, | ||
474 | MAX6650_ALRM_GPIO1); | ||
475 | static SENSOR_DEVICE_ATTR(gpio2_alarm, S_IRUGO, get_alarm, NULL, | ||
476 | MAX6650_ALRM_GPIO2); | ||
477 | |||
478 | static mode_t max6650_attrs_visible(struct kobject *kobj, struct attribute *a, | ||
479 | int n) | ||
480 | { | ||
481 | struct device *dev = container_of(kobj, struct device, kobj); | ||
482 | struct i2c_client *client = to_i2c_client(dev); | ||
483 | u8 alarm_en = i2c_smbus_read_byte_data(client, MAX6650_REG_ALARM_EN); | ||
484 | struct device_attribute *devattr; | ||
429 | 485 | ||
486 | /* | ||
487 | * Hide the alarms that have not been enabled by the firmware | ||
488 | */ | ||
489 | |||
490 | devattr = container_of(a, struct device_attribute, attr); | ||
491 | if (devattr == &sensor_dev_attr_fan1_max_alarm.dev_attr | ||
492 | || devattr == &sensor_dev_attr_fan1_min_alarm.dev_attr | ||
493 | || devattr == &sensor_dev_attr_fan1_fault.dev_attr | ||
494 | || devattr == &sensor_dev_attr_gpio1_alarm.dev_attr | ||
495 | || devattr == &sensor_dev_attr_gpio2_alarm.dev_attr) { | ||
496 | if (!(alarm_en & to_sensor_dev_attr(devattr)->index)) | ||
497 | return 0; | ||
498 | } | ||
499 | |||
500 | return a->mode; | ||
501 | } | ||
430 | 502 | ||
431 | static struct attribute *max6650_attrs[] = { | 503 | static struct attribute *max6650_attrs[] = { |
432 | &sensor_dev_attr_fan1_input.dev_attr.attr, | 504 | &sensor_dev_attr_fan1_input.dev_attr.attr, |
@@ -437,11 +509,17 @@ static struct attribute *max6650_attrs[] = { | |||
437 | &dev_attr_fan1_div.attr, | 509 | &dev_attr_fan1_div.attr, |
438 | &dev_attr_pwm1_enable.attr, | 510 | &dev_attr_pwm1_enable.attr, |
439 | &dev_attr_pwm1.attr, | 511 | &dev_attr_pwm1.attr, |
512 | &sensor_dev_attr_fan1_max_alarm.dev_attr.attr, | ||
513 | &sensor_dev_attr_fan1_min_alarm.dev_attr.attr, | ||
514 | &sensor_dev_attr_fan1_fault.dev_attr.attr, | ||
515 | &sensor_dev_attr_gpio1_alarm.dev_attr.attr, | ||
516 | &sensor_dev_attr_gpio2_alarm.dev_attr.attr, | ||
440 | NULL | 517 | NULL |
441 | }; | 518 | }; |
442 | 519 | ||
443 | static struct attribute_group max6650_attr_grp = { | 520 | static struct attribute_group max6650_attr_grp = { |
444 | .attrs = max6650_attrs, | 521 | .attrs = max6650_attrs, |
522 | .is_visible = max6650_attrs_visible, | ||
445 | }; | 523 | }; |
446 | 524 | ||
447 | /* | 525 | /* |
@@ -659,6 +737,12 @@ static struct max6650_data *max6650_update_device(struct device *dev) | |||
659 | MAX6650_REG_COUNT); | 737 | MAX6650_REG_COUNT); |
660 | data->dac = i2c_smbus_read_byte_data(client, MAX6650_REG_DAC); | 738 | data->dac = i2c_smbus_read_byte_data(client, MAX6650_REG_DAC); |
661 | 739 | ||
740 | /* Alarms are cleared on read in case the condition that | ||
741 | * caused the alarm is removed. Keep the value latched here | ||
742 | * for providing the register through different alarm files. */ | ||
743 | data->alarm |= i2c_smbus_read_byte_data(client, | ||
744 | MAX6650_REG_ALARM); | ||
745 | |||
662 | data->last_updated = jiffies; | 746 | data->last_updated = jiffies; |
663 | data->valid = 1; | 747 | data->valid = 1; |
664 | } | 748 | } |