diff options
author | Javier Achirica <jachirica@gmail.com> | 2014-03-20 19:01:16 -0400 |
---|---|---|
committer | Matthew Garrett <matthew.garrett@nebula.com> | 2014-04-06 12:58:12 -0400 |
commit | c62f15395c780fff606cfec23d66417a80a5ad81 (patch) | |
tree | 5a94e892b5686b12dee564c31345ebb8d84ca9d7 | |
parent | 2a26f3415865a9540b0b8a93455eeeea90a98983 (diff) |
sony-laptop: add fan speed regulation function
Rework error exit logic by Mattia Dongili.
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 | 119 |
1 files changed, 119 insertions, 0 deletions
diff --git a/drivers/platform/x86/sony-laptop.c b/drivers/platform/x86/sony-laptop.c index 9620285cb9af..7b5a56d59bac 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_fanspeed_setup(struct platform_device *pd); | ||
168 | static void sony_nc_fanspeed_cleanup(struct platform_device *pd); | ||
169 | |||
167 | static int sony_nc_usb_charge_setup(struct platform_device *pd); | 170 | static int sony_nc_usb_charge_setup(struct platform_device *pd); |
168 | static void sony_nc_usb_charge_cleanup(struct platform_device *pd); | 171 | static void sony_nc_usb_charge_cleanup(struct platform_device *pd); |
169 | 172 | ||
@@ -1391,6 +1394,12 @@ static void sony_nc_function_setup(struct acpi_device *device, | |||
1391 | pr_err("couldn't set up keyboard backlight function (%d)\n", | 1394 | pr_err("couldn't set up keyboard backlight function (%d)\n", |
1392 | result); | 1395 | result); |
1393 | break; | 1396 | break; |
1397 | case 0x0149: | ||
1398 | result = sony_nc_fanspeed_setup(pf_device); | ||
1399 | if (result) | ||
1400 | pr_err("couldn't set up fan speed function (%d)\n", | ||
1401 | result); | ||
1402 | break; | ||
1394 | case 0x0155: | 1403 | case 0x0155: |
1395 | result = sony_nc_usb_charge_setup(pf_device); | 1404 | result = sony_nc_usb_charge_setup(pf_device); |
1396 | if (result) | 1405 | if (result) |
@@ -1467,6 +1476,9 @@ static void sony_nc_function_cleanup(struct platform_device *pd) | |||
1467 | case 0x0163: | 1476 | case 0x0163: |
1468 | sony_nc_kbd_backlight_cleanup(pd, handle); | 1477 | sony_nc_kbd_backlight_cleanup(pd, handle); |
1469 | break; | 1478 | break; |
1479 | case 0x0149: | ||
1480 | sony_nc_fanspeed_cleanup(pd); | ||
1481 | break; | ||
1470 | case 0x0155: | 1482 | case 0x0155: |
1471 | sony_nc_usb_charge_cleanup(pd); | 1483 | sony_nc_usb_charge_cleanup(pd); |
1472 | break; | 1484 | break; |
@@ -2564,6 +2576,113 @@ static void sony_nc_highspeed_charging_cleanup(struct platform_device *pd) | |||
2564 | } | 2576 | } |
2565 | } | 2577 | } |
2566 | 2578 | ||
2579 | /* fan speed function */ | ||
2580 | static struct device_attribute *fan_handle, *hsf_handle; | ||
2581 | |||
2582 | static ssize_t sony_nc_hsfan_store(struct device *dev, | ||
2583 | struct device_attribute *attr, | ||
2584 | const char *buffer, size_t count) | ||
2585 | { | ||
2586 | unsigned int result; | ||
2587 | unsigned long value; | ||
2588 | |||
2589 | if (count > 31) | ||
2590 | return -EINVAL; | ||
2591 | |||
2592 | if (kstrtoul(buffer, 10, &value) || value > 1) | ||
2593 | return -EINVAL; | ||
2594 | |||
2595 | if (sony_call_snc_handle(0x0149, value << 0x10 | 0x0200, &result)) | ||
2596 | return -EIO; | ||
2597 | |||
2598 | return count; | ||
2599 | } | ||
2600 | |||
2601 | static ssize_t sony_nc_hsfan_show(struct device *dev, | ||
2602 | struct device_attribute *attr, char *buffer) | ||
2603 | { | ||
2604 | unsigned int result; | ||
2605 | |||
2606 | if (sony_call_snc_handle(0x0149, 0x0100, &result)) | ||
2607 | return -EIO; | ||
2608 | |||
2609 | return snprintf(buffer, PAGE_SIZE, "%d\n", result & 0x01); | ||
2610 | } | ||
2611 | |||
2612 | static ssize_t sony_nc_fanspeed_show(struct device *dev, | ||
2613 | struct device_attribute *attr, char *buffer) | ||
2614 | { | ||
2615 | unsigned int result; | ||
2616 | |||
2617 | if (sony_call_snc_handle(0x0149, 0x0300, &result)) | ||
2618 | return -EIO; | ||
2619 | |||
2620 | return snprintf(buffer, PAGE_SIZE, "%d\n", result & 0xff); | ||
2621 | } | ||
2622 | |||
2623 | static int sony_nc_fanspeed_setup(struct platform_device *pd) | ||
2624 | { | ||
2625 | unsigned int result; | ||
2626 | |||
2627 | fan_handle = kzalloc(sizeof(struct device_attribute), GFP_KERNEL); | ||
2628 | if (!fan_handle) | ||
2629 | return -ENOMEM; | ||
2630 | |||
2631 | hsf_handle = kzalloc(sizeof(struct device_attribute), GFP_KERNEL); | ||
2632 | if (!hsf_handle) { | ||
2633 | result = -ENOMEM; | ||
2634 | goto out_hsf_handle_alloc; | ||
2635 | } | ||
2636 | |||
2637 | sysfs_attr_init(&fan_handle->attr); | ||
2638 | fan_handle->attr.name = "fanspeed"; | ||
2639 | fan_handle->attr.mode = S_IRUGO; | ||
2640 | fan_handle->show = sony_nc_fanspeed_show; | ||
2641 | fan_handle->store = NULL; | ||
2642 | |||
2643 | sysfs_attr_init(&hsf_handle->attr); | ||
2644 | hsf_handle->attr.name = "fan_forced"; | ||
2645 | hsf_handle->attr.mode = S_IRUGO | S_IWUSR; | ||
2646 | hsf_handle->show = sony_nc_hsfan_show; | ||
2647 | hsf_handle->store = sony_nc_hsfan_store; | ||
2648 | |||
2649 | result = device_create_file(&pd->dev, fan_handle); | ||
2650 | if (result) | ||
2651 | goto out_fan_handle; | ||
2652 | |||
2653 | result = device_create_file(&pd->dev, hsf_handle); | ||
2654 | if (result) | ||
2655 | goto out_hsf_handle; | ||
2656 | |||
2657 | return 0; | ||
2658 | |||
2659 | out_hsf_handle: | ||
2660 | device_remove_file(&pd->dev, fan_handle); | ||
2661 | |||
2662 | out_fan_handle: | ||
2663 | kfree(hsf_handle); | ||
2664 | hsf_handle = NULL; | ||
2665 | |||
2666 | out_hsf_handle_alloc: | ||
2667 | kfree(fan_handle); | ||
2668 | fan_handle = NULL; | ||
2669 | return result; | ||
2670 | } | ||
2671 | |||
2672 | static void sony_nc_fanspeed_cleanup(struct platform_device *pd) | ||
2673 | { | ||
2674 | if (fan_handle) { | ||
2675 | device_remove_file(&pd->dev, fan_handle); | ||
2676 | kfree(fan_handle); | ||
2677 | fan_handle = NULL; | ||
2678 | } | ||
2679 | if (hsf_handle) { | ||
2680 | device_remove_file(&pd->dev, hsf_handle); | ||
2681 | kfree(hsf_handle); | ||
2682 | hsf_handle = NULL; | ||
2683 | } | ||
2684 | } | ||
2685 | |||
2567 | /* USB charge function */ | 2686 | /* USB charge function */ |
2568 | static struct device_attribute *uc_handle; | 2687 | static struct device_attribute *uc_handle; |
2569 | 2688 | ||