aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/platform
diff options
context:
space:
mode:
authorMattia Dongili <malattia@linux.it>2012-12-20 17:21:10 -0500
committerMatthew Garrett <matthew.garrett@nebula.com>2013-02-27 08:30:36 -0500
commit3a7abcd809e75b3588dd4a6529238e2a9b009c9a (patch)
tree44b9cdafdb810ea5dfad3b458d99c44a0f856633 /drivers/platform
parent3ec1c3983d73b1e3d4cfd72afab94c34eceafe8a (diff)
sony-laptop: allow reading the status of gfx switch
Signed-off-by: Mattia Dongili <malattia@linux.it> Signed-off-by: Matthew Garrett <matthew.garrett@nebula.com>
Diffstat (limited to 'drivers/platform')
-rw-r--r--drivers/platform/x86/sony-laptop.c121
1 files changed, 112 insertions, 9 deletions
diff --git a/drivers/platform/x86/sony-laptop.c b/drivers/platform/x86/sony-laptop.c
index 0bee6c2f8864..46c71f49a6b4 100644
--- a/drivers/platform/x86/sony-laptop.c
+++ b/drivers/platform/x86/sony-laptop.c
@@ -158,6 +158,11 @@ static void sony_nc_thermal_cleanup(struct platform_device *pd);
158static int sony_nc_lid_resume_setup(struct platform_device *pd); 158static int sony_nc_lid_resume_setup(struct platform_device *pd);
159static void sony_nc_lid_resume_cleanup(struct platform_device *pd); 159static void sony_nc_lid_resume_cleanup(struct platform_device *pd);
160 160
161static int sony_nc_gfx_switch_setup(struct platform_device *pd,
162 unsigned int handle);
163static void sony_nc_gfx_switch_cleanup(struct platform_device *pd);
164static int __sony_nc_gfx_switch_status_get(void);
165
161static int sony_nc_highspeed_charging_setup(struct platform_device *pd); 166static int sony_nc_highspeed_charging_setup(struct platform_device *pd);
162static void sony_nc_highspeed_charging_cleanup(struct platform_device *pd); 167static void sony_nc_highspeed_charging_cleanup(struct platform_device *pd);
163 168
@@ -1241,17 +1246,13 @@ static void sony_nc_notify(struct acpi_device *device, u32 event)
1241 /* Hybrid GFX switching */ 1246 /* Hybrid GFX switching */
1242 sony_call_snc_handle(handle, 0x0000, &result); 1247 sony_call_snc_handle(handle, 0x0000, &result);
1243 dprintk("GFX switch event received (reason: %s)\n", 1248 dprintk("GFX switch event received (reason: %s)\n",
1244 (result & 0x01) ? 1249 (result == 0x1) ? "switch change" :
1245 "switch change" : "unknown"); 1250 (result == 0x2) ? "output switch" :
1246 1251 (result == 0x3) ? "output switch" :
1247 /* verify the switch state 1252 "");
1248 * 1: discrete GFX
1249 * 0: integrated GFX
1250 */
1251 sony_call_snc_handle(handle, 0x0100, &result);
1252 1253
1253 ev_type = GFX_SWITCH; 1254 ev_type = GFX_SWITCH;
1254 real_ev = result & 0xff; 1255 real_ev = __sony_nc_gfx_switch_status_get();
1255 break; 1256 break;
1256 1257
1257 default: 1258 default:
@@ -1350,6 +1351,13 @@ static void sony_nc_function_setup(struct acpi_device *device,
1350 pr_err("couldn't set up thermal profile function (%d)\n", 1351 pr_err("couldn't set up thermal profile function (%d)\n",
1351 result); 1352 result);
1352 break; 1353 break;
1354 case 0x0128:
1355 case 0x0146:
1356 result = sony_nc_gfx_switch_setup(pf_device, handle);
1357 if (result)
1358 pr_err("couldn't set up GFX Switch status (%d)\n",
1359 result);
1360 break;
1353 case 0x0131: 1361 case 0x0131:
1354 result = sony_nc_highspeed_charging_setup(pf_device); 1362 result = sony_nc_highspeed_charging_setup(pf_device);
1355 if (result) 1363 if (result)
@@ -1414,6 +1422,10 @@ static void sony_nc_function_cleanup(struct platform_device *pd)
1414 case 0x0122: 1422 case 0x0122:
1415 sony_nc_thermal_cleanup(pd); 1423 sony_nc_thermal_cleanup(pd);
1416 break; 1424 break;
1425 case 0x0128:
1426 case 0x0146:
1427 sony_nc_gfx_switch_cleanup(pd);
1428 break;
1417 case 0x0131: 1429 case 0x0131:
1418 sony_nc_highspeed_charging_cleanup(pd); 1430 sony_nc_highspeed_charging_cleanup(pd);
1419 break; 1431 break;
@@ -2355,6 +2367,97 @@ static void sony_nc_lid_resume_cleanup(struct platform_device *pd)
2355 } 2367 }
2356} 2368}
2357 2369
2370/* GFX Switch position */
2371enum gfx_switch {
2372 SPEED,
2373 STAMINA,
2374 AUTO
2375};
2376struct snc_gfx_switch_control {
2377 struct device_attribute attr;
2378 unsigned int handle;
2379};
2380static struct snc_gfx_switch_control *gfxs_ctl;
2381
2382/* returns 0 for speed, 1 for stamina */
2383static int __sony_nc_gfx_switch_status_get(void)
2384{
2385 unsigned int result;
2386
2387 if (sony_call_snc_handle(gfxs_ctl->handle, 0x0100, &result))
2388 return -EIO;
2389
2390 switch (gfxs_ctl->handle) {
2391 case 0x0146:
2392 /* 1: discrete GFX (speed)
2393 * 0: integrated GFX (stamina)
2394 */
2395 return result & 0x1 ? SPEED : STAMINA;
2396 break;
2397 case 0x0128:
2398 /* it's a more elaborated bitmask, for now:
2399 * 2: integrated GFX (stamina)
2400 * 0: discrete GFX (speed)
2401 */
2402 dprintk("GFX Status: 0x%x\n", result);
2403 return result & 0x80 ? AUTO :
2404 result & 0x02 ? STAMINA : SPEED;
2405 break;
2406 }
2407 return -EINVAL;
2408}
2409
2410static ssize_t sony_nc_gfx_switch_status_show(struct device *dev,
2411 struct device_attribute *attr,
2412 char *buffer)
2413{
2414 int pos = __sony_nc_gfx_switch_status_get();
2415
2416 if (pos < 0)
2417 return pos;
2418
2419 return snprintf(buffer, PAGE_SIZE, "%s\n", pos ? "speed" : "stamina");
2420}
2421
2422static int sony_nc_gfx_switch_setup(struct platform_device *pd,
2423 unsigned int handle)
2424{
2425 unsigned int result;
2426
2427 gfxs_ctl = kzalloc(sizeof(struct snc_gfx_switch_control), GFP_KERNEL);
2428 if (!gfxs_ctl)
2429 return -ENOMEM;
2430
2431 gfxs_ctl->handle = handle;
2432
2433 sysfs_attr_init(&gfxs_ctl->attr.attr);
2434 gfxs_ctl->attr.attr.name = "gfx_switch_status";
2435 gfxs_ctl->attr.attr.mode = S_IRUGO;
2436 gfxs_ctl->attr.show = sony_nc_gfx_switch_status_show;
2437
2438 result = device_create_file(&pd->dev, &gfxs_ctl->attr);
2439 if (result)
2440 goto gfxerror;
2441
2442 return 0;
2443
2444gfxerror:
2445 kfree(gfxs_ctl);
2446 gfxs_ctl = NULL;
2447
2448 return result;
2449}
2450
2451static void sony_nc_gfx_switch_cleanup(struct platform_device *pd)
2452{
2453 if (gfxs_ctl) {
2454 device_remove_file(&pd->dev, &gfxs_ctl->attr);
2455
2456 kfree(gfxs_ctl);
2457 gfxs_ctl = NULL;
2458 }
2459}
2460
2358/* High speed charging function */ 2461/* High speed charging function */
2359static struct device_attribute *hsc_handle; 2462static struct device_attribute *hsc_handle;
2360 2463