diff options
-rw-r--r-- | Documentation/thinkpad-acpi.txt | 26 | ||||
-rw-r--r-- | drivers/misc/thinkpad_acpi.c | 122 | ||||
-rw-r--r-- | drivers/misc/thinkpad_acpi.h | 2 |
3 files changed, 143 insertions, 7 deletions
diff --git a/Documentation/thinkpad-acpi.txt b/Documentation/thinkpad-acpi.txt index cc079afaf66b..80c0bf28e392 100644 --- a/Documentation/thinkpad-acpi.txt +++ b/Documentation/thinkpad-acpi.txt | |||
@@ -458,17 +458,17 @@ X40: | |||
458 | 16 - one medium-pitched beep repeating constantly, stop with 17 | 458 | 16 - one medium-pitched beep repeating constantly, stop with 17 |
459 | 17 - stop 16 | 459 | 17 - stop 16 |
460 | 460 | ||
461 | Temperature sensors -- /proc/acpi/ibm/thermal | 461 | Temperature sensors |
462 | --------------------------------------------- | 462 | ------------------- |
463 | |||
464 | procfs: /proc/acpi/ibm/thermal | ||
465 | sysfs device attributes: (hwmon) temp*_input | ||
463 | 466 | ||
464 | Most ThinkPads include six or more separate temperature sensors but | 467 | Most ThinkPads include six or more separate temperature sensors but |
465 | only expose the CPU temperature through the standard ACPI methods. | 468 | only expose the CPU temperature through the standard ACPI methods. |
466 | This feature shows readings from up to eight different sensors on older | 469 | This feature shows readings from up to eight different sensors on older |
467 | ThinkPads, and it has experimental support for up to sixteen different | 470 | ThinkPads, and it has experimental support for up to sixteen different |
468 | sensors on newer ThinkPads. Readings from sensors that are not available | 471 | sensors on newer ThinkPads. |
469 | return -128. | ||
470 | |||
471 | No commands can be written to this file. | ||
472 | 472 | ||
473 | EXPERIMENTAL: The 16-sensors feature is marked EXPERIMENTAL because the | 473 | EXPERIMENTAL: The 16-sensors feature is marked EXPERIMENTAL because the |
474 | implementation directly accesses hardware registers and may not work as | 474 | implementation directly accesses hardware registers and may not work as |
@@ -525,6 +525,20 @@ The A31 has a very atypical layout for the thermal sensors | |||
525 | 8: Bay Battery: secondary sensor | 525 | 8: Bay Battery: secondary sensor |
526 | 526 | ||
527 | 527 | ||
528 | Procfs notes: | ||
529 | Readings from sensors that are not available return -128. | ||
530 | No commands can be written to this file. | ||
531 | |||
532 | Sysfs notes: | ||
533 | Sensors that are not available return the ENXIO error. This | ||
534 | status may change at runtime, as there are hotplug thermal | ||
535 | sensors, like those inside the batteries and docks. | ||
536 | |||
537 | thinkpad-acpi thermal sensors are reported through the hwmon | ||
538 | subsystem, and follow all of the hwmon guidelines at | ||
539 | Documentation/hwmon. | ||
540 | |||
541 | |||
528 | EXPERIMENTAL: Embedded controller register dump -- /proc/acpi/ibm/ecdump | 542 | EXPERIMENTAL: Embedded controller register dump -- /proc/acpi/ibm/ecdump |
529 | ------------------------------------------------------------------------ | 543 | ------------------------------------------------------------------------ |
530 | 544 | ||
diff --git a/drivers/misc/thinkpad_acpi.c b/drivers/misc/thinkpad_acpi.c index aa69ff0c1c91..d5526e882ddd 100644 --- a/drivers/misc/thinkpad_acpi.c +++ b/drivers/misc/thinkpad_acpi.c | |||
@@ -1992,11 +1992,91 @@ static struct ibm_struct beep_driver_data = { | |||
1992 | 1992 | ||
1993 | static enum thermal_access_mode thermal_read_mode; | 1993 | static enum thermal_access_mode thermal_read_mode; |
1994 | 1994 | ||
1995 | /* sysfs temp##_input -------------------------------------------------- */ | ||
1996 | |||
1997 | static ssize_t thermal_temp_input_show(struct device *dev, | ||
1998 | struct device_attribute *attr, | ||
1999 | char *buf) | ||
2000 | { | ||
2001 | struct sensor_device_attribute *sensor_attr = | ||
2002 | to_sensor_dev_attr(attr); | ||
2003 | int idx = sensor_attr->index; | ||
2004 | s32 value; | ||
2005 | int res; | ||
2006 | |||
2007 | res = thermal_get_sensor(idx, &value); | ||
2008 | if (res) | ||
2009 | return res; | ||
2010 | if (value == TP_EC_THERMAL_TMP_NA * 1000) | ||
2011 | return -ENXIO; | ||
2012 | |||
2013 | return snprintf(buf, PAGE_SIZE, "%d\n", value); | ||
2014 | } | ||
2015 | |||
2016 | #define THERMAL_SENSOR_ATTR_TEMP(_idxA, _idxB) \ | ||
2017 | SENSOR_ATTR(temp##_idxA##_input, S_IRUGO, thermal_temp_input_show, NULL, _idxB) | ||
2018 | |||
2019 | static struct sensor_device_attribute sensor_dev_attr_thermal_temp_input[] = { | ||
2020 | THERMAL_SENSOR_ATTR_TEMP(1, 0), | ||
2021 | THERMAL_SENSOR_ATTR_TEMP(2, 1), | ||
2022 | THERMAL_SENSOR_ATTR_TEMP(3, 2), | ||
2023 | THERMAL_SENSOR_ATTR_TEMP(4, 3), | ||
2024 | THERMAL_SENSOR_ATTR_TEMP(5, 4), | ||
2025 | THERMAL_SENSOR_ATTR_TEMP(6, 5), | ||
2026 | THERMAL_SENSOR_ATTR_TEMP(7, 6), | ||
2027 | THERMAL_SENSOR_ATTR_TEMP(8, 7), | ||
2028 | THERMAL_SENSOR_ATTR_TEMP(9, 8), | ||
2029 | THERMAL_SENSOR_ATTR_TEMP(10, 9), | ||
2030 | THERMAL_SENSOR_ATTR_TEMP(11, 10), | ||
2031 | THERMAL_SENSOR_ATTR_TEMP(12, 11), | ||
2032 | THERMAL_SENSOR_ATTR_TEMP(13, 12), | ||
2033 | THERMAL_SENSOR_ATTR_TEMP(14, 13), | ||
2034 | THERMAL_SENSOR_ATTR_TEMP(15, 14), | ||
2035 | THERMAL_SENSOR_ATTR_TEMP(16, 15), | ||
2036 | }; | ||
2037 | |||
2038 | #define THERMAL_ATTRS(X) \ | ||
2039 | &sensor_dev_attr_thermal_temp_input[X].dev_attr.attr | ||
2040 | |||
2041 | static struct attribute *thermal_temp_input_attr[] = { | ||
2042 | THERMAL_ATTRS(8), | ||
2043 | THERMAL_ATTRS(9), | ||
2044 | THERMAL_ATTRS(10), | ||
2045 | THERMAL_ATTRS(11), | ||
2046 | THERMAL_ATTRS(12), | ||
2047 | THERMAL_ATTRS(13), | ||
2048 | THERMAL_ATTRS(14), | ||
2049 | THERMAL_ATTRS(15), | ||
2050 | THERMAL_ATTRS(0), | ||
2051 | THERMAL_ATTRS(1), | ||
2052 | THERMAL_ATTRS(2), | ||
2053 | THERMAL_ATTRS(3), | ||
2054 | THERMAL_ATTRS(4), | ||
2055 | THERMAL_ATTRS(5), | ||
2056 | THERMAL_ATTRS(6), | ||
2057 | THERMAL_ATTRS(7), | ||
2058 | NULL | ||
2059 | }; | ||
2060 | |||
2061 | static const struct attribute_group thermal_temp_input16_group = { | ||
2062 | .attrs = thermal_temp_input_attr | ||
2063 | }; | ||
2064 | |||
2065 | static const struct attribute_group thermal_temp_input8_group = { | ||
2066 | .attrs = &thermal_temp_input_attr[8] | ||
2067 | }; | ||
2068 | |||
2069 | #undef THERMAL_SENSOR_ATTR_TEMP | ||
2070 | #undef THERMAL_ATTRS | ||
2071 | |||
2072 | /* --------------------------------------------------------------------- */ | ||
2073 | |||
1995 | static int __init thermal_init(struct ibm_init_struct *iibm) | 2074 | static int __init thermal_init(struct ibm_init_struct *iibm) |
1996 | { | 2075 | { |
1997 | u8 t, ta1, ta2; | 2076 | u8 t, ta1, ta2; |
1998 | int i; | 2077 | int i; |
1999 | int acpi_tmp7; | 2078 | int acpi_tmp7; |
2079 | int res; | ||
2000 | 2080 | ||
2001 | vdbg_printk(TPACPI_DBG_INIT, "initializing thermal subdriver\n"); | 2081 | vdbg_printk(TPACPI_DBG_INIT, "initializing thermal subdriver\n"); |
2002 | 2082 | ||
@@ -2060,7 +2140,46 @@ static int __init thermal_init(struct ibm_init_struct *iibm) | |||
2060 | str_supported(thermal_read_mode != TPACPI_THERMAL_NONE), | 2140 | str_supported(thermal_read_mode != TPACPI_THERMAL_NONE), |
2061 | thermal_read_mode); | 2141 | thermal_read_mode); |
2062 | 2142 | ||
2063 | return (thermal_read_mode != TPACPI_THERMAL_NONE)? 0 : 1; | 2143 | switch(thermal_read_mode) { |
2144 | case TPACPI_THERMAL_TPEC_16: | ||
2145 | res = sysfs_create_group(&tpacpi_pdev->dev.kobj, | ||
2146 | &thermal_temp_input16_group); | ||
2147 | if (res) | ||
2148 | return res; | ||
2149 | break; | ||
2150 | case TPACPI_THERMAL_TPEC_8: | ||
2151 | case TPACPI_THERMAL_ACPI_TMP07: | ||
2152 | case TPACPI_THERMAL_ACPI_UPDT: | ||
2153 | res = sysfs_create_group(&tpacpi_pdev->dev.kobj, | ||
2154 | &thermal_temp_input8_group); | ||
2155 | if (res) | ||
2156 | return res; | ||
2157 | break; | ||
2158 | case TPACPI_THERMAL_NONE: | ||
2159 | default: | ||
2160 | return 1; | ||
2161 | } | ||
2162 | |||
2163 | return 0; | ||
2164 | } | ||
2165 | |||
2166 | static void thermal_exit(void) | ||
2167 | { | ||
2168 | switch(thermal_read_mode) { | ||
2169 | case TPACPI_THERMAL_TPEC_16: | ||
2170 | sysfs_remove_group(&tpacpi_pdev->dev.kobj, | ||
2171 | &thermal_temp_input16_group); | ||
2172 | break; | ||
2173 | case TPACPI_THERMAL_TPEC_8: | ||
2174 | case TPACPI_THERMAL_ACPI_TMP07: | ||
2175 | case TPACPI_THERMAL_ACPI_UPDT: | ||
2176 | sysfs_remove_group(&tpacpi_pdev->dev.kobj, | ||
2177 | &thermal_temp_input16_group); | ||
2178 | break; | ||
2179 | case TPACPI_THERMAL_NONE: | ||
2180 | default: | ||
2181 | break; | ||
2182 | } | ||
2064 | } | 2183 | } |
2065 | 2184 | ||
2066 | /* idx is zero-based */ | 2185 | /* idx is zero-based */ |
@@ -2168,6 +2287,7 @@ static int thermal_read(char *p) | |||
2168 | static struct ibm_struct thermal_driver_data = { | 2287 | static struct ibm_struct thermal_driver_data = { |
2169 | .name = "thermal", | 2288 | .name = "thermal", |
2170 | .read = thermal_read, | 2289 | .read = thermal_read, |
2290 | .exit = thermal_exit, | ||
2171 | }; | 2291 | }; |
2172 | 2292 | ||
2173 | /************************************************************************* | 2293 | /************************************************************************* |
diff --git a/drivers/misc/thinkpad_acpi.h b/drivers/misc/thinkpad_acpi.h index a9feb53c6d3c..e833ff3caf39 100644 --- a/drivers/misc/thinkpad_acpi.h +++ b/drivers/misc/thinkpad_acpi.h | |||
@@ -38,6 +38,7 @@ | |||
38 | #include <linux/fb.h> | 38 | #include <linux/fb.h> |
39 | #include <linux/platform_device.h> | 39 | #include <linux/platform_device.h> |
40 | #include <linux/hwmon.h> | 40 | #include <linux/hwmon.h> |
41 | #include <linux/hwmon-sysfs.h> | ||
41 | #include <asm/uaccess.h> | 42 | #include <asm/uaccess.h> |
42 | 43 | ||
43 | #include <linux/dmi.h> | 44 | #include <linux/dmi.h> |
@@ -467,6 +468,7 @@ enum thermal_access_mode { | |||
467 | enum { /* TPACPI_THERMAL_TPEC_* */ | 468 | enum { /* TPACPI_THERMAL_TPEC_* */ |
468 | TP_EC_THERMAL_TMP0 = 0x78, /* ACPI EC regs TMP 0..7 */ | 469 | TP_EC_THERMAL_TMP0 = 0x78, /* ACPI EC regs TMP 0..7 */ |
469 | TP_EC_THERMAL_TMP8 = 0xC0, /* ACPI EC regs TMP 8..15 */ | 470 | TP_EC_THERMAL_TMP8 = 0xC0, /* ACPI EC regs TMP 8..15 */ |
471 | TP_EC_THERMAL_TMP_NA = -128, /* ACPI EC sensor not available */ | ||
470 | }; | 472 | }; |
471 | 473 | ||
472 | #define TPACPI_MAX_THERMAL_SENSORS 16 /* Max thermal sensors supported */ | 474 | #define TPACPI_MAX_THERMAL_SENSORS 16 /* Max thermal sensors supported */ |