aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/platform
diff options
context:
space:
mode:
authorMarco Chiappero <marco@absence.it>2012-05-19 09:35:54 -0400
committerMatthew Garrett <mjg@redhat.com>2012-05-31 14:33:35 -0400
commit54535d083f0ae6ee51a43a7a3e17e3ca89774937 (patch)
tree7b6e9feafe72be44d821d49a62ff083ca59f94e9 /drivers/platform
parentbab7084c745bf4d75b760728387f375fd34dc683 (diff)
sony-laptop: support automatic resume on lid open
A few models offer the chance to set whether to resume from S3 and/or S4 when opening the lid. [malattia@linux.it: create three sysfs files for S3/4/5 rather than using a single one accepting a bitmask. Support S5 since the DSDT exports it. Use a struct to hold all the related values, caching of the current status value rather than re-reading all the time in the sysfs show function.] 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.c140
1 files changed, 140 insertions, 0 deletions
diff --git a/drivers/platform/x86/sony-laptop.c b/drivers/platform/x86/sony-laptop.c
index 2b72e476dfff..bc7f40bcd9cc 100644
--- a/drivers/platform/x86/sony-laptop.c
+++ b/drivers/platform/x86/sony-laptop.c
@@ -152,6 +152,9 @@ static int sony_nc_thermal_setup(struct platform_device *pd);
152static void sony_nc_thermal_cleanup(struct platform_device *pd); 152static void sony_nc_thermal_cleanup(struct platform_device *pd);
153static void sony_nc_thermal_resume(void); 153static void sony_nc_thermal_resume(void);
154 154
155static int sony_nc_lid_resume_setup(struct platform_device *pd);
156static void sony_nc_lid_resume_cleanup(struct platform_device *pd);
157
155enum sony_nc_rfkill { 158enum sony_nc_rfkill {
156 SONY_WIFI, 159 SONY_WIFI,
157 SONY_BLUETOOTH, 160 SONY_BLUETOOTH,
@@ -1286,6 +1289,12 @@ static void sony_nc_function_setup(struct acpi_device *device,
1286 pr_err("couldn't set up battery care function (%d)\n", 1289 pr_err("couldn't set up battery care function (%d)\n",
1287 result); 1290 result);
1288 break; 1291 break;
1292 case 0x0119:
1293 result = sony_nc_lid_resume_setup(pf_device);
1294 if (result)
1295 pr_err("couldn't set up lid resume function (%d)\n",
1296 result);
1297 break;
1289 case 0x0122: 1298 case 0x0122:
1290 result = sony_nc_thermal_setup(pf_device); 1299 result = sony_nc_thermal_setup(pf_device);
1291 if (result) 1300 if (result)
@@ -1333,6 +1342,9 @@ static void sony_nc_function_cleanup(struct platform_device *pd)
1333 case 0x013f: 1342 case 0x013f:
1334 sony_nc_battery_care_cleanup(pd); 1343 sony_nc_battery_care_cleanup(pd);
1335 break; 1344 break;
1345 case 0x0119:
1346 sony_nc_lid_resume_cleanup(pd);
1347 break;
1336 case 0x0122: 1348 case 0x0122:
1337 sony_nc_thermal_cleanup(pd); 1349 sony_nc_thermal_cleanup(pd);
1338 break; 1350 break;
@@ -2106,6 +2118,134 @@ static void sony_nc_thermal_resume(void)
2106 sony_nc_thermal_mode_set(th_handle->mode); 2118 sony_nc_thermal_mode_set(th_handle->mode);
2107} 2119}
2108 2120
2121/* resume on LID open */
2122struct snc_lid_resume_control {
2123 struct device_attribute attrs[3];
2124 unsigned int status;
2125};
2126static struct snc_lid_resume_control *lid_ctl;
2127
2128static ssize_t sony_nc_lid_resume_store(struct device *dev,
2129 struct device_attribute *attr,
2130 const char *buffer, size_t count)
2131{
2132 unsigned int result, pos;
2133 unsigned long value;
2134 if (count > 31)
2135 return -EINVAL;
2136
2137 if (kstrtoul(buffer, 10, &value) || value > 1)
2138 return -EINVAL;
2139
2140 /* the value we have to write to SNC is a bitmask:
2141 * +--------------+
2142 * | S3 | S4 | S5 |
2143 * +--------------+
2144 * 2 1 0
2145 */
2146 if (strcmp(attr->attr.name, "lid_resume_S3") == 0)
2147 pos = 2;
2148 else if (strcmp(attr->attr.name, "lid_resume_S4") == 0)
2149 pos = 1;
2150 else if (strcmp(attr->attr.name, "lid_resume_S5") == 0)
2151 pos = 0;
2152 else
2153 return -EINVAL;
2154
2155 if (value)
2156 value = lid_ctl->status | (1 << pos);
2157 else
2158 value = lid_ctl->status & ~(1 << pos);
2159
2160 if (sony_call_snc_handle(0x0119, value << 0x10 | 0x0100, &result))
2161 return -EIO;
2162
2163 lid_ctl->status = value;
2164
2165 return count;
2166}
2167
2168static ssize_t sony_nc_lid_resume_show(struct device *dev,
2169 struct device_attribute *attr, char *buffer)
2170{
2171 unsigned int pos;
2172
2173 if (strcmp(attr->attr.name, "lid_resume_S3") == 0)
2174 pos = 2;
2175 else if (strcmp(attr->attr.name, "lid_resume_S4") == 0)
2176 pos = 1;
2177 else if (strcmp(attr->attr.name, "lid_resume_S5") == 0)
2178 pos = 0;
2179 else
2180 return -EINVAL;
2181
2182 return snprintf(buffer, PAGE_SIZE, "%d\n",
2183 (lid_ctl->status >> pos) & 0x01);
2184}
2185
2186static int sony_nc_lid_resume_setup(struct platform_device *pd)
2187{
2188 unsigned int result;
2189 int i;
2190
2191 if (sony_call_snc_handle(0x0119, 0x0000, &result))
2192 return -EIO;
2193
2194 lid_ctl = kzalloc(sizeof(struct snc_lid_resume_control), GFP_KERNEL);
2195 if (!lid_ctl)
2196 return -ENOMEM;
2197
2198 lid_ctl->status = result & 0x7;
2199
2200 sysfs_attr_init(&lid_ctl->attrs[0].attr);
2201 lid_ctl->attrs[0].attr.name = "lid_resume_S3";
2202 lid_ctl->attrs[0].attr.mode = S_IRUGO | S_IWUSR;
2203 lid_ctl->attrs[0].show = sony_nc_lid_resume_show;
2204 lid_ctl->attrs[0].store = sony_nc_lid_resume_store;
2205
2206 sysfs_attr_init(&lid_ctl->attrs[1].attr);
2207 lid_ctl->attrs[1].attr.name = "lid_resume_S4";
2208 lid_ctl->attrs[1].attr.mode = S_IRUGO | S_IWUSR;
2209 lid_ctl->attrs[1].show = sony_nc_lid_resume_show;
2210 lid_ctl->attrs[1].store = sony_nc_lid_resume_store;
2211
2212 sysfs_attr_init(&lid_ctl->attrs[2].attr);
2213 lid_ctl->attrs[2].attr.name = "lid_resume_S5";
2214 lid_ctl->attrs[2].attr.mode = S_IRUGO | S_IWUSR;
2215 lid_ctl->attrs[2].show = sony_nc_lid_resume_show;
2216 lid_ctl->attrs[2].store = sony_nc_lid_resume_store;
2217
2218 for (i = 0; i < 3; i++) {
2219 result = device_create_file(&pd->dev, &lid_ctl->attrs[i]);
2220 if (result)
2221 goto liderror;
2222 }
2223
2224 return 0;
2225
2226liderror:
2227 for (; i > 0; i--)
2228 device_remove_file(&pd->dev, &lid_ctl->attrs[i]);
2229
2230 kfree(lid_ctl);
2231 lid_ctl = NULL;
2232
2233 return result;
2234}
2235
2236static void sony_nc_lid_resume_cleanup(struct platform_device *pd)
2237{
2238 int i;
2239
2240 if (lid_ctl) {
2241 for (i = 0; i < 3; i++)
2242 device_remove_file(&pd->dev, &lid_ctl->attrs[i]);
2243
2244 kfree(lid_ctl);
2245 lid_ctl = NULL;
2246 }
2247}
2248
2109static void sony_nc_backlight_ng_read_limits(int handle, 2249static void sony_nc_backlight_ng_read_limits(int handle,
2110 struct sony_backlight_props *props) 2250 struct sony_backlight_props *props)
2111{ 2251{