Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

i8k: Implement hwmon based fan speed control

Fan speed can be set to off, slow, and fast, which can be exported
to userspace through the hwmon ABI as pwm1 / pwm2.

Cc: Jean Delvare <khali@linux-fr.org>
Signed-off-by: Guenter Roeck <linux@roeck-us.net>
Acked-by: Arnd Bergmann <arnd@arndb.de>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>

authored by

Guenter Roeck and committed by
Greg Kroah-Hartman
e7f5f275 e551b152

+44 -5
+44 -5
drivers/char/i8k.c
··· 509 509 return sprintf(buf, "%d\n", fan_speed); 510 510 } 511 511 512 + static ssize_t i8k_hwmon_show_pwm(struct device *dev, 513 + struct device_attribute *devattr, 514 + char *buf) 515 + { 516 + int index = to_sensor_dev_attr(devattr)->index; 517 + int status; 518 + 519 + status = i8k_get_fan_status(index); 520 + if (status < 0) 521 + return -EIO; 522 + return sprintf(buf, "%d\n", clamp_val(status * 128, 0, 255)); 523 + } 524 + 525 + static ssize_t i8k_hwmon_set_pwm(struct device *dev, 526 + struct device_attribute *attr, 527 + const char *buf, size_t count) 528 + { 529 + int index = to_sensor_dev_attr(attr)->index; 530 + unsigned long val; 531 + int err; 532 + 533 + err = kstrtoul(buf, 10, &val); 534 + if (err) 535 + return err; 536 + val = clamp_val(DIV_ROUND_CLOSEST(val, 128), 0, 2); 537 + 538 + mutex_lock(&i8k_mutex); 539 + err = i8k_set_fan(index, val); 540 + mutex_unlock(&i8k_mutex); 541 + 542 + return err < 0 ? -EIO : count; 543 + } 544 + 512 545 static ssize_t i8k_hwmon_show_label(struct device *dev, 513 546 struct device_attribute *devattr, 514 547 char *buf) ··· 562 529 static SENSOR_DEVICE_ATTR(temp4_input, S_IRUGO, i8k_hwmon_show_temp, NULL, 3); 563 530 static SENSOR_DEVICE_ATTR(fan1_input, S_IRUGO, i8k_hwmon_show_fan, NULL, 564 531 I8K_FAN_LEFT); 532 + static SENSOR_DEVICE_ATTR(pwm1, S_IRUGO | S_IWUSR, i8k_hwmon_show_pwm, 533 + i8k_hwmon_set_pwm, I8K_FAN_LEFT); 565 534 static SENSOR_DEVICE_ATTR(fan2_input, S_IRUGO, i8k_hwmon_show_fan, NULL, 566 535 I8K_FAN_RIGHT); 536 + static SENSOR_DEVICE_ATTR(pwm2, S_IRUGO | S_IWUSR, i8k_hwmon_show_pwm, 537 + i8k_hwmon_set_pwm, I8K_FAN_RIGHT); 567 538 static SENSOR_DEVICE_ATTR(temp1_label, S_IRUGO, i8k_hwmon_show_label, NULL, 0); 568 539 static SENSOR_DEVICE_ATTR(fan1_label, S_IRUGO, i8k_hwmon_show_label, NULL, 1); 569 540 static SENSOR_DEVICE_ATTR(fan2_label, S_IRUGO, i8k_hwmon_show_label, NULL, 2); ··· 579 542 &sensor_dev_attr_temp3_input.dev_attr.attr, /* 3 */ 580 543 &sensor_dev_attr_temp4_input.dev_attr.attr, /* 4 */ 581 544 &sensor_dev_attr_fan1_input.dev_attr.attr, /* 5 */ 582 - &sensor_dev_attr_fan1_label.dev_attr.attr, /* 6 */ 583 - &sensor_dev_attr_fan2_input.dev_attr.attr, /* 7 */ 584 - &sensor_dev_attr_fan2_label.dev_attr.attr, /* 8 */ 545 + &sensor_dev_attr_pwm1.dev_attr.attr, /* 6 */ 546 + &sensor_dev_attr_fan1_label.dev_attr.attr, /* 7 */ 547 + &sensor_dev_attr_fan2_input.dev_attr.attr, /* 8 */ 548 + &sensor_dev_attr_pwm2.dev_attr.attr, /* 9 */ 549 + &sensor_dev_attr_fan2_label.dev_attr.attr, /* 10 */ 585 550 NULL 586 551 }; 587 552 ··· 599 560 return 0; 600 561 if (index == 4 && !(i8k_hwmon_flags & I8K_HWMON_HAVE_TEMP4)) 601 562 return 0; 602 - if ((index == 5 || index == 6) && 563 + if (index >= 5 && index <= 7 && 603 564 !(i8k_hwmon_flags & I8K_HWMON_HAVE_FAN1)) 604 565 return 0; 605 - if ((index == 7 || index == 8) && 566 + if (index >= 8 && index <= 10 && 606 567 !(i8k_hwmon_flags & I8K_HWMON_HAVE_FAN2)) 607 568 return 0; 608 569