aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/misc
diff options
context:
space:
mode:
authorHenrique de Moraes Holschuh <hmh@hmh.eng.br>2007-04-24 10:48:16 -0400
committerLen Brown <len.brown@intel.com>2007-04-25 02:00:27 -0400
commit2c37aa4e22dd55070c608290c5031f2ee93e69ce (patch)
treeab8a0c05c4a3e51e6f111d3377393b766d4e39a2 /drivers/misc
parent40ca9fdf8aa7d929e2b8939be1e6380d107381e1 (diff)
ACPI: thinkpad-acpi: add sysfs support to the thermal subdriver
Export thinkpad thermal sensors to sysfs, following the hwmon specification for thermal monitoring sensors. ThinkPad thermal monitoring is done by the EC. Sensors can show up or disappear at runtime when they are inside hotswappable hardware, such as batteries. Sensors that are not available return -ENXIO when accessed. Up to 16 thermal sensors are supported on new firmware (but nobody has reported a ThinkPad with more than 12 sensors so far), and 8 sensors are supported on older firmware. Thermal sensor mapping is model-specific. Precision varies, it is 1 degree Celcius on new ThinkPads, but higher on some older models. Signed-off-by: Henrique de Moraes Holschuh <hmh@hmh.eng.br> Signed-off-by: Len Brown <len.brown@intel.com>
Diffstat (limited to 'drivers/misc')
-rw-r--r--drivers/misc/thinkpad_acpi.c122
-rw-r--r--drivers/misc/thinkpad_acpi.h2
2 files changed, 123 insertions, 1 deletions
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
1993static enum thermal_access_mode thermal_read_mode; 1993static enum thermal_access_mode thermal_read_mode;
1994 1994
1995/* sysfs temp##_input -------------------------------------------------- */
1996
1997static 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
2019static 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
2041static 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
2061static const struct attribute_group thermal_temp_input16_group = {
2062 .attrs = thermal_temp_input_attr
2063};
2064
2065static 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
1995static int __init thermal_init(struct ibm_init_struct *iibm) 2074static 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
2166static 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)
2168static struct ibm_struct thermal_driver_data = { 2287static 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 {
467enum { /* TPACPI_THERMAL_TPEC_* */ 468enum { /* 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 */