aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/acpi/ibm_acpi.c
diff options
context:
space:
mode:
authorHenrique de Moraes Holschuh <hmh@hmh.eng.br>2006-11-24 08:47:08 -0500
committerLen Brown <len.brown@intel.com>2006-12-07 01:38:38 -0500
commit60eb0b35a9cc3400251cb4028d100e350649cf8a (patch)
tree2f655a273572e46b6c4f662071d027e57cad1bcf /drivers/acpi/ibm_acpi.c
parenta26f878abcd0491906b5bbac8dd174f27019e907 (diff)
ACPI: ibm-acpi: Implement direct-ec-access thermal reading modes for up to 16 sensors
This patch extends ibm-acpi to support reading thermal sensors directly through ACPI EC register access. It uses a DMI match to detect ThinkPads with a new-style embedded controller, that are known to have forward- compatible register maps and use 0x00 to fill in non-used registers and export thermal sensors at EC offsets 0x78-7F and 0xC0-C7. Direct ACPI EC register access is implemented for 8-sensor and 16-sensor new-style ThinkPad controller firmwares as an experimental feature. The code does some limited sanity checks on the temperatures read through EC access, and will default to the old ACPI TMP0-7 mode if anything is amiss. Userspace ABI is not changed for 8 sensors, but /proc/acpi/ibm/thermal is extended for 16 sensors if the firmware supports 16 sensors. A documentation update is also provided. The information about the ThinkPad register map was determined by studying ibm-acpi "ecdump" output from various ThinkPad models, submitted by subscribers of the linux-thinkpad mailinglist. Futher information was gathered from the DSDT tables, as they describe the EC register map in recent ThinkPads. DSDT source shows that TMP0-7 access and direct register access are actually the same thing on these firmwares, but unfortunately IBM never did update their DSDT EC register map to export TMP8-TMP15 for the second range of sensors. Signed-off-by: Henrique de Moraes Holschuh <hmh@hmh.eng.br>
Diffstat (limited to 'drivers/acpi/ibm_acpi.c')
-rw-r--r--drivers/acpi/ibm_acpi.c93
1 files changed, 91 insertions, 2 deletions
diff --git a/drivers/acpi/ibm_acpi.c b/drivers/acpi/ibm_acpi.c
index baf9492f0a79..1703c617c0e8 100644
--- a/drivers/acpi/ibm_acpi.c
+++ b/drivers/acpi/ibm_acpi.c
@@ -80,6 +80,7 @@
80#include <linux/proc_fs.h> 80#include <linux/proc_fs.h>
81#include <linux/backlight.h> 81#include <linux/backlight.h>
82#include <asm/uaccess.h> 82#include <asm/uaccess.h>
83#include <linux/dmi.h>
83 84
84#include <acpi/acpi_drivers.h> 85#include <acpi/acpi_drivers.h>
85#include <acpi/acnamesp.h> 86#include <acpi/acnamesp.h>
@@ -221,13 +222,17 @@ enum thermal_access_mode {
221 IBMACPI_THERMAL_NONE = 0, /* No thermal support */ 222 IBMACPI_THERMAL_NONE = 0, /* No thermal support */
222 IBMACPI_THERMAL_ACPI_TMP07, /* Use ACPI TMP0-7 */ 223 IBMACPI_THERMAL_ACPI_TMP07, /* Use ACPI TMP0-7 */
223 IBMACPI_THERMAL_ACPI_UPDT, /* Use ACPI TMP0-7 with UPDT */ 224 IBMACPI_THERMAL_ACPI_UPDT, /* Use ACPI TMP0-7 with UPDT */
225 IBMACPI_THERMAL_TPEC_8, /* Use ACPI EC regs, 8 sensors */
226 IBMACPI_THERMAL_TPEC_16, /* Use ACPI EC regs, 16 sensors */
224}; 227};
225 228
226#define IBMACPI_MAX_THERMAL_SENSORS 8 /* Max thermal sensors supported */ 229#define IBMACPI_MAX_THERMAL_SENSORS 16 /* Max thermal sensors supported */
227struct ibm_thermal_sensors_struct { 230struct ibm_thermal_sensors_struct {
228 s32 temp[IBMACPI_MAX_THERMAL_SENSORS]; 231 s32 temp[IBMACPI_MAX_THERMAL_SENSORS];
229}; 232};
230 233
234static int ibm_thinkpad_ec_found;
235
231struct ibm_struct { 236struct ibm_struct {
232 char *name; 237 char *name;
233 char param[32]; 238 char param[32];
@@ -1290,7 +1295,52 @@ static enum thermal_access_mode thermal_read_mode;
1290 1295
1291static int thermal_init(void) 1296static int thermal_init(void)
1292{ 1297{
1293 if (acpi_evalf(ec_handle, NULL, "TMP7", "qv")) { 1298 u8 t, ta1, ta2;
1299 int i;
1300 int acpi_tmp7 = acpi_evalf(ec_handle, NULL, "TMP7", "qv");
1301
1302 if (ibm_thinkpad_ec_found && experimental) {
1303 /*
1304 * Direct EC access mode: sensors at registers
1305 * 0x78-0x7F, 0xC0-0xC7. Registers return 0x00 for
1306 * non-implemented, thermal sensors return 0x80 when
1307 * not available
1308 */
1309
1310 ta1 = ta2 = 0;
1311 for (i = 0; i < 8; i++) {
1312 if (likely(acpi_ec_read(0x78 + i, &t))) {
1313 ta1 |= t;
1314 } else {
1315 ta1 = 0;
1316 break;
1317 }
1318 if (likely(acpi_ec_read(0xC0 + i, &t))) {
1319 ta2 |= t;
1320 } else {
1321 ta1 = 0;
1322 break;
1323 }
1324 }
1325 if (ta1 == 0) {
1326 /* This is sheer paranoia, but we handle it anyway */
1327 if (acpi_tmp7) {
1328 printk(IBM_ERR
1329 "ThinkPad ACPI EC access misbehaving, "
1330 "falling back to ACPI TMPx access mode\n");
1331 thermal_read_mode = IBMACPI_THERMAL_ACPI_TMP07;
1332 } else {
1333 printk(IBM_ERR
1334 "ThinkPad ACPI EC access misbehaving, "
1335 "disabling thermal sensors access\n");
1336 thermal_read_mode = IBMACPI_THERMAL_NONE;
1337 }
1338 } else {
1339 thermal_read_mode =
1340 (ta2 != 0) ?
1341 IBMACPI_THERMAL_TPEC_16 : IBMACPI_THERMAL_TPEC_8;
1342 }
1343 } else if (acpi_tmp7) {
1294 if (acpi_evalf(ec_handle, NULL, "UPDT", "qv")) { 1344 if (acpi_evalf(ec_handle, NULL, "UPDT", "qv")) {
1295 /* 600e/x, 770e, 770x */ 1345 /* 600e/x, 770e, 770x */
1296 thermal_read_mode = IBMACPI_THERMAL_ACPI_UPDT; 1346 thermal_read_mode = IBMACPI_THERMAL_ACPI_UPDT;
@@ -1309,12 +1359,30 @@ static int thermal_init(void)
1309static int thermal_get_sensors(struct ibm_thermal_sensors_struct *s) 1359static int thermal_get_sensors(struct ibm_thermal_sensors_struct *s)
1310{ 1360{
1311 int i, t; 1361 int i, t;
1362 s8 tmp;
1312 char tmpi[] = "TMPi"; 1363 char tmpi[] = "TMPi";
1313 1364
1314 if (!s) 1365 if (!s)
1315 return -EINVAL; 1366 return -EINVAL;
1316 1367
1317 switch (thermal_read_mode) { 1368 switch (thermal_read_mode) {
1369#if IBMACPI_MAX_THERMAL_SENSORS >= 16
1370 case IBMACPI_THERMAL_TPEC_16:
1371 for (i = 0; i < 8; i++) {
1372 if (!acpi_ec_read(0xC0 + i, &tmp))
1373 return -EIO;
1374 s->temp[i + 8] = tmp * 1000;
1375 }
1376 /* fallthrough */
1377#endif
1378 case IBMACPI_THERMAL_TPEC_8:
1379 for (i = 0; i < 8; i++) {
1380 if (!acpi_ec_read(0x78 + i, &tmp))
1381 return -EIO;
1382 s->temp[i] = tmp * 1000;
1383 }
1384 return (thermal_read_mode == IBMACPI_THERMAL_TPEC_16) ? 16 : 8;
1385
1318 case IBMACPI_THERMAL_ACPI_UPDT: 1386 case IBMACPI_THERMAL_ACPI_UPDT:
1319 if (!acpi_evalf(ec_handle, NULL, "UPDT", "v")) 1387 if (!acpi_evalf(ec_handle, NULL, "UPDT", "v"))
1320 return -EIO; 1388 return -EIO;
@@ -2052,6 +2120,24 @@ static void acpi_ibm_exit(void)
2052 remove_proc_entry(IBM_DIR, acpi_root_dir); 2120 remove_proc_entry(IBM_DIR, acpi_root_dir);
2053} 2121}
2054 2122
2123static int __init check_dmi_for_ec(void)
2124{
2125 struct dmi_device *dev = NULL;
2126
2127 /*
2128 * ThinkPad T23 or newer, A31 or newer, R50e or newer,
2129 * X32 or newer, all Z series; Some models must have an
2130 * up-to-date BIOS or they will not be detected.
2131 *
2132 * See http://thinkwiki.org/wiki/List_of_DMI_IDs
2133 */
2134 while ((dev = dmi_find_device(DMI_DEV_TYPE_OEM_STRING, NULL, dev))) {
2135 if (strstr(dev->name, "IBM ThinkPad Embedded Controller"))
2136 return 1;
2137 }
2138 return 0;
2139}
2140
2055static int __init acpi_ibm_init(void) 2141static int __init acpi_ibm_init(void)
2056{ 2142{
2057 int ret, i; 2143 int ret, i;
@@ -2071,6 +2157,9 @@ static int __init acpi_ibm_init(void)
2071 return -ENODEV; 2157 return -ENODEV;
2072 } 2158 }
2073 2159
2160 /* Models with newer firmware report the EC in DMI */
2161 ibm_thinkpad_ec_found = check_dmi_for_ec();
2162
2074 /* these handles are not required */ 2163 /* these handles are not required */
2075 IBM_HANDLE_INIT(vid); 2164 IBM_HANDLE_INIT(vid);
2076 IBM_HANDLE_INIT(vid2); 2165 IBM_HANDLE_INIT(vid2);