aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/platform
diff options
context:
space:
mode:
authorMarco Chiappero <marco@absence.it>2012-05-19 09:35:51 -0400
committerMatthew Garrett <mjg@redhat.com>2012-05-31 14:29:35 -0400
commit49f000adcad2d47f22ae97eb78fb2ef8081cd08f (patch)
tree9cef253a9ae99f02229aef419c3cb4745582185f /drivers/platform
parent967145a030a86cba29fe090acd2b55b56568359e (diff)
sony-laptop: add thermal profiles support
[malattia@linux.it: support string based profiles names] Signed-off-by: Marco Chiappero <marco@absence.it> Signed-off-by: Mattia Dongili <malattia@linux.it> Signed-off-by: Matthew Garrett <mjg@redhat.com>
Diffstat (limited to 'drivers/platform')
-rw-r--r--drivers/platform/x86/sony-laptop.c183
1 files changed, 183 insertions, 0 deletions
diff --git a/drivers/platform/x86/sony-laptop.c b/drivers/platform/x86/sony-laptop.c
index 0ac186e9abdc..c3f54ad8125c 100644
--- a/drivers/platform/x86/sony-laptop.c
+++ b/drivers/platform/x86/sony-laptop.c
@@ -148,6 +148,10 @@ static int sony_nc_battery_care_setup(struct platform_device *pd,
148 unsigned int handle); 148 unsigned int handle);
149static void sony_nc_battery_care_cleanup(struct platform_device *pd); 149static void sony_nc_battery_care_cleanup(struct platform_device *pd);
150 150
151static int sony_nc_thermal_setup(struct platform_device *pd);
152static void sony_nc_thermal_cleanup(struct platform_device *pd);
153static void sony_nc_thermal_resume(void);
154
151enum sony_nc_rfkill { 155enum sony_nc_rfkill {
152 SONY_WIFI, 156 SONY_WIFI,
153 SONY_BLUETOOTH, 157 SONY_BLUETOOTH,
@@ -1282,6 +1286,12 @@ static void sony_nc_function_setup(struct acpi_device *device,
1282 pr_err("couldn't set up battery care function (%d)\n", 1286 pr_err("couldn't set up battery care function (%d)\n",
1283 result); 1287 result);
1284 break; 1288 break;
1289 case 0x0122:
1290 result = sony_nc_thermal_setup(pf_device);
1291 if (result)
1292 pr_err("couldn't set up thermal profile function (%d)\n",
1293 result);
1294 break;
1285 case 0x0124: 1295 case 0x0124:
1286 case 0x0135: 1296 case 0x0135:
1287 sony_nc_rfkill_setup(device); 1297 sony_nc_rfkill_setup(device);
@@ -1323,6 +1333,9 @@ static void sony_nc_function_cleanup(struct platform_device *pd)
1323 case 0x013f: 1333 case 0x013f:
1324 sony_nc_battery_care_cleanup(pd); 1334 sony_nc_battery_care_cleanup(pd);
1325 break; 1335 break;
1336 case 0x0122:
1337 sony_nc_thermal_cleanup(pd);
1338 break;
1326 case 0x0124: 1339 case 0x0124:
1327 case 0x0135: 1340 case 0x0135:
1328 sony_nc_rfkill_cleanup(); 1341 sony_nc_rfkill_cleanup();
@@ -1362,6 +1375,9 @@ static void sony_nc_function_resume(void)
1362 /* re-enable hotkeys */ 1375 /* re-enable hotkeys */
1363 sony_call_snc_handle(handle, 0x100, &result); 1376 sony_call_snc_handle(handle, 0x100, &result);
1364 break; 1377 break;
1378 case 0x0122:
1379 sony_nc_thermal_resume();
1380 break;
1365 case 0x0124: 1381 case 0x0124:
1366 case 0x0135: 1382 case 0x0135:
1367 sony_nc_rfkill_update(); 1383 sony_nc_rfkill_update();
@@ -1923,6 +1939,173 @@ static void sony_nc_battery_care_cleanup(struct platform_device *pd)
1923 } 1939 }
1924} 1940}
1925 1941
1942struct snc_thermal_ctrl {
1943 unsigned int mode;
1944 unsigned int profiles;
1945 struct device_attribute mode_attr;
1946 struct device_attribute profiles_attr;
1947};
1948static struct snc_thermal_ctrl *th_handle;
1949
1950#define THM_PROFILE_MAX 3
1951static const char * const snc_thermal_profiles[] = {
1952 "balanced",
1953 "silent",
1954 "performance"
1955};
1956
1957static int sony_nc_thermal_mode_set(unsigned short mode)
1958{
1959 unsigned int result;
1960
1961 /* the thermal profile seems to be a two bit bitmask:
1962 * lsb -> silent
1963 * msb -> performance
1964 * no bit set is the normal operation and is always valid
1965 * Some vaio models only have "balanced" and "performance"
1966 */
1967 if ((mode && !(th_handle->profiles & mode)) || mode >= THM_PROFILE_MAX)
1968 return -EINVAL;
1969
1970 if (sony_call_snc_handle(0x0122, mode << 0x10 | 0x0200, &result))
1971 return -EIO;
1972
1973 th_handle->mode = mode;
1974
1975 return 0;
1976}
1977
1978static int sony_nc_thermal_mode_get(void)
1979{
1980 unsigned int result;
1981
1982 if (sony_call_snc_handle(0x0122, 0x0100, &result))
1983 return -EIO;
1984
1985 return result & 0xff;
1986}
1987
1988static ssize_t sony_nc_thermal_profiles_show(struct device *dev,
1989 struct device_attribute *attr, char *buffer)
1990{
1991 short cnt;
1992 size_t idx = 0;
1993
1994 for (cnt = 0; cnt < THM_PROFILE_MAX; cnt++) {
1995 if (!cnt || (th_handle->profiles & cnt))
1996 idx += snprintf(buffer + idx, PAGE_SIZE - idx, "%s ",
1997 snc_thermal_profiles[cnt]);
1998 }
1999 idx += snprintf(buffer + idx, PAGE_SIZE - idx, "\n");
2000
2001 return idx;
2002}
2003
2004static ssize_t sony_nc_thermal_mode_store(struct device *dev,
2005 struct device_attribute *attr,
2006 const char *buffer, size_t count)
2007{
2008 unsigned short cmd;
2009 size_t len = count;
2010
2011 if (count == 0)
2012 return -EINVAL;
2013
2014 /* skip the newline if present */
2015 if (buffer[len - 1] == '\n')
2016 len--;
2017
2018 for (cmd = 0; cmd < THM_PROFILE_MAX; cmd++)
2019 if (strncmp(buffer, snc_thermal_profiles[cmd], len) == 0)
2020 break;
2021
2022 if (sony_nc_thermal_mode_set(cmd))
2023 return -EIO;
2024
2025 return count;
2026}
2027
2028static ssize_t sony_nc_thermal_mode_show(struct device *dev,
2029 struct device_attribute *attr, char *buffer)
2030{
2031 ssize_t count = 0;
2032 unsigned int mode = sony_nc_thermal_mode_get();
2033
2034 if (mode < 0)
2035 return mode;
2036
2037 count = snprintf(buffer, PAGE_SIZE, "%s\n", snc_thermal_profiles[mode]);
2038
2039 return count;
2040}
2041
2042static int sony_nc_thermal_setup(struct platform_device *pd)
2043{
2044 int ret = 0;
2045 th_handle = kzalloc(sizeof(struct snc_thermal_ctrl), GFP_KERNEL);
2046 if (!th_handle)
2047 return -ENOMEM;
2048
2049 ret = sony_call_snc_handle(0x0122, 0x0000, &th_handle->profiles);
2050 if (ret) {
2051 pr_warn("couldn't to read the thermal profiles\n");
2052 goto outkzalloc;
2053 }
2054
2055 ret = sony_nc_thermal_mode_get();
2056 if (ret < 0) {
2057 pr_warn("couldn't to read the current thermal profile");
2058 goto outkzalloc;
2059 }
2060 th_handle->mode = ret;
2061
2062 sysfs_attr_init(&th_handle->profiles_attr.attr);
2063 th_handle->profiles_attr.attr.name = "thermal_profiles";
2064 th_handle->profiles_attr.attr.mode = S_IRUGO;
2065 th_handle->profiles_attr.show = sony_nc_thermal_profiles_show;
2066
2067 sysfs_attr_init(&th_handle->mode_attr.attr);
2068 th_handle->mode_attr.attr.name = "thermal_control";
2069 th_handle->mode_attr.attr.mode = S_IRUGO | S_IWUSR;
2070 th_handle->mode_attr.show = sony_nc_thermal_mode_show;
2071 th_handle->mode_attr.store = sony_nc_thermal_mode_store;
2072
2073 ret = device_create_file(&pd->dev, &th_handle->profiles_attr);
2074 if (ret)
2075 goto outkzalloc;
2076
2077 ret = device_create_file(&pd->dev, &th_handle->mode_attr);
2078 if (ret)
2079 goto outprofiles;
2080
2081 return 0;
2082
2083outprofiles:
2084 device_remove_file(&pd->dev, &th_handle->profiles_attr);
2085outkzalloc:
2086 kfree(th_handle);
2087 th_handle = NULL;
2088 return ret;
2089}
2090
2091static void sony_nc_thermal_cleanup(struct platform_device *pd)
2092{
2093 if (th_handle) {
2094 device_remove_file(&pd->dev, &th_handle->profiles_attr);
2095 device_remove_file(&pd->dev, &th_handle->mode_attr);
2096 kfree(th_handle);
2097 th_handle = NULL;
2098 }
2099}
2100
2101static void sony_nc_thermal_resume(void)
2102{
2103 unsigned int status = sony_nc_thermal_mode_get();
2104
2105 if (status != th_handle->mode)
2106 sony_nc_thermal_mode_set(th_handle->mode);
2107}
2108
1926static void sony_nc_backlight_ng_read_limits(int handle, 2109static void sony_nc_backlight_ng_read_limits(int handle,
1927 struct sony_backlight_props *props) 2110 struct sony_backlight_props *props)
1928{ 2111{