aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/platform
diff options
context:
space:
mode:
authorMario Limonciello <mario_limonciello@dell.com>2016-02-02 16:38:55 -0500
committerDarren Hart <dvhart@linux.intel.com>2016-02-07 14:58:58 -0500
commit8ea81ec67b82fd35e389c3eef395206bac8e2259 (patch)
tree9f0218b9c923945ac71e55938e10e2fd39b720d1 /drivers/platform
parentcbbb50d6038bc093154fb6e209729bbf8bebd614 (diff)
alienware-wmi: Add support for deep sleep control.
Allow for user configuration of BIOS settings that allow the system to be turned on via HID devices. The feature requires hardware architectural modifications and can not be supported on existing systems. Signed-off-by: Mario Limonciello <mario_limonciello@dell.com> [dvhart: comment formatting and line length fixes] Signed-off-by: Darren Hart <dvhart@linux.intel.com>
Diffstat (limited to 'drivers/platform')
-rw-r--r--drivers/platform/x86/alienware-wmi.c95
1 files changed, 95 insertions, 0 deletions
diff --git a/drivers/platform/x86/alienware-wmi.c b/drivers/platform/x86/alienware-wmi.c
index fa86b7d5d6b5..a9f8d3044cd3 100644
--- a/drivers/platform/x86/alienware-wmi.c
+++ b/drivers/platform/x86/alienware-wmi.c
@@ -34,6 +34,8 @@
34#define WMAX_METHOD_ZONE_CONTROL 0x4 34#define WMAX_METHOD_ZONE_CONTROL 0x4
35#define WMAX_METHOD_HDMI_CABLE 0x5 35#define WMAX_METHOD_HDMI_CABLE 0x5
36#define WMAX_METHOD_AMPLIFIER_CABLE 0x6 36#define WMAX_METHOD_AMPLIFIER_CABLE 0x6
37#define WMAX_METHOD_DEEP_SLEEP_CONTROL 0x0B
38#define WMAX_METHOD_DEEP_SLEEP_STATUS 0x0C
37 39
38MODULE_AUTHOR("Mario Limonciello <mario_limonciello@dell.com>"); 40MODULE_AUTHOR("Mario Limonciello <mario_limonciello@dell.com>");
39MODULE_DESCRIPTION("Alienware special feature control"); 41MODULE_DESCRIPTION("Alienware special feature control");
@@ -62,6 +64,7 @@ struct quirk_entry {
62 u8 num_zones; 64 u8 num_zones;
63 u8 hdmi_mux; 65 u8 hdmi_mux;
64 u8 amplifier; 66 u8 amplifier;
67 u8 deepslp;
65}; 68};
66 69
67static struct quirk_entry *quirks; 70static struct quirk_entry *quirks;
@@ -70,24 +73,28 @@ static struct quirk_entry quirk_unknown = {
70 .num_zones = 2, 73 .num_zones = 2,
71 .hdmi_mux = 0, 74 .hdmi_mux = 0,
72 .amplifier = 0, 75 .amplifier = 0,
76 .deepslp = 0,
73}; 77};
74 78
75static struct quirk_entry quirk_x51_r1_r2 = { 79static struct quirk_entry quirk_x51_r1_r2 = {
76 .num_zones = 3, 80 .num_zones = 3,
77 .hdmi_mux = 0, 81 .hdmi_mux = 0,
78 .amplifier = 0, 82 .amplifier = 0,
83 .deepslp = 0,
79}; 84};
80 85
81static struct quirk_entry quirk_x51_r3 = { 86static struct quirk_entry quirk_x51_r3 = {
82 .num_zones = 4, 87 .num_zones = 4,
83 .hdmi_mux = 0, 88 .hdmi_mux = 0,
84 .amplifier = 1, 89 .amplifier = 1,
90 .deepslp = 0,
85}; 91};
86 92
87static struct quirk_entry quirk_asm100 = { 93static struct quirk_entry quirk_asm100 = {
88 .num_zones = 2, 94 .num_zones = 2,
89 .hdmi_mux = 1, 95 .hdmi_mux = 1,
90 .amplifier = 0, 96 .amplifier = 0,
97 .deepslp = 0,
91}; 98};
92 99
93static int __init dmi_matched(const struct dmi_system_id *dmi) 100static int __init dmi_matched(const struct dmi_system_id *dmi)
@@ -647,6 +654,87 @@ static int create_amplifier(struct platform_device *dev)
647 return ret; 654 return ret;
648} 655}
649 656
657/*
658 * Deep Sleep Control support
659 * - Modifies BIOS setting for deep sleep control allowing extra wakeup events
660 */
661static ssize_t show_deepsleep_status(struct device *dev,
662 struct device_attribute *attr, char *buf)
663{
664 acpi_status status;
665 u32 out_data;
666 struct wmax_basic_args in_args = {
667 .arg = 0,
668 };
669 status = alienware_wmax_command(&in_args, WMAX_METHOD_DEEP_SLEEP_STATUS,
670 (u32 *) &out_data);
671 if (ACPI_SUCCESS(status)) {
672 if (out_data == 0)
673 return scnprintf(buf, PAGE_SIZE,
674 "[disabled] s5 s5_s4\n");
675 else if (out_data == 1)
676 return scnprintf(buf, PAGE_SIZE,
677 "disabled [s5] s5_s4\n");
678 else if (out_data == 2)
679 return scnprintf(buf, PAGE_SIZE,
680 "disabled s5 [s5_s4]\n");
681 }
682 pr_err("alienware-wmi: unknown deep sleep status: %d\n", status);
683 return scnprintf(buf, PAGE_SIZE, "disabled s5 s5_s4 [unknown]\n");
684}
685
686static ssize_t toggle_deepsleep(struct device *dev,
687 struct device_attribute *attr,
688 const char *buf, size_t count)
689{
690 acpi_status status;
691 struct wmax_basic_args args;
692
693 if (strcmp(buf, "disabled\n") == 0)
694 args.arg = 0;
695 else if (strcmp(buf, "s5\n") == 0)
696 args.arg = 1;
697 else
698 args.arg = 2;
699 pr_debug("alienware-wmi: setting deep sleep to %d : %s", args.arg, buf);
700
701 status = alienware_wmax_command(&args, WMAX_METHOD_DEEP_SLEEP_CONTROL,
702 NULL);
703
704 if (ACPI_FAILURE(status))
705 pr_err("alienware-wmi: deep sleep control failed: results: %u\n",
706 status);
707 return count;
708}
709
710static DEVICE_ATTR(deepsleep, S_IRUGO | S_IWUSR, show_deepsleep_status, toggle_deepsleep);
711
712static struct attribute *deepsleep_attrs[] = {
713 &dev_attr_deepsleep.attr,
714 NULL,
715};
716
717static struct attribute_group deepsleep_attribute_group = {
718 .name = "deepsleep",
719 .attrs = deepsleep_attrs,
720};
721
722static void remove_deepsleep(struct platform_device *dev)
723{
724 if (quirks->deepslp > 0)
725 sysfs_remove_group(&dev->dev.kobj, &deepsleep_attribute_group);
726}
727
728static int create_deepsleep(struct platform_device *dev)
729{
730 int ret;
731
732 ret = sysfs_create_group(&dev->dev.kobj, &deepsleep_attribute_group);
733 if (ret)
734 remove_deepsleep(dev);
735 return ret;
736}
737
650static int __init alienware_wmi_init(void) 738static int __init alienware_wmi_init(void)
651{ 739{
652 int ret; 740 int ret;
@@ -688,6 +776,12 @@ static int __init alienware_wmi_init(void)
688 goto fail_prep_amplifier; 776 goto fail_prep_amplifier;
689 } 777 }
690 778
779 if (quirks->deepslp > 0) {
780 ret = create_deepsleep(platform_device);
781 if (ret)
782 goto fail_prep_deepsleep;
783 }
784
691 ret = alienware_zone_init(platform_device); 785 ret = alienware_zone_init(platform_device);
692 if (ret) 786 if (ret)
693 goto fail_prep_zones; 787 goto fail_prep_zones;
@@ -696,6 +790,7 @@ static int __init alienware_wmi_init(void)
696 790
697fail_prep_zones: 791fail_prep_zones:
698 alienware_zone_exit(platform_device); 792 alienware_zone_exit(platform_device);
793fail_prep_deepsleep:
699fail_prep_amplifier: 794fail_prep_amplifier:
700fail_prep_hdmi: 795fail_prep_hdmi:
701 platform_device_del(platform_device); 796 platform_device_del(platform_device);