diff options
| -rw-r--r-- | drivers/platform/x86/thinkpad_acpi.c | 109 |
1 files changed, 58 insertions, 51 deletions
diff --git a/drivers/platform/x86/thinkpad_acpi.c b/drivers/platform/x86/thinkpad_acpi.c index d7d41ae2f299..213219d938e8 100644 --- a/drivers/platform/x86/thinkpad_acpi.c +++ b/drivers/platform/x86/thinkpad_acpi.c | |||
| @@ -5897,6 +5897,60 @@ TPACPI_HANDLE(sfan, ec, "SFAN", /* 570 */ | |||
| 5897 | ); /* all others */ | 5897 | ); /* all others */ |
| 5898 | 5898 | ||
| 5899 | /* | 5899 | /* |
| 5900 | * Unitialized HFSP quirk: ACPI DSDT and EC fail to initialize the | ||
| 5901 | * HFSP register at boot, so it contains 0x07 but the Thinkpad could | ||
| 5902 | * be in auto mode (0x80). | ||
| 5903 | * | ||
| 5904 | * This is corrected by any write to HFSP either by the driver, or | ||
| 5905 | * by the firmware. | ||
| 5906 | * | ||
| 5907 | * We assume 0x07 really means auto mode while this quirk is active, | ||
| 5908 | * as this is far more likely than the ThinkPad being in level 7, | ||
| 5909 | * which is only used by the firmware during thermal emergencies. | ||
| 5910 | */ | ||
| 5911 | |||
| 5912 | static void fan_quirk1_detect(void) | ||
| 5913 | { | ||
| 5914 | /* In some ThinkPads, neither the EC nor the ACPI | ||
| 5915 | * DSDT initialize the HFSP register, and it ends up | ||
| 5916 | * being initially set to 0x07 when it *could* be | ||
| 5917 | * either 0x07 or 0x80. | ||
| 5918 | * | ||
| 5919 | * Enable for TP-1Y (T43), TP-78 (R51e), | ||
| 5920 | * TP-76 (R52), TP-70 (T43, R52), which are known | ||
| 5921 | * to be buggy. */ | ||
| 5922 | if (fan_control_initial_status == 0x07) { | ||
| 5923 | switch (thinkpad_id.ec_model) { | ||
| 5924 | case 0x5931: /* TP-1Y */ | ||
| 5925 | case 0x3837: /* TP-78 */ | ||
| 5926 | case 0x3637: /* TP-76 */ | ||
| 5927 | case 0x3037: /* TP-70 */ | ||
| 5928 | printk(TPACPI_NOTICE | ||
| 5929 | "fan_init: initial fan status is unknown, " | ||
| 5930 | "assuming it is in auto mode\n"); | ||
| 5931 | tp_features.fan_ctrl_status_undef = 1; | ||
| 5932 | ;; | ||
| 5933 | } | ||
| 5934 | } | ||
| 5935 | } | ||
| 5936 | |||
| 5937 | static void fan_quirk1_handle(u8 *fan_status) | ||
| 5938 | { | ||
| 5939 | if (unlikely(tp_features.fan_ctrl_status_undef)) { | ||
| 5940 | if (*fan_status != fan_control_initial_status) { | ||
| 5941 | /* something changed the HFSP regisnter since | ||
| 5942 | * driver init time, so it is not undefined | ||
| 5943 | * anymore */ | ||
| 5944 | tp_features.fan_ctrl_status_undef = 0; | ||
| 5945 | } else { | ||
| 5946 | /* Return most likely status. In fact, it | ||
| 5947 | * might be the only possible status */ | ||
| 5948 | *fan_status = TP_EC_FAN_AUTO; | ||
| 5949 | } | ||
| 5950 | } | ||
| 5951 | } | ||
| 5952 | |||
| 5953 | /* | ||
| 5900 | * Call with fan_mutex held | 5954 | * Call with fan_mutex held |
| 5901 | */ | 5955 | */ |
| 5902 | static void fan_update_desired_level(u8 status) | 5956 | static void fan_update_desired_level(u8 status) |
| @@ -5934,8 +5988,10 @@ static int fan_get_status(u8 *status) | |||
| 5934 | if (unlikely(!acpi_ec_read(fan_status_offset, &s))) | 5988 | if (unlikely(!acpi_ec_read(fan_status_offset, &s))) |
| 5935 | return -EIO; | 5989 | return -EIO; |
| 5936 | 5990 | ||
| 5937 | if (likely(status)) | 5991 | if (likely(status)) { |
| 5938 | *status = s; | 5992 | *status = s; |
| 5993 | fan_quirk1_handle(status); | ||
| 5994 | } | ||
| 5939 | 5995 | ||
| 5940 | break; | 5996 | break; |
| 5941 | 5997 | ||
| @@ -6245,16 +6301,6 @@ static ssize_t fan_pwm1_enable_show(struct device *dev, | |||
| 6245 | if (res) | 6301 | if (res) |
| 6246 | return res; | 6302 | return res; |
| 6247 | 6303 | ||
| 6248 | if (unlikely(tp_features.fan_ctrl_status_undef)) { | ||
| 6249 | if (status != fan_control_initial_status) { | ||
| 6250 | tp_features.fan_ctrl_status_undef = 0; | ||
| 6251 | } else { | ||
| 6252 | /* Return most likely status. In fact, it | ||
| 6253 | * might be the only possible status */ | ||
| 6254 | status = TP_EC_FAN_AUTO; | ||
| 6255 | } | ||
| 6256 | } | ||
| 6257 | |||
| 6258 | if (status & TP_EC_FAN_FULLSPEED) { | 6304 | if (status & TP_EC_FAN_FULLSPEED) { |
| 6259 | mode = 0; | 6305 | mode = 0; |
| 6260 | } else if (status & TP_EC_FAN_AUTO) { | 6306 | } else if (status & TP_EC_FAN_AUTO) { |
| @@ -6319,14 +6365,6 @@ static ssize_t fan_pwm1_show(struct device *dev, | |||
| 6319 | if (res) | 6365 | if (res) |
| 6320 | return res; | 6366 | return res; |
| 6321 | 6367 | ||
| 6322 | if (unlikely(tp_features.fan_ctrl_status_undef)) { | ||
| 6323 | if (status != fan_control_initial_status) { | ||
| 6324 | tp_features.fan_ctrl_status_undef = 0; | ||
| 6325 | } else { | ||
| 6326 | status = TP_EC_FAN_AUTO; | ||
| 6327 | } | ||
| 6328 | } | ||
| 6329 | |||
| 6330 | if ((status & | 6368 | if ((status & |
| 6331 | (TP_EC_FAN_AUTO | TP_EC_FAN_FULLSPEED)) != 0) | 6369 | (TP_EC_FAN_AUTO | TP_EC_FAN_FULLSPEED)) != 0) |
| 6332 | status = fan_control_desired_level; | 6370 | status = fan_control_desired_level; |
| @@ -6458,29 +6496,7 @@ static int __init fan_init(struct ibm_init_struct *iibm) | |||
| 6458 | if (likely(acpi_ec_read(fan_status_offset, | 6496 | if (likely(acpi_ec_read(fan_status_offset, |
| 6459 | &fan_control_initial_status))) { | 6497 | &fan_control_initial_status))) { |
| 6460 | fan_status_access_mode = TPACPI_FAN_RD_TPEC; | 6498 | fan_status_access_mode = TPACPI_FAN_RD_TPEC; |
| 6461 | 6499 | fan_quirk1_detect(); | |
| 6462 | /* In some ThinkPads, neither the EC nor the ACPI | ||
| 6463 | * DSDT initialize the fan status, and it ends up | ||
| 6464 | * being set to 0x07 when it *could* be either | ||
| 6465 | * 0x07 or 0x80. | ||
| 6466 | * | ||
| 6467 | * Enable for TP-1Y (T43), TP-78 (R51e), | ||
| 6468 | * TP-76 (R52), TP-70 (T43, R52), which are known | ||
| 6469 | * to be buggy. */ | ||
| 6470 | if (fan_control_initial_status == 0x07) { | ||
| 6471 | switch (thinkpad_id.ec_model) { | ||
| 6472 | case 0x5931: /* TP-1Y */ | ||
| 6473 | case 0x3837: /* TP-78 */ | ||
| 6474 | case 0x3637: /* TP-76 */ | ||
| 6475 | case 0x3037: /* TP-70 */ | ||
| 6476 | printk(TPACPI_NOTICE | ||
| 6477 | "fan_init: initial fan status " | ||
| 6478 | "is unknown, assuming it is " | ||
| 6479 | "in auto mode\n"); | ||
| 6480 | tp_features.fan_ctrl_status_undef = 1; | ||
| 6481 | ;; | ||
| 6482 | } | ||
| 6483 | } | ||
| 6484 | } else { | 6500 | } else { |
| 6485 | printk(TPACPI_ERR | 6501 | printk(TPACPI_ERR |
| 6486 | "ThinkPad ACPI EC access misbehaving, " | 6502 | "ThinkPad ACPI EC access misbehaving, " |
| @@ -6669,15 +6685,6 @@ static int fan_read(char *p) | |||
| 6669 | if (rc < 0) | 6685 | if (rc < 0) |
| 6670 | return rc; | 6686 | return rc; |
| 6671 | 6687 | ||
| 6672 | if (unlikely(tp_features.fan_ctrl_status_undef)) { | ||
| 6673 | if (status != fan_control_initial_status) | ||
| 6674 | tp_features.fan_ctrl_status_undef = 0; | ||
| 6675 | else | ||
| 6676 | /* Return most likely status. In fact, it | ||
| 6677 | * might be the only possible status */ | ||
| 6678 | status = TP_EC_FAN_AUTO; | ||
| 6679 | } | ||
| 6680 | |||
| 6681 | len += sprintf(p + len, "status:\t\t%s\n", | 6688 | len += sprintf(p + len, "status:\t\t%s\n", |
| 6682 | (status != 0) ? "enabled" : "disabled"); | 6689 | (status != 0) ? "enabled" : "disabled"); |
| 6683 | 6690 | ||
