diff options
| -rw-r--r-- | Documentation/hwmon/it87 | 9 | ||||
| -rw-r--r-- | drivers/hwmon/it87.c | 66 |
2 files changed, 70 insertions, 5 deletions
diff --git a/Documentation/hwmon/it87 b/Documentation/hwmon/it87 index 87850d86c559..e1f38287fbb3 100644 --- a/Documentation/hwmon/it87 +++ b/Documentation/hwmon/it87 | |||
| @@ -209,3 +209,12 @@ doesn't use CPU cycles. | |||
| 209 | Trip points must be set properly before switching to automatic fan speed | 209 | Trip points must be set properly before switching to automatic fan speed |
| 210 | control mode. The driver will perform basic integrity checks before | 210 | control mode. The driver will perform basic integrity checks before |
| 211 | actually switching to automatic control mode. | 211 | actually switching to automatic control mode. |
| 212 | |||
| 213 | |||
| 214 | Temperature offset attributes | ||
| 215 | ----------------------------- | ||
| 216 | |||
| 217 | The driver supports temp[1-3]_offset sysfs attributes to adjust the reported | ||
| 218 | temperature for thermal diodes or diode-connected thermal transistors. | ||
| 219 | If a temperature sensor is configured for thermistors, the attribute values | ||
| 220 | are ignored. | ||
diff --git a/drivers/hwmon/it87.c b/drivers/hwmon/it87.c index 21fb7f24152c..767563269182 100644 --- a/drivers/hwmon/it87.c +++ b/drivers/hwmon/it87.c | |||
| @@ -203,6 +203,8 @@ static const u8 IT87_REG_FAN[] = { 0x0d, 0x0e, 0x0f, 0x80, 0x82 }; | |||
| 203 | static const u8 IT87_REG_FAN_MIN[] = { 0x10, 0x11, 0x12, 0x84, 0x86 }; | 203 | static const u8 IT87_REG_FAN_MIN[] = { 0x10, 0x11, 0x12, 0x84, 0x86 }; |
| 204 | static const u8 IT87_REG_FANX[] = { 0x18, 0x19, 0x1a, 0x81, 0x83 }; | 204 | static const u8 IT87_REG_FANX[] = { 0x18, 0x19, 0x1a, 0x81, 0x83 }; |
| 205 | static const u8 IT87_REG_FANX_MIN[] = { 0x1b, 0x1c, 0x1d, 0x85, 0x87 }; | 205 | static const u8 IT87_REG_FANX_MIN[] = { 0x1b, 0x1c, 0x1d, 0x85, 0x87 }; |
| 206 | static const u8 IT87_REG_TEMP_OFFSET[] = { 0x56, 0x57, 0x59 }; | ||
| 207 | |||
| 206 | #define IT87_REG_FAN_MAIN_CTRL 0x13 | 208 | #define IT87_REG_FAN_MAIN_CTRL 0x13 |
| 207 | #define IT87_REG_FAN_CTL 0x14 | 209 | #define IT87_REG_FAN_CTL 0x14 |
| 208 | #define IT87_REG_PWM(nr) (0x15 + (nr)) | 210 | #define IT87_REG_PWM(nr) (0x15 + (nr)) |
| @@ -263,7 +265,7 @@ struct it87_data { | |||
| 263 | u16 fan[5]; /* Register values, possibly combined */ | 265 | u16 fan[5]; /* Register values, possibly combined */ |
| 264 | u16 fan_min[5]; /* Register values, possibly combined */ | 266 | u16 fan_min[5]; /* Register values, possibly combined */ |
| 265 | u8 has_temp; /* Bitfield, temp sensors enabled */ | 267 | u8 has_temp; /* Bitfield, temp sensors enabled */ |
| 266 | s8 temp[3][3]; /* [nr][0]=temp, [1]=min, [2]=max */ | 268 | s8 temp[3][4]; /* [nr][0]=temp, [1]=min, [2]=max, [3]=offset */ |
| 267 | u8 sensor; /* Register value */ | 269 | u8 sensor; /* Register value */ |
| 268 | u8 fan_div[3]; /* Register encoding, shifted right */ | 270 | u8 fan_div[3]; /* Register encoding, shifted right */ |
| 269 | u8 vid; /* Register encoding, combined */ | 271 | u8 vid; /* Register encoding, combined */ |
| @@ -312,6 +314,17 @@ static inline int has_newer_autopwm(const struct it87_data *data) | |||
| 312 | || data->type == it8728; | 314 | || data->type == it8728; |
| 313 | } | 315 | } |
| 314 | 316 | ||
| 317 | static inline int has_temp_offset(const struct it87_data *data) | ||
| 318 | { | ||
| 319 | return data->type == it8716 | ||
| 320 | || data->type == it8718 | ||
| 321 | || data->type == it8720 | ||
| 322 | || data->type == it8721 | ||
| 323 | || data->type == it8728 | ||
| 324 | || data->type == it8782 | ||
| 325 | || data->type == it8783; | ||
| 326 | } | ||
| 327 | |||
| 315 | static int adc_lsb(const struct it87_data *data, int nr) | 328 | static int adc_lsb(const struct it87_data *data, int nr) |
| 316 | { | 329 | { |
| 317 | int lsb = has_12mv_adc(data) ? 12 : 16; | 330 | int lsb = has_12mv_adc(data) ? 12 : 16; |
| @@ -546,16 +559,34 @@ static ssize_t set_temp(struct device *dev, struct device_attribute *attr, | |||
| 546 | int index = sattr->index; | 559 | int index = sattr->index; |
| 547 | struct it87_data *data = dev_get_drvdata(dev); | 560 | struct it87_data *data = dev_get_drvdata(dev); |
| 548 | long val; | 561 | long val; |
| 562 | u8 reg, regval; | ||
| 549 | 563 | ||
| 550 | if (kstrtol(buf, 10, &val) < 0) | 564 | if (kstrtol(buf, 10, &val) < 0) |
| 551 | return -EINVAL; | 565 | return -EINVAL; |
| 552 | 566 | ||
| 553 | mutex_lock(&data->update_lock); | 567 | mutex_lock(&data->update_lock); |
| 568 | |||
| 569 | switch (index) { | ||
| 570 | default: | ||
| 571 | case 1: | ||
| 572 | reg = IT87_REG_TEMP_LOW(nr); | ||
| 573 | break; | ||
| 574 | case 2: | ||
| 575 | reg = IT87_REG_TEMP_HIGH(nr); | ||
| 576 | break; | ||
| 577 | case 3: | ||
| 578 | regval = it87_read_value(data, IT87_REG_BEEP_ENABLE); | ||
| 579 | if (!(regval & 0x80)) { | ||
| 580 | regval |= 0x80; | ||
| 581 | it87_write_value(data, IT87_REG_BEEP_ENABLE, regval); | ||
| 582 | } | ||
| 583 | data->valid = 0; | ||
| 584 | reg = IT87_REG_TEMP_OFFSET[nr]; | ||
| 585 | break; | ||
| 586 | } | ||
| 587 | |||
| 554 | data->temp[nr][index] = TEMP_TO_REG(val); | 588 | data->temp[nr][index] = TEMP_TO_REG(val); |
| 555 | it87_write_value(data, | 589 | it87_write_value(data, reg, data->temp[nr][index]); |
| 556 | index == 1 ? IT87_REG_TEMP_LOW(nr) | ||
| 557 | : IT87_REG_TEMP_HIGH(nr), | ||
| 558 | data->temp[nr][index]); | ||
| 559 | mutex_unlock(&data->update_lock); | 590 | mutex_unlock(&data->update_lock); |
| 560 | return count; | 591 | return count; |
| 561 | } | 592 | } |
| @@ -565,16 +596,22 @@ static SENSOR_DEVICE_ATTR_2(temp1_min, S_IRUGO | S_IWUSR, show_temp, set_temp, | |||
| 565 | 0, 1); | 596 | 0, 1); |
| 566 | static SENSOR_DEVICE_ATTR_2(temp1_max, S_IRUGO | S_IWUSR, show_temp, set_temp, | 597 | static SENSOR_DEVICE_ATTR_2(temp1_max, S_IRUGO | S_IWUSR, show_temp, set_temp, |
| 567 | 0, 2); | 598 | 0, 2); |
| 599 | static SENSOR_DEVICE_ATTR_2(temp1_offset, S_IRUGO | S_IWUSR, show_temp, | ||
| 600 | set_temp, 0, 3); | ||
| 568 | static SENSOR_DEVICE_ATTR_2(temp2_input, S_IRUGO, show_temp, NULL, 1, 0); | 601 | static SENSOR_DEVICE_ATTR_2(temp2_input, S_IRUGO, show_temp, NULL, 1, 0); |
| 569 | static SENSOR_DEVICE_ATTR_2(temp2_min, S_IRUGO | S_IWUSR, show_temp, set_temp, | 602 | static SENSOR_DEVICE_ATTR_2(temp2_min, S_IRUGO | S_IWUSR, show_temp, set_temp, |
| 570 | 1, 1); | 603 | 1, 1); |
| 571 | static SENSOR_DEVICE_ATTR_2(temp2_max, S_IRUGO | S_IWUSR, show_temp, set_temp, | 604 | static SENSOR_DEVICE_ATTR_2(temp2_max, S_IRUGO | S_IWUSR, show_temp, set_temp, |
| 572 | 1, 2); | 605 | 1, 2); |
| 606 | static SENSOR_DEVICE_ATTR_2(temp2_offset, S_IRUGO | S_IWUSR, show_temp, | ||
| 607 | set_temp, 1, 3); | ||
| 573 | static SENSOR_DEVICE_ATTR_2(temp3_input, S_IRUGO, show_temp, NULL, 2, 0); | 608 | static SENSOR_DEVICE_ATTR_2(temp3_input, S_IRUGO, show_temp, NULL, 2, 0); |
| 574 | static SENSOR_DEVICE_ATTR_2(temp3_min, S_IRUGO | S_IWUSR, show_temp, set_temp, | 609 | static SENSOR_DEVICE_ATTR_2(temp3_min, S_IRUGO | S_IWUSR, show_temp, set_temp, |
| 575 | 2, 1); | 610 | 2, 1); |
| 576 | static SENSOR_DEVICE_ATTR_2(temp3_max, S_IRUGO | S_IWUSR, show_temp, set_temp, | 611 | static SENSOR_DEVICE_ATTR_2(temp3_max, S_IRUGO | S_IWUSR, show_temp, set_temp, |
| 577 | 2, 2); | 612 | 2, 2); |
| 613 | static SENSOR_DEVICE_ATTR_2(temp3_offset, S_IRUGO | S_IWUSR, show_temp, | ||
| 614 | set_temp, 2, 3); | ||
| 578 | 615 | ||
| 579 | static ssize_t show_temp_type(struct device *dev, struct device_attribute *attr, | 616 | static ssize_t show_temp_type(struct device *dev, struct device_attribute *attr, |
| 580 | char *buf) | 617 | char *buf) |
| @@ -1429,6 +1466,12 @@ static const struct attribute_group it87_group_temp[3] = { | |||
| 1429 | { .attrs = it87_attributes_temp[2] }, | 1466 | { .attrs = it87_attributes_temp[2] }, |
| 1430 | }; | 1467 | }; |
| 1431 | 1468 | ||
| 1469 | static struct attribute *it87_attributes_temp_offset[] = { | ||
| 1470 | &sensor_dev_attr_temp1_offset.dev_attr.attr, | ||
| 1471 | &sensor_dev_attr_temp2_offset.dev_attr.attr, | ||
| 1472 | &sensor_dev_attr_temp3_offset.dev_attr.attr, | ||
| 1473 | }; | ||
| 1474 | |||
| 1432 | static struct attribute *it87_attributes[] = { | 1475 | static struct attribute *it87_attributes[] = { |
| 1433 | &dev_attr_alarms.attr, | 1476 | &dev_attr_alarms.attr, |
| 1434 | &sensor_dev_attr_intrusion0_alarm.dev_attr.attr, | 1477 | &sensor_dev_attr_intrusion0_alarm.dev_attr.attr, |
| @@ -1899,6 +1942,9 @@ static void it87_remove_files(struct device *dev) | |||
| 1899 | if (!(data->has_temp & (1 << i))) | 1942 | if (!(data->has_temp & (1 << i))) |
| 1900 | continue; | 1943 | continue; |
| 1901 | sysfs_remove_group(&dev->kobj, &it87_group_temp[i]); | 1944 | sysfs_remove_group(&dev->kobj, &it87_group_temp[i]); |
| 1945 | if (has_temp_offset(data)) | ||
| 1946 | sysfs_remove_file(&dev->kobj, | ||
| 1947 | it87_attributes_temp_offset[i]); | ||
| 1902 | if (sio_data->beep_pin) | 1948 | if (sio_data->beep_pin) |
| 1903 | sysfs_remove_file(&dev->kobj, | 1949 | sysfs_remove_file(&dev->kobj, |
| 1904 | it87_attributes_temp_beep[i]); | 1950 | it87_attributes_temp_beep[i]); |
| @@ -2026,6 +2072,12 @@ static int it87_probe(struct platform_device *pdev) | |||
| 2026 | err = sysfs_create_group(&dev->kobj, &it87_group_temp[i]); | 2072 | err = sysfs_create_group(&dev->kobj, &it87_group_temp[i]); |
| 2027 | if (err) | 2073 | if (err) |
| 2028 | goto error; | 2074 | goto error; |
| 2075 | if (has_temp_offset(data)) { | ||
| 2076 | err = sysfs_create_file(&dev->kobj, | ||
| 2077 | it87_attributes_temp_offset[i]); | ||
| 2078 | if (err) | ||
| 2079 | goto error; | ||
| 2080 | } | ||
| 2029 | if (sio_data->beep_pin) { | 2081 | if (sio_data->beep_pin) { |
| 2030 | err = sysfs_create_file(&dev->kobj, | 2082 | err = sysfs_create_file(&dev->kobj, |
| 2031 | it87_attributes_temp_beep[i]); | 2083 | it87_attributes_temp_beep[i]); |
| @@ -2383,6 +2435,10 @@ static struct it87_data *it87_update_device(struct device *dev) | |||
| 2383 | it87_read_value(data, IT87_REG_TEMP_LOW(i)); | 2435 | it87_read_value(data, IT87_REG_TEMP_LOW(i)); |
| 2384 | data->temp[i][2] = | 2436 | data->temp[i][2] = |
| 2385 | it87_read_value(data, IT87_REG_TEMP_HIGH(i)); | 2437 | it87_read_value(data, IT87_REG_TEMP_HIGH(i)); |
| 2438 | if (has_temp_offset(data)) | ||
| 2439 | data->temp[i][3] = | ||
| 2440 | it87_read_value(data, | ||
| 2441 | IT87_REG_TEMP_OFFSET[i]); | ||
| 2386 | } | 2442 | } |
| 2387 | 2443 | ||
| 2388 | /* Newer chips don't have clock dividers */ | 2444 | /* Newer chips don't have clock dividers */ |
