diff options
author | Javier Achirica <jachirica@gmail.com> | 2014-03-20 19:01:15 -0400 |
---|---|---|
committer | Matthew Garrett <matthew.garrett@nebula.com> | 2014-04-06 12:58:12 -0400 |
commit | 2a26f3415865a9540b0b8a93455eeeea90a98983 (patch) | |
tree | 80cfd94363e5bf50cde3117472d6686e086a4b9a | |
parent | 9e04c9080dfadd9bc254ffaa738f39e4796d0ab7 (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.c | 86 |
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); | |||
164 | static int sony_nc_highspeed_charging_setup(struct platform_device *pd); | 164 | static int sony_nc_highspeed_charging_setup(struct platform_device *pd); |
165 | static void sony_nc_highspeed_charging_cleanup(struct platform_device *pd); | 165 | static void sony_nc_highspeed_charging_cleanup(struct platform_device *pd); |
166 | 166 | ||
167 | static int sony_nc_usb_charge_setup(struct platform_device *pd); | ||
168 | static void sony_nc_usb_charge_cleanup(struct platform_device *pd); | ||
169 | |||
167 | static int sony_nc_panelid_setup(struct platform_device *pd); | 170 | static int sony_nc_panelid_setup(struct platform_device *pd); |
168 | static void sony_nc_panelid_cleanup(struct platform_device *pd); | 171 | static 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 */ | ||
2568 | static struct device_attribute *uc_handle; | ||
2569 | |||
2570 | static 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 | |||
2589 | static 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 | |||
2600 | static 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 | |||
2632 | static 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 */ |
2556 | static struct device_attribute *panel_handle; | 2642 | static struct device_attribute *panel_handle; |
2557 | 2643 | ||