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>
This commit is contained in:
Родитель
09475d32e6
Коммит
52b5226f48
|
@ -12,7 +12,7 @@
|
|||
* also work with the MAX6651. It does not distinguish max6650 and max6651
|
||||
* chips.
|
||||
*
|
||||
* Tha datasheet was last seen at:
|
||||
* The datasheet was last seen at:
|
||||
*
|
||||
* http://pdfserv.maxim-ic.com/en/ds/MAX6650-MAX6651.pdf
|
||||
*
|
||||
|
@ -98,6 +98,16 @@ I2C_CLIENT_INSMOD_1(max6650);
|
|||
#define MAX6650_CFG_MODE_OPEN_LOOP 0x30
|
||||
#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 */
|
||||
#define FAN_RPM_MIN 240
|
||||
#define FAN_RPM_MAX 30000
|
||||
|
@ -151,6 +161,7 @@ struct max6650_data
|
|||
u8 tach[4];
|
||||
u8 count;
|
||||
u8 dac;
|
||||
u8 alarm;
|
||||
};
|
||||
|
||||
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,
|
|||
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(fan2_input, S_IRUGO, get_fan, NULL, 1);
|
||||
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);
|
|||
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, 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[] = {
|
||||
&sensor_dev_attr_fan1_input.dev_attr.attr,
|
||||
|
@ -437,11 +509,17 @@ static struct attribute *max6650_attrs[] = {
|
|||
&dev_attr_fan1_div.attr,
|
||||
&dev_attr_pwm1_enable.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
|
||||
};
|
||||
|
||||
static struct attribute_group max6650_attr_grp = {
|
||||
.attrs = max6650_attrs,
|
||||
.is_visible = max6650_attrs_visible,
|
||||
};
|
||||
|
||||
/*
|
||||
|
@ -659,6 +737,12 @@ static struct max6650_data *max6650_update_device(struct device *dev)
|
|||
MAX6650_REG_COUNT);
|
||||
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->valid = 1;
|
||||
}
|
||||
|
|
Загрузка…
Ссылка в новой задаче