hwmon: (it87) Introduce support for tempX_offset sysfs attribute
authorGuenter Roeck <linux@roeck-us.net>
Wed, 19 Dec 2012 21:17:01 +0000 (22:17 +0100)
committerJean Delvare <khali@endymion.delvare>
Wed, 19 Dec 2012 21:17:01 +0000 (22:17 +0100)
Signed-off-by: Guenter Roeck <linux@roeck-us.net>
Signed-off-by: Jean Delvare <khali@linux-fr.org>
Documentation/hwmon/it87
drivers/hwmon/it87.c

index 87850d8..e1f3828 100644 (file)
@@ -209,3 +209,12 @@ doesn't use CPU cycles.
 Trip points must be set properly before switching to automatic fan speed
 control mode. The driver will perform basic integrity checks before
 actually switching to automatic control mode.
+
+
+Temperature offset attributes
+-----------------------------
+
+The driver supports temp[1-3]_offset sysfs attributes to adjust the reported
+temperature for thermal diodes or diode-connected thermal transistors.
+If a temperature sensor is configured for thermistors, the attribute values
+are ignored.
index 21fb7f2..7675632 100644 (file)
@@ -203,6 +203,8 @@ static const u8 IT87_REG_FAN[]              = { 0x0d, 0x0e, 0x0f, 0x80, 0x82 };
 static const u8 IT87_REG_FAN_MIN[]     = { 0x10, 0x11, 0x12, 0x84, 0x86 };
 static const u8 IT87_REG_FANX[]                = { 0x18, 0x19, 0x1a, 0x81, 0x83 };
 static const u8 IT87_REG_FANX_MIN[]    = { 0x1b, 0x1c, 0x1d, 0x85, 0x87 };
+static const u8 IT87_REG_TEMP_OFFSET[] = { 0x56, 0x57, 0x59 };
+
 #define IT87_REG_FAN_MAIN_CTRL 0x13
 #define IT87_REG_FAN_CTL       0x14
 #define IT87_REG_PWM(nr)       (0x15 + (nr))
@@ -263,7 +265,7 @@ struct it87_data {
        u16 fan[5];             /* Register values, possibly combined */
        u16 fan_min[5];         /* Register values, possibly combined */
        u8 has_temp;            /* Bitfield, temp sensors enabled */
-       s8 temp[3][3];          /* [nr][0]=temp, [1]=min, [2]=max */
+       s8 temp[3][4];          /* [nr][0]=temp, [1]=min, [2]=max, [3]=offset */
        u8 sensor;              /* Register value */
        u8 fan_div[3];          /* Register encoding, shifted right */
        u8 vid;                 /* Register encoding, combined */
@@ -312,6 +314,17 @@ static inline int has_newer_autopwm(const struct it87_data *data)
            || data->type == it8728;
 }
 
+static inline int has_temp_offset(const struct it87_data *data)
+{
+       return data->type == it8716
+           || data->type == it8718
+           || data->type == it8720
+           || data->type == it8721
+           || data->type == it8728
+           || data->type == it8782
+           || data->type == it8783;
+}
+
 static int adc_lsb(const struct it87_data *data, int nr)
 {
        int lsb = has_12mv_adc(data) ? 12 : 16;
@@ -546,16 +559,34 @@ static ssize_t set_temp(struct device *dev, struct device_attribute *attr,
        int index = sattr->index;
        struct it87_data *data = dev_get_drvdata(dev);
        long val;
+       u8 reg, regval;
 
        if (kstrtol(buf, 10, &val) < 0)
                return -EINVAL;
 
        mutex_lock(&data->update_lock);
+
+       switch (index) {
+       default:
+       case 1:
+               reg = IT87_REG_TEMP_LOW(nr);
+               break;
+       case 2:
+               reg = IT87_REG_TEMP_HIGH(nr);
+               break;
+       case 3:
+               regval = it87_read_value(data, IT87_REG_BEEP_ENABLE);
+               if (!(regval & 0x80)) {
+                       regval |= 0x80;
+                       it87_write_value(data, IT87_REG_BEEP_ENABLE, regval);
+               }
+               data->valid = 0;
+               reg = IT87_REG_TEMP_OFFSET[nr];
+               break;
+       }
+
        data->temp[nr][index] = TEMP_TO_REG(val);
-       it87_write_value(data,
-                        index == 1 ? IT87_REG_TEMP_LOW(nr)
-                                   : IT87_REG_TEMP_HIGH(nr),
-                        data->temp[nr][index]);
+       it87_write_value(data, reg, data->temp[nr][index]);
        mutex_unlock(&data->update_lock);
        return count;
 }
@@ -565,16 +596,22 @@ static SENSOR_DEVICE_ATTR_2(temp1_min, S_IRUGO | S_IWUSR, show_temp, set_temp,
                            0, 1);
 static SENSOR_DEVICE_ATTR_2(temp1_max, S_IRUGO | S_IWUSR, show_temp, set_temp,
                            0, 2);
+static SENSOR_DEVICE_ATTR_2(temp1_offset, S_IRUGO | S_IWUSR, show_temp,
+                           set_temp, 0, 3);
 static SENSOR_DEVICE_ATTR_2(temp2_input, S_IRUGO, show_temp, NULL, 1, 0);
 static SENSOR_DEVICE_ATTR_2(temp2_min, S_IRUGO | S_IWUSR, show_temp, set_temp,
                            1, 1);
 static SENSOR_DEVICE_ATTR_2(temp2_max, S_IRUGO | S_IWUSR, show_temp, set_temp,
                            1, 2);
+static SENSOR_DEVICE_ATTR_2(temp2_offset, S_IRUGO | S_IWUSR, show_temp,
+                           set_temp, 1, 3);
 static SENSOR_DEVICE_ATTR_2(temp3_input, S_IRUGO, show_temp, NULL, 2, 0);
 static SENSOR_DEVICE_ATTR_2(temp3_min, S_IRUGO | S_IWUSR, show_temp, set_temp,
                            2, 1);
 static SENSOR_DEVICE_ATTR_2(temp3_max, S_IRUGO | S_IWUSR, show_temp, set_temp,
                            2, 2);
+static SENSOR_DEVICE_ATTR_2(temp3_offset, S_IRUGO | S_IWUSR, show_temp,
+                           set_temp, 2, 3);
 
 static ssize_t show_temp_type(struct device *dev, struct device_attribute *attr,
                              char *buf)
@@ -1429,6 +1466,12 @@ static const struct attribute_group it87_group_temp[3] = {
        { .attrs = it87_attributes_temp[2] },
 };
 
+static struct attribute *it87_attributes_temp_offset[] = {
+       &sensor_dev_attr_temp1_offset.dev_attr.attr,
+       &sensor_dev_attr_temp2_offset.dev_attr.attr,
+       &sensor_dev_attr_temp3_offset.dev_attr.attr,
+};
+
 static struct attribute *it87_attributes[] = {
        &dev_attr_alarms.attr,
        &sensor_dev_attr_intrusion0_alarm.dev_attr.attr,
@@ -1899,6 +1942,9 @@ static void it87_remove_files(struct device *dev)
                if (!(data->has_temp & (1 << i)))
                        continue;
                sysfs_remove_group(&dev->kobj, &it87_group_temp[i]);
+               if (has_temp_offset(data))
+                       sysfs_remove_file(&dev->kobj,
+                                         it87_attributes_temp_offset[i]);
                if (sio_data->beep_pin)
                        sysfs_remove_file(&dev->kobj,
                                          it87_attributes_temp_beep[i]);
@@ -2026,6 +2072,12 @@ static int it87_probe(struct platform_device *pdev)
                err = sysfs_create_group(&dev->kobj, &it87_group_temp[i]);
                if (err)
                        goto error;
+               if (has_temp_offset(data)) {
+                       err = sysfs_create_file(&dev->kobj,
+                                               it87_attributes_temp_offset[i]);
+                       if (err)
+                               goto error;
+               }
                if (sio_data->beep_pin) {
                        err = sysfs_create_file(&dev->kobj,
                                                it87_attributes_temp_beep[i]);
@@ -2383,6 +2435,10 @@ static struct it87_data *it87_update_device(struct device *dev)
                                it87_read_value(data, IT87_REG_TEMP_LOW(i));
                        data->temp[i][2] =
                                it87_read_value(data, IT87_REG_TEMP_HIGH(i));
+                       if (has_temp_offset(data))
+                               data->temp[i][3] =
+                                 it87_read_value(data,
+                                                 IT87_REG_TEMP_OFFSET[i]);
                }
 
                /* Newer chips don't have clock dividers */