aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/platform
diff options
context:
space:
mode:
authorHenrique de Moraes Holschuh <hmh@hmh.eng.br>2009-06-17 23:40:17 -0400
committerLen Brown <len.brown@intel.com>2009-06-18 01:30:57 -0400
commitd73772474f6ebbacbe820c31c0fa1cffa7160246 (patch)
tree7564212618d43910de01a818c0cdef5759ad12a9 /drivers/platform
parentd7880f10c5d42ba182a97c1fd41d41d0b8837097 (diff)
thinkpad-acpi: support the second fan on the X61
Support reading the tachometer of the auxiliary fan of a X60/X61. It was found out by sheer luck, that bit 0 of EC register 0x31 (formely HBRV) selects which fan is active for tachometer readings through EC 0x84/0x085: 0 for fan1, 1 for fan2. Many thanks to Christoph Kl??nter, to Whoopie, and to weasel, who helped confirm that behaviour. Fan control through EC HFSP applies to both fans equally, regardless of the state of bit 0 of EC 0x31. That matches the way the DSDT uses HFSP. In order to better support the secondary fan, export a second tachometer over hwmon, and add defensive measures to make sure we are reading the correct tachometer. Support for the second fan is whitelist-based, as I have not found anything obvious to look for in the DSDT to detect the presence of the second fan. Signed-off-by: Henrique de Moraes Holschuh <hmh@hmh.eng.br> Signed-off-by: Len Brown <len.brown@intel.com>
Diffstat (limited to 'drivers/platform')
-rw-r--r--drivers/platform/x86/thinkpad_acpi.c122
1 files changed, 121 insertions, 1 deletions
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 */
6439static 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 */
6454static 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
6565static 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
6513static int fan_set_level(int level) 6593static 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 ------------------------------------------------ */
6999static 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
7013static 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) ------------------------------- */
6919static ssize_t fan_fan_watchdog_show(struct device_driver *drv, 7018static 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,
6948static struct attribute *fan_attributes[] = { 7047static 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
6966static const struct tpacpi_quirk fan_quirk_table[] __initconst = { 7073static 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
6975static int __init fan_init(struct ibm_init_struct *iibm) 7084static 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)