diff options
author | Henrique de Moraes Holschuh <hmh@hmh.eng.br> | 2007-04-24 10:48:16 -0400 |
---|---|---|
committer | Len Brown <len.brown@intel.com> | 2007-04-25 02:00:27 -0400 |
commit | 2c37aa4e22dd55070c608290c5031f2ee93e69ce (patch) | |
tree | ab8a0c05c4a3e51e6f111d3377393b766d4e39a2 /drivers | |
parent | 40ca9fdf8aa7d929e2b8939be1e6380d107381e1 (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')
-rw-r--r-- | drivers/misc/thinkpad_acpi.c | 122 | ||||
-rw-r--r-- | drivers/misc/thinkpad_acpi.h | 2 |
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 | ||
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 */ |