diff options
Diffstat (limited to 'drivers/platform/x86/intel-hid.c')
-rw-r--r-- | drivers/platform/x86/intel-hid.c | 40 |
1 files changed, 35 insertions, 5 deletions
diff --git a/drivers/platform/x86/intel-hid.c b/drivers/platform/x86/intel-hid.c index 63ba2cbd04c2..8519e0f97bdd 100644 --- a/drivers/platform/x86/intel-hid.c +++ b/drivers/platform/x86/intel-hid.c | |||
@@ -23,6 +23,7 @@ | |||
23 | #include <linux/platform_device.h> | 23 | #include <linux/platform_device.h> |
24 | #include <linux/input/sparse-keymap.h> | 24 | #include <linux/input/sparse-keymap.h> |
25 | #include <linux/acpi.h> | 25 | #include <linux/acpi.h> |
26 | #include <linux/suspend.h> | ||
26 | #include <acpi/acpi_bus.h> | 27 | #include <acpi/acpi_bus.h> |
27 | 28 | ||
28 | MODULE_LICENSE("GPL"); | 29 | MODULE_LICENSE("GPL"); |
@@ -75,6 +76,7 @@ static const struct key_entry intel_array_keymap[] = { | |||
75 | struct intel_hid_priv { | 76 | struct intel_hid_priv { |
76 | struct input_dev *input_dev; | 77 | struct input_dev *input_dev; |
77 | struct input_dev *array; | 78 | struct input_dev *array; |
79 | bool wakeup_mode; | ||
78 | }; | 80 | }; |
79 | 81 | ||
80 | static int intel_hid_set_enable(struct device *device, bool enable) | 82 | static int intel_hid_set_enable(struct device *device, bool enable) |
@@ -116,23 +118,37 @@ static void intel_button_array_enable(struct device *device, bool enable) | |||
116 | dev_warn(device, "failed to set button capability\n"); | 118 | dev_warn(device, "failed to set button capability\n"); |
117 | } | 119 | } |
118 | 120 | ||
119 | static int intel_hid_pl_suspend_handler(struct device *device) | 121 | static int intel_hid_pm_prepare(struct device *device) |
120 | { | 122 | { |
121 | intel_hid_set_enable(device, false); | 123 | struct intel_hid_priv *priv = dev_get_drvdata(device); |
122 | intel_button_array_enable(device, false); | 124 | |
125 | priv->wakeup_mode = true; | ||
126 | return 0; | ||
127 | } | ||
123 | 128 | ||
129 | static int intel_hid_pl_suspend_handler(struct device *device) | ||
130 | { | ||
131 | if (pm_suspend_via_firmware()) { | ||
132 | intel_hid_set_enable(device, false); | ||
133 | intel_button_array_enable(device, false); | ||
134 | } | ||
124 | return 0; | 135 | return 0; |
125 | } | 136 | } |
126 | 137 | ||
127 | static int intel_hid_pl_resume_handler(struct device *device) | 138 | static int intel_hid_pl_resume_handler(struct device *device) |
128 | { | 139 | { |
129 | intel_hid_set_enable(device, true); | 140 | struct intel_hid_priv *priv = dev_get_drvdata(device); |
130 | intel_button_array_enable(device, true); | ||
131 | 141 | ||
142 | priv->wakeup_mode = false; | ||
143 | if (pm_resume_via_firmware()) { | ||
144 | intel_hid_set_enable(device, true); | ||
145 | intel_button_array_enable(device, true); | ||
146 | } | ||
132 | return 0; | 147 | return 0; |
133 | } | 148 | } |
134 | 149 | ||
135 | static const struct dev_pm_ops intel_hid_pl_pm_ops = { | 150 | static const struct dev_pm_ops intel_hid_pl_pm_ops = { |
151 | .prepare = intel_hid_pm_prepare, | ||
136 | .freeze = intel_hid_pl_suspend_handler, | 152 | .freeze = intel_hid_pl_suspend_handler, |
137 | .thaw = intel_hid_pl_resume_handler, | 153 | .thaw = intel_hid_pl_resume_handler, |
138 | .restore = intel_hid_pl_resume_handler, | 154 | .restore = intel_hid_pl_resume_handler, |
@@ -186,6 +202,19 @@ static void notify_handler(acpi_handle handle, u32 event, void *context) | |||
186 | unsigned long long ev_index; | 202 | unsigned long long ev_index; |
187 | acpi_status status; | 203 | acpi_status status; |
188 | 204 | ||
205 | if (priv->wakeup_mode) { | ||
206 | /* Wake up on 5-button array events only. */ | ||
207 | if (event == 0xc0 || !priv->array) | ||
208 | return; | ||
209 | |||
210 | if (sparse_keymap_entry_from_scancode(priv->array, event)) | ||
211 | pm_wakeup_hard_event(&device->dev); | ||
212 | else | ||
213 | dev_info(&device->dev, "unknown event 0x%x\n", event); | ||
214 | |||
215 | return; | ||
216 | } | ||
217 | |||
189 | /* 0xC0 is for HID events, other values are for 5 button array */ | 218 | /* 0xC0 is for HID events, other values are for 5 button array */ |
190 | if (event != 0xc0) { | 219 | if (event != 0xc0) { |
191 | if (!priv->array || | 220 | if (!priv->array || |
@@ -270,6 +299,7 @@ static int intel_hid_probe(struct platform_device *device) | |||
270 | "failed to enable HID power button\n"); | 299 | "failed to enable HID power button\n"); |
271 | } | 300 | } |
272 | 301 | ||
302 | device_init_wakeup(&device->dev, true); | ||
273 | return 0; | 303 | return 0; |
274 | 304 | ||
275 | err_remove_notify: | 305 | err_remove_notify: |