aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJavier Achirica <jachirica@gmail.com>2014-03-20 19:01:15 -0400
committerMatthew Garrett <matthew.garrett@nebula.com>2014-04-06 12:58:12 -0400
commit2a26f3415865a9540b0b8a93455eeeea90a98983 (patch)
tree80cfd94363e5bf50cde3117472d6686e086a4b9a
parent9e04c9080dfadd9bc254ffaa738f39e4796d0ab7 (diff)
sony-laptop: add usb charge function
Allows to specify if the USB socket should charge attached devices while the laptop is suspended to ram. Signed-off-by: Javier Achirica <jachirica@gmail.com> Signed-off-by: Mattia Dongili <malattia@linux.it> Signed-off-by: Matthew Garrett <matthew.garrett@nebula.com>
-rw-r--r--drivers/platform/x86/sony-laptop.c86
1 files changed, 86 insertions, 0 deletions
diff --git a/drivers/platform/x86/sony-laptop.c b/drivers/platform/x86/sony-laptop.c
index d1f712e368ce..9620285cb9af 100644
--- a/drivers/platform/x86/sony-laptop.c
+++ b/drivers/platform/x86/sony-laptop.c
@@ -164,6 +164,9 @@ static int __sony_nc_gfx_switch_status_get(void);
164static int sony_nc_highspeed_charging_setup(struct platform_device *pd); 164static int sony_nc_highspeed_charging_setup(struct platform_device *pd);
165static void sony_nc_highspeed_charging_cleanup(struct platform_device *pd); 165static void sony_nc_highspeed_charging_cleanup(struct platform_device *pd);
166 166
167static int sony_nc_usb_charge_setup(struct platform_device *pd);
168static void sony_nc_usb_charge_cleanup(struct platform_device *pd);
169
167static int sony_nc_panelid_setup(struct platform_device *pd); 170static int sony_nc_panelid_setup(struct platform_device *pd);
168static void sony_nc_panelid_cleanup(struct platform_device *pd); 171static void sony_nc_panelid_cleanup(struct platform_device *pd);
169 172
@@ -1388,6 +1391,12 @@ static void sony_nc_function_setup(struct acpi_device *device,
1388 pr_err("couldn't set up keyboard backlight function (%d)\n", 1391 pr_err("couldn't set up keyboard backlight function (%d)\n",
1389 result); 1392 result);
1390 break; 1393 break;
1394 case 0x0155:
1395 result = sony_nc_usb_charge_setup(pf_device);
1396 if (result)
1397 pr_err("couldn't set up USB charge support (%d)\n",
1398 result);
1399 break;
1391 case 0x011D: 1400 case 0x011D:
1392 result = sony_nc_panelid_setup(pf_device); 1401 result = sony_nc_panelid_setup(pf_device);
1393 if (result) 1402 if (result)
@@ -1458,6 +1467,9 @@ static void sony_nc_function_cleanup(struct platform_device *pd)
1458 case 0x0163: 1467 case 0x0163:
1459 sony_nc_kbd_backlight_cleanup(pd, handle); 1468 sony_nc_kbd_backlight_cleanup(pd, handle);
1460 break; 1469 break;
1470 case 0x0155:
1471 sony_nc_usb_charge_cleanup(pd);
1472 break;
1461 case 0x011D: 1473 case 0x011D:
1462 sony_nc_panelid_cleanup(pd); 1474 sony_nc_panelid_cleanup(pd);
1463 break; 1475 break;
@@ -2552,6 +2564,80 @@ static void sony_nc_highspeed_charging_cleanup(struct platform_device *pd)
2552 } 2564 }
2553} 2565}
2554 2566
2567/* USB charge function */
2568static struct device_attribute *uc_handle;
2569
2570static ssize_t sony_nc_usb_charge_store(struct device *dev,
2571 struct device_attribute *attr,
2572 const char *buffer, size_t count)
2573{
2574 unsigned int result;
2575 unsigned long value;
2576
2577 if (count > 31)
2578 return -EINVAL;
2579
2580 if (kstrtoul(buffer, 10, &value) || value > 1)
2581 return -EINVAL;
2582
2583 if (sony_call_snc_handle(0x0155, value << 0x10 | 0x0100, &result))
2584 return -EIO;
2585
2586 return count;
2587}
2588
2589static ssize_t sony_nc_usb_charge_show(struct device *dev,
2590 struct device_attribute *attr, char *buffer)
2591{
2592 unsigned int result;
2593
2594 if (sony_call_snc_handle(0x0155, 0x0000, &result))
2595 return -EIO;
2596
2597 return snprintf(buffer, PAGE_SIZE, "%d\n", result & 0x01);
2598}
2599
2600static int sony_nc_usb_charge_setup(struct platform_device *pd)
2601{
2602 unsigned int result;
2603
2604 if (sony_call_snc_handle(0x0155, 0x0000, &result) || !(result & 0x01)) {
2605 /* some models advertise the handle but have no implementation
2606 * for it
2607 */
2608 pr_info("No USB Charge capability found\n");
2609 return 0;
2610 }
2611
2612 uc_handle = kzalloc(sizeof(struct device_attribute), GFP_KERNEL);
2613 if (!uc_handle)
2614 return -ENOMEM;
2615
2616 sysfs_attr_init(&uc_handle->attr);
2617 uc_handle->attr.name = "usb_charge";
2618 uc_handle->attr.mode = S_IRUGO | S_IWUSR;
2619 uc_handle->show = sony_nc_usb_charge_show;
2620 uc_handle->store = sony_nc_usb_charge_store;
2621
2622 result = device_create_file(&pd->dev, uc_handle);
2623 if (result) {
2624 kfree(uc_handle);
2625 uc_handle = NULL;
2626 return result;
2627 }
2628
2629 return 0;
2630}
2631
2632static void sony_nc_usb_charge_cleanup(struct platform_device *pd)
2633{
2634 if (uc_handle) {
2635 device_remove_file(&pd->dev, uc_handle);
2636 kfree(uc_handle);
2637 uc_handle = NULL;
2638 }
2639}
2640
2555/* Panel ID function */ 2641/* Panel ID function */
2556static struct device_attribute *panel_handle; 2642static struct device_attribute *panel_handle;
2557 2643