[ltp] [patch 09/11] ibm-acpi: fix and extend fan control functions

Henrique de Moraes Holschuh linux-thinkpad@linux-thinkpad.org
Mon, 09 Oct 2006 09:41:40 -0300


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 on EC 0x2f
	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>
---
 Documentation/ibm-acpi.txt |   49 ++++++++++++++++++++++++++------
 drivers/acpi/ibm_acpi.c    |   67 ++++++++++++++++++++++++++++++++++++++-------
 2 files changed, 96 insertions(+), 20 deletions(-)

Index: 2.6.18/drivers/acpi/ibm_acpi.c
===================================================================
--- 2.6.18.orig/drivers/acpi/ibm_acpi.c	2006-10-06 17:26:00.000000000 -0300
+++ 2.6.18/drivers/acpi/ibm_acpi.c	2006-10-06 17:26:27.000000000 -0300
@@ -1745,7 +1745,8 @@
 	if (sfan_handle) {
 		/* 570, 770x-JL */
 		fan_control_access_mode = IBMACPI_FAN_WR_ACPI_SFAN;
-		fan_control_commands |= IBMACPI_FAN_CMD_LEVEL;
+		fan_control_commands |= IBMACPI_FAN_CMD_LEVEL
+					| IBMACPI_FAN_CMD_ENABLE;
 	} else {
 		if (!gfan_handle) {
 			/* gfan without sfan means no fan control */
@@ -1754,10 +1755,13 @@
 			if (fans_handle) {
 				/* X31, X40 */
 				fan_control_access_mode = IBMACPI_FAN_WR_ACPI_FANS;
-				fan_control_commands |= IBMACPI_FAN_CMD_SPEED | IBMACPI_FAN_CMD_ENABLE;
+				fan_control_commands |= IBMACPI_FAN_CMD_SPEED
+							| IBMACPI_FAN_CMD_LEVEL
+							| IBMACPI_FAN_CMD_ENABLE;
 			} else {
 				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;
 			}
 		}
 	}
@@ -1820,9 +1824,20 @@
 		len += sprintf(p + len, "status:\t\tunavailable\n");
 	}
 
-	if (fan_control_commands & IBMACPI_FAN_CMD_LEVEL)
-		len += sprintf(p + len, "commands:\tlevel <level>"
-			       " (<level> is 0-7)\n");
+	if (fan_control_commands & IBMACPI_FAN_CMD_LEVEL) {
+		len += sprintf(p + len, "commands:\tlevel <level>");
+
+		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)
 		len += sprintf(p + len, "commands:\tenable, disable\n");
@@ -1838,11 +1853,11 @@
 {
 	int level;
 
-	if (sscanf(cmd, "level %d", &level) != 1)
-		return 0;
-
 	switch (fan_control_access_mode) {
 	case IBMACPI_FAN_WR_ACPI_SFAN:
+		if (sscanf(cmd, "level %d", &level) != 1)
+			return 0;
+
 		if (level >= 0 && level <= 7) {
 			if (!acpi_evalf(sfan_handle, NULL, NULL, "vd", level))
 				*rc = -EIO;
@@ -1850,7 +1865,28 @@
 			*rc = -EINVAL;
 		break;
 
+	case IBMACPI_FAN_WR_ACPI_FANS:
+	case IBMACPI_FAN_WR_TPEC:
+		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) {
+			if ((level < 0) || (level > 7)) {
+				*rc = -EINVAL;
+				break;
+			}
+		} else
+			return 0;
+
+		if (!acpi_ec_write(fan_status_offset, level))
+			*rc = -EIO;
+		break;
+
 	default:
+		if (strlencmp(cmd, "level") != 0)
+			return 0;
+
 		printk(IBM_ERR "level command accepted for unsupported "
 			"access mode %d", fan_control_access_mode);
 		*rc = -EINVAL;
@@ -1866,7 +1902,13 @@
 	switch (fan_control_access_mode) {
 	case IBMACPI_FAN_WR_ACPI_FANS:
 	case IBMACPI_FAN_WR_TPEC:
-		if (!acpi_ec_write(fan_status_offset, 0x80))
+		if (!acpi_ec_write(fan_status_offset, IBMACPI_FAN_EC_AUTO))
+			*rc = -EIO;
+		break;
+
+	case IBMACPI_FAN_WR_ACPI_SFAN:
+		/* For safety, handle enable as "level 7" */
+		if (!acpi_evalf(sfan_handle, NULL, NULL, "vd", 7))
 			*rc = -EIO;
 		break;
 
@@ -1890,6 +1932,11 @@
 			*rc = -EIO;
 		break;
 
+	case IBMACPI_FAN_WR_ACPI_SFAN:
+		if (!acpi_evalf(sfan_handle, NULL, NULL, "vd", 0x00))
+			*rc = -EIO;
+		break;
+
 	default:
 		printk(IBM_ERR "disable command accepted for unsupported "
 			"access mode %d", fan_control_access_mode);
Index: 2.6.18/Documentation/ibm-acpi.txt
===================================================================
--- 2.6.18.orig/Documentation/ibm-acpi.txt	2006-10-06 17:27:22.000000000 -0300
+++ 2.6.18/Documentation/ibm-acpi.txt	2006-10-06 17:27:26.000000000 -0300
@@ -602,20 +602,52 @@
 WITH CAUTION! To use this feature, you need to supply the
 experimental=1 parameter when loading the module.
 
-This feature attempts to show the current fan speed. The speed is read
-directly from the hardware registers of the embedded controller. This
-is known to work on later R, T and X series ThinkPads but may show a
-bogus value on other models.
+This feature attempts to show the current fan speed, control mode and
+other fan data that might be available.  The speed is read directly
+from the hardware registers of the embedded controller. This is known
+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 tachometer 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:
 
 	echo enable  >/proc/acpi/ibm/fan
 	echo disable >/proc/acpi/ibm/fan
 
+Placing a fan on level 0 is the same as disabling it.  Enabling a fan
+places it either in level auto, or in level 7 depending on the ThinkPad
+model.
+
 WARNING WARNING WARNING: do not leave the fan disabled unless you are
 monitoring the temperature sensor readings and you are ready to enable
 it if necessary to avoid overheating.
 
+An enabled fan in level "auto" may stop spinning if the EC decides the
+ThinkPad is cool enough and doesn't need the extra airflow.  This is
+normal, and the EC will spin the fan up if the varios thermal readings
+rise too much.
+
+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.
+
 The fan only runs if it's enabled *and* the various temperature
 sensors which control it read high enough. On the X40, this seems to
 depend on the CPU and HDD temperatures. Specifically, the fan is
@@ -635,12 +667,9 @@
 any effect or the fan speed eventually settles somewhere in that
 range. The fan cannot be stopped or started with this command.
 
-On the 570, temperature readings are not available through this
-feature and the fan control works a little differently. The fan speed
-is reported in levels from 0 (off) to 7 (max) and can be controlled
-with the following command:
-
-	echo 'level <level>' > /proc/acpi/ibm/thermal
+The ThinkPad's ACPI DSDT code will reprogram the fan on its own when
+certain conditions are met.  It will override any fan programming done
+through ibm-acpi.
 
 
 Multiple Commands, Module Parameters

--
  "One disk to rule them all, One disk to find them. One disk to bring
  them all and in the darkness grind them. In the Land of Redmond
  where the shadows lie." -- The Silicon Valley Tarot
  Henrique Holschuh