diff options
-rw-r--r-- | Documentation/laptops/thinkpad-acpi.txt | 10 | ||||
-rw-r--r-- | drivers/platform/x86/thinkpad_acpi.c | 122 |
2 files changed, 130 insertions, 2 deletions
diff --git a/Documentation/laptops/thinkpad-acpi.txt b/Documentation/laptops/thinkpad-acpi.txt index f2ff638cce8d..0d5e91379ae8 100644 --- a/Documentation/laptops/thinkpad-acpi.txt +++ b/Documentation/laptops/thinkpad-acpi.txt | |||
@@ -1269,7 +1269,7 @@ Fan control and monitoring: fan speed, fan enable/disable | |||
1269 | 1269 | ||
1270 | procfs: /proc/acpi/ibm/fan | 1270 | procfs: /proc/acpi/ibm/fan |
1271 | sysfs device attributes: (hwmon "thinkpad") fan1_input, pwm1, | 1271 | sysfs device attributes: (hwmon "thinkpad") fan1_input, pwm1, |
1272 | pwm1_enable | 1272 | pwm1_enable, fan2_input |
1273 | sysfs hwmon driver attributes: fan_watchdog | 1273 | sysfs hwmon driver attributes: fan_watchdog |
1274 | 1274 | ||
1275 | NOTE NOTE NOTE: fan control operations are disabled by default for | 1275 | NOTE NOTE NOTE: fan control operations are disabled by default for |
@@ -1282,6 +1282,9 @@ from the hardware registers of the embedded controller. This is known | |||
1282 | to work on later R, T, X and Z series ThinkPads but may show a bogus | 1282 | to work on later R, T, X and Z series ThinkPads but may show a bogus |
1283 | value on other models. | 1283 | value on other models. |
1284 | 1284 | ||
1285 | Some Lenovo ThinkPads support a secondary fan. This fan cannot be | ||
1286 | controlled separately, it shares the main fan control. | ||
1287 | |||
1285 | Fan levels: | 1288 | Fan levels: |
1286 | 1289 | ||
1287 | Most ThinkPad fans work in "levels" at the firmware interface. Level 0 | 1290 | Most ThinkPad fans work in "levels" at the firmware interface. Level 0 |
@@ -1412,6 +1415,11 @@ hwmon device attribute fan1_input: | |||
1412 | which can take up to two minutes. May return rubbish on older | 1415 | which can take up to two minutes. May return rubbish on older |
1413 | ThinkPads. | 1416 | ThinkPads. |
1414 | 1417 | ||
1418 | hwmon device attribute fan2_input: | ||
1419 | Fan tachometer reading, in RPM, for the secondary fan. | ||
1420 | Available only on some ThinkPads. If the secondary fan is | ||
1421 | not installed, will always read 0. | ||
1422 | |||
1415 | hwmon driver attribute fan_watchdog: | 1423 | hwmon driver attribute fan_watchdog: |
1416 | Fan safety watchdog timer interval, in seconds. Minimum is | 1424 | Fan safety watchdog timer interval, in seconds. Minimum is |
1417 | 1 second, maximum is 120 seconds. 0 disables the watchdog. | 1425 | 1 second, maximum is 120 seconds. 0 disables the watchdog. |
diff --git a/drivers/platform/x86/thinkpad_acpi.c b/drivers/platform/x86/thinkpad_acpi.c index c8d74dbacbbd..27ca676a7092 100644 --- a/drivers/platform/x86/thinkpad_acpi.c +++ b/drivers/platform/x86/thinkpad_acpi.c | |||
@@ -264,6 +264,7 @@ static struct { | |||
264 | u32 wan:1; | 264 | u32 wan:1; |
265 | u32 uwb:1; | 265 | u32 uwb:1; |
266 | u32 fan_ctrl_status_undef:1; | 266 | u32 fan_ctrl_status_undef:1; |
267 | u32 second_fan:1; | ||
267 | u32 beep_needs_two_args:1; | 268 | u32 beep_needs_two_args:1; |
268 | u32 input_device_registered:1; | 269 | u32 input_device_registered:1; |
269 | u32 platform_drv_registered:1; | 270 | u32 platform_drv_registered:1; |
@@ -6298,6 +6299,21 @@ static struct ibm_struct volume_driver_data = { | |||
6298 | * For firmware bugs, refer to: | 6299 | * For firmware bugs, refer to: |
6299 | * http://thinkwiki.org/wiki/Embedded_Controller_Firmware#Firmware_Issues | 6300 | * http://thinkwiki.org/wiki/Embedded_Controller_Firmware#Firmware_Issues |
6300 | * | 6301 | * |
6302 | * ---- | ||
6303 | * | ||
6304 | * ThinkPad EC register 0x31 bit 0 (only on select models) | ||
6305 | * | ||
6306 | * When bit 0 of EC register 0x31 is zero, the tachometer registers | ||
6307 | * show the speed of the main fan. When bit 0 of EC register 0x31 | ||
6308 | * is one, the tachometer registers show the speed of the auxiliary | ||
6309 | * fan. | ||
6310 | * | ||
6311 | * Fan control seems to affect both fans, regardless of the state | ||
6312 | * of this bit. | ||
6313 | * | ||
6314 | * So far, only the firmware for the X60/X61 non-tablet versions | ||
6315 | * seem to support this (firmware TP-7M). | ||
6316 | * | ||
6301 | * TPACPI_FAN_WR_ACPI_FANS: | 6317 | * TPACPI_FAN_WR_ACPI_FANS: |
6302 | * ThinkPad X31, X40, X41. Not available in the X60. | 6318 | * ThinkPad X31, X40, X41. Not available in the X60. |
6303 | * | 6319 | * |
@@ -6324,6 +6340,8 @@ enum { /* Fan control constants */ | |||
6324 | fan_status_offset = 0x2f, /* EC register 0x2f */ | 6340 | fan_status_offset = 0x2f, /* EC register 0x2f */ |
6325 | fan_rpm_offset = 0x84, /* EC register 0x84: LSB, 0x85 MSB (RPM) | 6341 | fan_rpm_offset = 0x84, /* EC register 0x84: LSB, 0x85 MSB (RPM) |
6326 | * 0x84 must be read before 0x85 */ | 6342 | * 0x84 must be read before 0x85 */ |
6343 | fan_select_offset = 0x31, /* EC register 0x31 (Firmware 7M) | ||
6344 | bit 0 selects which fan is active */ | ||
6327 | 6345 | ||
6328 | TP_EC_FAN_FULLSPEED = 0x40, /* EC fan mode: full speed */ | 6346 | TP_EC_FAN_FULLSPEED = 0x40, /* EC fan mode: full speed */ |
6329 | TP_EC_FAN_AUTO = 0x80, /* EC fan mode: auto fan control */ | 6347 | TP_EC_FAN_AUTO = 0x80, /* EC fan mode: auto fan control */ |
@@ -6417,6 +6435,38 @@ static void fan_quirk1_handle(u8 *fan_status) | |||
6417 | } | 6435 | } |
6418 | } | 6436 | } |
6419 | 6437 | ||
6438 | /* Select main fan on X60/X61, NOOP on others */ | ||
6439 | static bool fan_select_fan1(void) | ||
6440 | { | ||
6441 | if (tp_features.second_fan) { | ||
6442 | u8 val; | ||
6443 | |||
6444 | if (ec_read(fan_select_offset, &val) < 0) | ||
6445 | return false; | ||
6446 | val &= 0xFEU; | ||
6447 | if (ec_write(fan_select_offset, val) < 0) | ||
6448 | return false; | ||
6449 | } | ||
6450 | return true; | ||
6451 | } | ||
6452 | |||
6453 | /* Select secondary fan on X60/X61 */ | ||
6454 | static bool fan_select_fan2(void) | ||
6455 | { | ||
6456 | u8 val; | ||
6457 | |||
6458 | if (!tp_features.second_fan) | ||
6459 | return false; | ||
6460 | |||
6461 | if (ec_read(fan_select_offset, &val) < 0) | ||
6462 | return false; | ||
6463 | val |= 0x01U; | ||
6464 | if (ec_write(fan_select_offset, val) < 0) | ||
6465 | return false; | ||
6466 | |||
6467 | return true; | ||
6468 | } | ||
6469 | |||
6420 | /* | 6470 | /* |
6421 | * Call with fan_mutex held | 6471 | * Call with fan_mutex held |
6422 | */ | 6472 | */ |
@@ -6494,6 +6544,8 @@ static int fan_get_speed(unsigned int *speed) | |||
6494 | switch (fan_status_access_mode) { | 6544 | switch (fan_status_access_mode) { |
6495 | case TPACPI_FAN_RD_TPEC: | 6545 | case TPACPI_FAN_RD_TPEC: |
6496 | /* all except 570, 600e/x, 770e, 770x */ | 6546 | /* all except 570, 600e/x, 770e, 770x */ |
6547 | if (unlikely(!fan_select_fan1())) | ||
6548 | return -EIO; | ||
6497 | if (unlikely(!acpi_ec_read(fan_rpm_offset, &lo) || | 6549 | if (unlikely(!acpi_ec_read(fan_rpm_offset, &lo) || |
6498 | !acpi_ec_read(fan_rpm_offset + 1, &hi))) | 6550 | !acpi_ec_read(fan_rpm_offset + 1, &hi))) |
6499 | return -EIO; | 6551 | return -EIO; |
@@ -6510,6 +6562,34 @@ static int fan_get_speed(unsigned int *speed) | |||
6510 | return 0; | 6562 | return 0; |
6511 | } | 6563 | } |
6512 | 6564 | ||
6565 | static int fan2_get_speed(unsigned int *speed) | ||
6566 | { | ||
6567 | u8 hi, lo; | ||
6568 | bool rc; | ||
6569 | |||
6570 | switch (fan_status_access_mode) { | ||
6571 | case TPACPI_FAN_RD_TPEC: | ||
6572 | /* all except 570, 600e/x, 770e, 770x */ | ||
6573 | if (unlikely(!fan_select_fan2())) | ||
6574 | return -EIO; | ||
6575 | rc = !acpi_ec_read(fan_rpm_offset, &lo) || | ||
6576 | !acpi_ec_read(fan_rpm_offset + 1, &hi); | ||
6577 | fan_select_fan1(); /* play it safe */ | ||
6578 | if (rc) | ||
6579 | return -EIO; | ||
6580 | |||
6581 | if (likely(speed)) | ||
6582 | *speed = (hi << 8) | lo; | ||
6583 | |||
6584 | break; | ||
6585 | |||
6586 | default: | ||
6587 | return -ENXIO; | ||
6588 | } | ||
6589 | |||
6590 | return 0; | ||
6591 | } | ||
6592 | |||
6513 | static int fan_set_level(int level) | 6593 | static int fan_set_level(int level) |
6514 | { | 6594 | { |
6515 | if (!fan_control_allowed) | 6595 | if (!fan_control_allowed) |
@@ -6915,6 +6995,25 @@ static struct device_attribute dev_attr_fan_fan1_input = | |||
6915 | __ATTR(fan1_input, S_IRUGO, | 6995 | __ATTR(fan1_input, S_IRUGO, |
6916 | fan_fan1_input_show, NULL); | 6996 | fan_fan1_input_show, NULL); |
6917 | 6997 | ||
6998 | /* sysfs fan fan2_input ------------------------------------------------ */ | ||
6999 | static ssize_t fan_fan2_input_show(struct device *dev, | ||
7000 | struct device_attribute *attr, | ||
7001 | char *buf) | ||
7002 | { | ||
7003 | int res; | ||
7004 | unsigned int speed; | ||
7005 | |||
7006 | res = fan2_get_speed(&speed); | ||
7007 | if (res < 0) | ||
7008 | return res; | ||
7009 | |||
7010 | return snprintf(buf, PAGE_SIZE, "%u\n", speed); | ||
7011 | } | ||
7012 | |||
7013 | static struct device_attribute dev_attr_fan_fan2_input = | ||
7014 | __ATTR(fan2_input, S_IRUGO, | ||
7015 | fan_fan2_input_show, NULL); | ||
7016 | |||
6918 | /* sysfs fan fan_watchdog (hwmon driver) ------------------------------- */ | 7017 | /* sysfs fan fan_watchdog (hwmon driver) ------------------------------- */ |
6919 | static ssize_t fan_fan_watchdog_show(struct device_driver *drv, | 7018 | static ssize_t fan_fan_watchdog_show(struct device_driver *drv, |
6920 | char *buf) | 7019 | char *buf) |
@@ -6948,6 +7047,7 @@ static DRIVER_ATTR(fan_watchdog, S_IWUSR | S_IRUGO, | |||
6948 | static struct attribute *fan_attributes[] = { | 7047 | static struct attribute *fan_attributes[] = { |
6949 | &dev_attr_fan_pwm1_enable.attr, &dev_attr_fan_pwm1.attr, | 7048 | &dev_attr_fan_pwm1_enable.attr, &dev_attr_fan_pwm1.attr, |
6950 | &dev_attr_fan_fan1_input.attr, | 7049 | &dev_attr_fan_fan1_input.attr, |
7050 | NULL, /* for fan2_input */ | ||
6951 | NULL | 7051 | NULL |
6952 | }; | 7052 | }; |
6953 | 7053 | ||
@@ -6955,7 +7055,8 @@ static const struct attribute_group fan_attr_group = { | |||
6955 | .attrs = fan_attributes, | 7055 | .attrs = fan_attributes, |
6956 | }; | 7056 | }; |
6957 | 7057 | ||
6958 | #define TPACPI_FAN_Q1 0x0001 | 7058 | #define TPACPI_FAN_Q1 0x0001 /* Unitialized HFSP */ |
7059 | #define TPACPI_FAN_2FAN 0x0002 /* EC 0x31 bit 0 selects fan2 */ | ||
6959 | 7060 | ||
6960 | #define TPACPI_FAN_QI(__id1, __id2, __quirks) \ | 7061 | #define TPACPI_FAN_QI(__id1, __id2, __quirks) \ |
6961 | { .vendor = PCI_VENDOR_ID_IBM, \ | 7062 | { .vendor = PCI_VENDOR_ID_IBM, \ |
@@ -6963,13 +7064,21 @@ static const struct attribute_group fan_attr_group = { | |||
6963 | .ec = TPID(__id1, __id2), \ | 7064 | .ec = TPID(__id1, __id2), \ |
6964 | .quirks = __quirks } | 7065 | .quirks = __quirks } |
6965 | 7066 | ||
7067 | #define TPACPI_FAN_QL(__id1, __id2, __quirks) \ | ||
7068 | { .vendor = PCI_VENDOR_ID_LENOVO, \ | ||
7069 | .bios = TPACPI_MATCH_ANY, \ | ||
7070 | .ec = TPID(__id1, __id2), \ | ||
7071 | .quirks = __quirks } | ||
7072 | |||
6966 | static const struct tpacpi_quirk fan_quirk_table[] __initconst = { | 7073 | static const struct tpacpi_quirk fan_quirk_table[] __initconst = { |
6967 | TPACPI_FAN_QI('1', 'Y', TPACPI_FAN_Q1), | 7074 | TPACPI_FAN_QI('1', 'Y', TPACPI_FAN_Q1), |
6968 | TPACPI_FAN_QI('7', '8', TPACPI_FAN_Q1), | 7075 | TPACPI_FAN_QI('7', '8', TPACPI_FAN_Q1), |
6969 | TPACPI_FAN_QI('7', '6', TPACPI_FAN_Q1), | 7076 | TPACPI_FAN_QI('7', '6', TPACPI_FAN_Q1), |
6970 | TPACPI_FAN_QI('7', '0', TPACPI_FAN_Q1), | 7077 | TPACPI_FAN_QI('7', '0', TPACPI_FAN_Q1), |
7078 | TPACPI_FAN_QL('7', 'M', TPACPI_FAN_2FAN), | ||
6971 | }; | 7079 | }; |
6972 | 7080 | ||
7081 | #undef TPACPI_FAN_QL | ||
6973 | #undef TPACPI_FAN_QI | 7082 | #undef TPACPI_FAN_QI |
6974 | 7083 | ||
6975 | static int __init fan_init(struct ibm_init_struct *iibm) | 7084 | static int __init fan_init(struct ibm_init_struct *iibm) |
@@ -6986,6 +7095,7 @@ static int __init fan_init(struct ibm_init_struct *iibm) | |||
6986 | fan_control_commands = 0; | 7095 | fan_control_commands = 0; |
6987 | fan_watchdog_maxinterval = 0; | 7096 | fan_watchdog_maxinterval = 0; |
6988 | tp_features.fan_ctrl_status_undef = 0; | 7097 | tp_features.fan_ctrl_status_undef = 0; |
7098 | tp_features.second_fan = 0; | ||
6989 | fan_control_desired_level = 7; | 7099 | fan_control_desired_level = 7; |
6990 | 7100 | ||
6991 | TPACPI_ACPIHANDLE_INIT(fans); | 7101 | TPACPI_ACPIHANDLE_INIT(fans); |
@@ -7006,6 +7116,11 @@ static int __init fan_init(struct ibm_init_struct *iibm) | |||
7006 | fan_status_access_mode = TPACPI_FAN_RD_TPEC; | 7116 | fan_status_access_mode = TPACPI_FAN_RD_TPEC; |
7007 | if (quirks & TPACPI_FAN_Q1) | 7117 | if (quirks & TPACPI_FAN_Q1) |
7008 | fan_quirk1_setup(); | 7118 | fan_quirk1_setup(); |
7119 | if (quirks & TPACPI_FAN_2FAN) { | ||
7120 | tp_features.second_fan = 1; | ||
7121 | dbg_printk(TPACPI_DBG_INIT | TPACPI_DBG_FAN, | ||
7122 | "secondary fan support enabled\n"); | ||
7123 | } | ||
7009 | } else { | 7124 | } else { |
7010 | printk(TPACPI_ERR | 7125 | printk(TPACPI_ERR |
7011 | "ThinkPad ACPI EC access misbehaving, " | 7126 | "ThinkPad ACPI EC access misbehaving, " |
@@ -7061,6 +7176,11 @@ static int __init fan_init(struct ibm_init_struct *iibm) | |||
7061 | 7176 | ||
7062 | if (fan_status_access_mode != TPACPI_FAN_NONE || | 7177 | if (fan_status_access_mode != TPACPI_FAN_NONE || |
7063 | fan_control_access_mode != TPACPI_FAN_WR_NONE) { | 7178 | fan_control_access_mode != TPACPI_FAN_WR_NONE) { |
7179 | if (tp_features.second_fan) { | ||
7180 | /* attach second fan tachometer */ | ||
7181 | fan_attributes[ARRAY_SIZE(fan_attributes)-2] = | ||
7182 | &dev_attr_fan_fan2_input.attr; | ||
7183 | } | ||
7064 | rc = sysfs_create_group(&tpacpi_sensors_pdev->dev.kobj, | 7184 | rc = sysfs_create_group(&tpacpi_sensors_pdev->dev.kobj, |
7065 | &fan_attr_group); | 7185 | &fan_attr_group); |
7066 | if (rc < 0) | 7186 | if (rc < 0) |