Commit 52b5226f authored by Christian Engelmayer's avatar Christian Engelmayer Committed by Jean Delvare

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: default avatarChristian Engelmayer <christian.engelmayer@frequentis.com>
Acked-by: default avatarHans de Goede <hdegoede@redhat.com>
Signed-off-by: default avatarJean Delvare <khali@linux-fr.org>
parent 09475d32
...@@ -12,7 +12,7 @@ ...@@ -12,7 +12,7 @@
* also work with the MAX6651. It does not distinguish max6650 and max6651 * also work with the MAX6651. It does not distinguish max6650 and max6651
* chips. * chips.
* *
* Tha datasheet was last seen at: * The datasheet was last seen at:
* *
* http://pdfserv.maxim-ic.com/en/ds/MAX6650-MAX6651.pdf * http://pdfserv.maxim-ic.com/en/ds/MAX6650-MAX6651.pdf
* *
...@@ -98,6 +98,16 @@ I2C_CLIENT_INSMOD_1(max6650); ...@@ -98,6 +98,16 @@ I2C_CLIENT_INSMOD_1(max6650);
#define MAX6650_CFG_MODE_OPEN_LOOP 0x30 #define MAX6650_CFG_MODE_OPEN_LOOP 0x30
#define MAX6650_COUNT_MASK 0x03 #define MAX6650_COUNT_MASK 0x03
/*
* Alarm status register bits
*/
#define MAX6650_ALRM_MAX 0x01
#define MAX6650_ALRM_MIN 0x02
#define MAX6650_ALRM_TACH 0x04
#define MAX6650_ALRM_GPIO1 0x08
#define MAX6650_ALRM_GPIO2 0x10
/* Minimum and maximum values of the FAN-RPM */ /* Minimum and maximum values of the FAN-RPM */
#define FAN_RPM_MIN 240 #define FAN_RPM_MIN 240
#define FAN_RPM_MAX 30000 #define FAN_RPM_MAX 30000
...@@ -151,6 +161,7 @@ struct max6650_data ...@@ -151,6 +161,7 @@ struct max6650_data
u8 tach[4]; u8 tach[4];
u8 count; u8 count;
u8 dac; u8 dac;
u8 alarm;
}; };
static ssize_t get_fan(struct device *dev, struct device_attribute *devattr, 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,6 +429,33 @@ static ssize_t set_div(struct device *dev, struct device_attribute *devattr,
return count; return count;
} }
/*
* Get alarm stati:
* Possible values:
* 0 = no alarm
* 1 = alarm
*/
static ssize_t get_alarm(struct device *dev, struct device_attribute *devattr,
char *buf)
{
struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
struct max6650_data *data = max6650_update_device(dev);
struct i2c_client *client = to_i2c_client(dev);
int alarm = 0;
if (data->alarm & attr->index) {
mutex_lock(&data->update_lock);
alarm = 1;
data->alarm &= ~attr->index;
data->alarm |= i2c_smbus_read_byte_data(client,
MAX6650_REG_ALARM);
mutex_unlock(&data->update_lock);
}
return sprintf(buf, "%d\n", alarm);
}
static SENSOR_DEVICE_ATTR(fan1_input, S_IRUGO, get_fan, NULL, 0); static SENSOR_DEVICE_ATTR(fan1_input, S_IRUGO, get_fan, NULL, 0);
static SENSOR_DEVICE_ATTR(fan2_input, S_IRUGO, get_fan, NULL, 1); static SENSOR_DEVICE_ATTR(fan2_input, S_IRUGO, get_fan, NULL, 1);
static SENSOR_DEVICE_ATTR(fan3_input, S_IRUGO, get_fan, NULL, 2); 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,7 +464,41 @@ static DEVICE_ATTR(fan1_target, S_IWUSR | S_IRUGO, get_target, set_target);
static DEVICE_ATTR(fan1_div, S_IWUSR | S_IRUGO, get_div, set_div); static DEVICE_ATTR(fan1_div, S_IWUSR | S_IRUGO, get_div, set_div);
static DEVICE_ATTR(pwm1_enable, S_IWUSR | S_IRUGO, get_enable, set_enable); static DEVICE_ATTR(pwm1_enable, S_IWUSR | S_IRUGO, get_enable, set_enable);
static DEVICE_ATTR(pwm1, S_IWUSR | S_IRUGO, get_pwm, set_pwm); static DEVICE_ATTR(pwm1, S_IWUSR | S_IRUGO, get_pwm, set_pwm);
static SENSOR_DEVICE_ATTR(fan1_max_alarm, S_IRUGO, get_alarm, NULL,
MAX6650_ALRM_MAX);
static SENSOR_DEVICE_ATTR(fan1_min_alarm, S_IRUGO, get_alarm, NULL,
MAX6650_ALRM_MIN);
static SENSOR_DEVICE_ATTR(fan1_fault, S_IRUGO, get_alarm, NULL,
MAX6650_ALRM_TACH);
static SENSOR_DEVICE_ATTR(gpio1_alarm, S_IRUGO, get_alarm, NULL,
MAX6650_ALRM_GPIO1);
static SENSOR_DEVICE_ATTR(gpio2_alarm, S_IRUGO, get_alarm, NULL,
MAX6650_ALRM_GPIO2);
static mode_t max6650_attrs_visible(struct kobject *kobj, struct attribute *a,
int n)
{
struct device *dev = container_of(kobj, struct device, kobj);
struct i2c_client *client = to_i2c_client(dev);
u8 alarm_en = i2c_smbus_read_byte_data(client, MAX6650_REG_ALARM_EN);
struct device_attribute *devattr;
/*
* Hide the alarms that have not been enabled by the firmware
*/
devattr = container_of(a, struct device_attribute, attr);
if (devattr == &sensor_dev_attr_fan1_max_alarm.dev_attr
|| devattr == &sensor_dev_attr_fan1_min_alarm.dev_attr
|| devattr == &sensor_dev_attr_fan1_fault.dev_attr
|| devattr == &sensor_dev_attr_gpio1_alarm.dev_attr
|| devattr == &sensor_dev_attr_gpio2_alarm.dev_attr) {
if (!(alarm_en & to_sensor_dev_attr(devattr)->index))
return 0;
}
return a->mode;
}
static struct attribute *max6650_attrs[] = { static struct attribute *max6650_attrs[] = {
&sensor_dev_attr_fan1_input.dev_attr.attr, &sensor_dev_attr_fan1_input.dev_attr.attr,
...@@ -437,11 +509,17 @@ static struct attribute *max6650_attrs[] = { ...@@ -437,11 +509,17 @@ static struct attribute *max6650_attrs[] = {
&dev_attr_fan1_div.attr, &dev_attr_fan1_div.attr,
&dev_attr_pwm1_enable.attr, &dev_attr_pwm1_enable.attr,
&dev_attr_pwm1.attr, &dev_attr_pwm1.attr,
&sensor_dev_attr_fan1_max_alarm.dev_attr.attr,
&sensor_dev_attr_fan1_min_alarm.dev_attr.attr,
&sensor_dev_attr_fan1_fault.dev_attr.attr,
&sensor_dev_attr_gpio1_alarm.dev_attr.attr,
&sensor_dev_attr_gpio2_alarm.dev_attr.attr,
NULL NULL
}; };
static struct attribute_group max6650_attr_grp = { static struct attribute_group max6650_attr_grp = {
.attrs = max6650_attrs, .attrs = max6650_attrs,
.is_visible = max6650_attrs_visible,
}; };
/* /*
...@@ -659,6 +737,12 @@ static struct max6650_data *max6650_update_device(struct device *dev) ...@@ -659,6 +737,12 @@ static struct max6650_data *max6650_update_device(struct device *dev)
MAX6650_REG_COUNT); MAX6650_REG_COUNT);
data->dac = i2c_smbus_read_byte_data(client, MAX6650_REG_DAC); data->dac = i2c_smbus_read_byte_data(client, MAX6650_REG_DAC);
/* Alarms are cleared on read in case the condition that
* caused the alarm is removed. Keep the value latched here
* for providing the register through different alarm files. */
data->alarm |= i2c_smbus_read_byte_data(client,
MAX6650_REG_ALARM);
data->last_updated = jiffies; data->last_updated = jiffies;
data->valid = 1; data->valid = 1;
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment