ACPI: ibm-acpi: fix and extend fan control functions

This patch extend fan control functions, implementing enable/disable for
all write access modes, implementing level control for all level-capable
write access modes.

The patch also updates the documentation, explaining levels auto and
disengaged.

ABI changes:
	1. Support level 0 as an equivalent to disable
	2. Add support for level auto and level disengaged when doing
	   EC 0x2f fan control
	3. Support enable/disable for all level-based write access modes
	4. Add support for level command on FANS thinkpads, as per
	   thinkwiki reports

Signed-off-by: Henrique de Moraes Holschuh <hmh@hmh.eng.br>
This commit is contained in:
Henrique de Moraes Holschuh 2006-11-24 11:47:13 -02:00 committed by Len Brown
parent 1c6a334e9c
commit a12095c2b5
2 changed files with 81 additions and 25 deletions

View File

@ -571,27 +571,57 @@ directly accesses hardware registers and may not work as expected. USE
WITH CAUTION! To use this feature, you need to supply the WITH CAUTION! To use this feature, you need to supply the
experimental=1 parameter when loading the module. experimental=1 parameter when loading the module.
This feature attempts to show the current fan speed. The speed is read This feature attempts to show the current fan speed, control mode and
directly from the hardware registers of the embedded controller. This other fan data that might be available. The speed is read directly
is known to work on later R, T and X series ThinkPads but may show a from the hardware registers of the embedded controller. This is known
bogus value on other models. to work on later R, T and X series ThinkPads but may show a bogus
value on other models.
Most ThinkPad fans work in "levels". Level 0 stops the fan. The higher
the level, the higher the fan speed, although adjacent levels often map
to the same fan speed. 7 is the highest level, where the fan reaches
the maximum recommended speed. Level "auto" means the EC changes the
fan level according to some internal algorithm, usually based on
readings from the thermal sensors. Level "disengaged" means the EC
disables the speed-locked closed-loop fan control, and drives the fan as
fast as it can go, which might exceed hardware limits, so use this level
with caution.
The fan usually ramps up or down slowly from one speed to another,
and it is normal for the EC to take several seconds to react to fan
commands.
The fan may be enabled or disabled with the following commands: The fan may be enabled or disabled with the following commands:
echo enable >/proc/acpi/ibm/fan echo enable >/proc/acpi/ibm/fan
echo disable >/proc/acpi/ibm/fan echo disable >/proc/acpi/ibm/fan
WARNING WARNING WARNING: do not leave the fan disabled unless you are Placing a fan on level 0 is the same as disabling it. Enabling a fan
monitoring the temperature sensor readings and you are ready to enable will try to place it in a safe level if it is too slow or disabled.
it if necessary to avoid overheating.
The fan only runs if it's enabled *and* the various temperature WARNING WARNING WARNING: do not leave the fan disabled unless you are
sensors which control it read high enough. On the X40, this seems to monitoring all of the temperature sensor readings and you are ready to
depend on the CPU and HDD temperatures. Specifically, the fan is enable it if necessary to avoid overheating.
turned on when either the CPU temperature climbs to 56 degrees or the
HDD temperature climbs to 46 degrees. The fan is turned off when the An enabled fan in level "auto" may stop spinning if the EC decides the
CPU temperature drops to 49 degrees and the HDD temperature drops to ThinkPad is cool enough and doesn't need the extra airflow. This is
41 degrees. These thresholds cannot currently be controlled. normal, and the EC will spin the fan up if the varios thermal readings
rise too much.
On the X40, this seems to depend on the CPU and HDD temperatures.
Specifically, the fan is turned on when either the CPU temperature
climbs to 56 degrees or the HDD temperature climbs to 46 degrees. The
fan is turned off when the CPU temperature drops to 49 degrees and the
HDD temperature drops to 41 degrees. These thresholds cannot
currently be controlled.
The fan level can be controlled with the command:
echo 'level <level>' > /proc/acpi/ibm/thermal
Where <level> is an integer from 0 to 7, or one of the words "auto"
or "disengaged" (without the quotes). Not all ThinkPads support the
"auto" and "disengaged" levels.
On the X31 and X40 (and ONLY on those models), the fan speed can be On the X31 and X40 (and ONLY on those models), the fan speed can be
controlled to a certain degree. Once the fan is running, it can be controlled to a certain degree. Once the fan is running, it can be
@ -604,12 +634,9 @@ about 3700 to about 7350. Values outside this range either do not have
any effect or the fan speed eventually settles somewhere in that any effect or the fan speed eventually settles somewhere in that
range. The fan cannot be stopped or started with this command. range. The fan cannot be stopped or started with this command.
On the 570, temperature readings are not available through this The ThinkPad's ACPI DSDT code will reprogram the fan on its own when
feature and the fan control works a little differently. The fan speed certain conditions are met. It will override any fan programming done
is reported in levels from 0 (off) to 7 (max) and can be controlled through ibm-acpi.
with the following command:
echo 'level <level>' > /proc/acpi/ibm/thermal
EXPERIMENTAL: WAN -- /proc/acpi/ibm/wan EXPERIMENTAL: WAN -- /proc/acpi/ibm/wan
--------------------------------------- ---------------------------------------

View File

@ -1833,10 +1833,13 @@ static int fan_init(void)
IBMACPI_FAN_WR_ACPI_FANS; IBMACPI_FAN_WR_ACPI_FANS;
fan_control_commands |= fan_control_commands |=
IBMACPI_FAN_CMD_SPEED | IBMACPI_FAN_CMD_SPEED |
IBMACPI_FAN_CMD_LEVEL |
IBMACPI_FAN_CMD_ENABLE; IBMACPI_FAN_CMD_ENABLE;
} else { } else {
fan_control_access_mode = IBMACPI_FAN_WR_TPEC; fan_control_access_mode = IBMACPI_FAN_WR_TPEC;
fan_control_commands |= IBMACPI_FAN_CMD_ENABLE; fan_control_commands |=
IBMACPI_FAN_CMD_LEVEL |
IBMACPI_FAN_CMD_ENABLE;
} }
} }
} }
@ -1948,9 +1951,20 @@ static int fan_read(char *p)
len += sprintf(p + len, "status:\t\tnot supported\n"); len += sprintf(p + len, "status:\t\tnot supported\n");
} }
if (fan_control_commands & IBMACPI_FAN_CMD_LEVEL) if (fan_control_commands & IBMACPI_FAN_CMD_LEVEL) {
len += sprintf(p + len, "commands:\tlevel <level>" len += sprintf(p + len, "commands:\tlevel <level>");
" (<level> is 0-7)\n");
switch (fan_control_access_mode) {
case IBMACPI_FAN_WR_ACPI_SFAN:
len += sprintf(p + len, " (<level> is 0-7)\n");
break;
default:
len += sprintf(p + len, " (<level> is 0-7, "
"auto, disengaged)\n");
break;
}
}
if (fan_control_commands & IBMACPI_FAN_CMD_ENABLE) if (fan_control_commands & IBMACPI_FAN_CMD_ENABLE)
len += sprintf(p + len, "commands:\tenable, disable\n"); len += sprintf(p + len, "commands:\tenable, disable\n");
@ -1973,6 +1987,17 @@ static int fan_set_level(int level)
return -EINVAL; return -EINVAL;
break; break;
case IBMACPI_FAN_WR_ACPI_FANS:
case IBMACPI_FAN_WR_TPEC:
if ((level != IBMACPI_FAN_EC_AUTO) &&
(level != IBMACPI_FAN_EC_DISENGAGED) &&
((level < 0) || (level > 7)))
return -EINVAL;
if (!acpi_ec_write(fan_status_offset, level))
return -EIO;
break;
default: default:
return -ENXIO; return -ENXIO;
} }
@ -2060,7 +2085,11 @@ static int fan_write_cmd_level(const char *cmd, int *rc)
{ {
int level; int level;
if (sscanf(cmd, "level %d", &level) != 1) if (strlencmp(cmd, "level auto") == 0)
level = IBMACPI_FAN_EC_AUTO;
else if (strlencmp(cmd, "level disengaged") == 0)
level = IBMACPI_FAN_EC_DISENGAGED;
else if (sscanf(cmd, "level %d", &level) != 1)
return 0; return 0;
if ((*rc = fan_set_level(level)) == -ENXIO) if ((*rc = fan_set_level(level)) == -ENXIO)