aboutsummaryrefslogtreecommitdiffstats
path: root/drivers
diff options
context:
space:
mode:
Diffstat (limited to 'drivers')
-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);