aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/platform
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/platform')
-rw-r--r--drivers/platform/x86/Kconfig6
-rw-r--r--drivers/platform/x86/apple-gmux.c426
-rw-r--r--drivers/platform/x86/asus-wmi.c21
-rw-r--r--drivers/platform/x86/asus-wmi.h1
-rw-r--r--drivers/platform/x86/classmate-laptop.c16
-rw-r--r--drivers/platform/x86/dell-laptop.c12
-rw-r--r--drivers/platform/x86/fujitsu-tablet.c2
-rw-r--r--drivers/platform/x86/hdaps.c2
-rw-r--r--drivers/platform/x86/hp_accel.c2
-rw-r--r--drivers/platform/x86/ideapad-laptop.c110
-rw-r--r--drivers/platform/x86/msi-laptop.c4
-rw-r--r--drivers/platform/x86/panasonic-laptop.c4
-rw-r--r--drivers/platform/x86/sony-laptop.c12
-rw-r--r--drivers/platform/x86/thinkpad_acpi.c9
-rw-r--r--drivers/platform/x86/toshiba_acpi.c2
-rw-r--r--drivers/platform/x86/toshiba_bluetooth.c4
-rw-r--r--drivers/platform/x86/xo15-ebook.c2
17 files changed, 595 insertions, 40 deletions
diff --git a/drivers/platform/x86/Kconfig b/drivers/platform/x86/Kconfig
index 2a262f5c5c0c..c86bae828c28 100644
--- a/drivers/platform/x86/Kconfig
+++ b/drivers/platform/x86/Kconfig
@@ -289,6 +289,7 @@ config IDEAPAD_LAPTOP
289 tristate "Lenovo IdeaPad Laptop Extras" 289 tristate "Lenovo IdeaPad Laptop Extras"
290 depends on ACPI 290 depends on ACPI
291 depends on RFKILL && INPUT 291 depends on RFKILL && INPUT
292 depends on SERIO_I8042
292 select INPUT_SPARSEKMAP 293 select INPUT_SPARSEKMAP
293 help 294 help
294 This is a driver for the rfkill switches on Lenovo IdeaPad netbooks. 295 This is a driver for the rfkill switches on Lenovo IdeaPad netbooks.
@@ -758,8 +759,11 @@ config SAMSUNG_Q10
758 759
759config APPLE_GMUX 760config APPLE_GMUX
760 tristate "Apple Gmux Driver" 761 tristate "Apple Gmux Driver"
762 depends on ACPI
761 depends on PNP 763 depends on PNP
762 select BACKLIGHT_CLASS_DEVICE 764 depends on BACKLIGHT_CLASS_DEVICE
765 depends on BACKLIGHT_APPLE=n || BACKLIGHT_APPLE
766 depends on ACPI_VIDEO=n || ACPI_VIDEO
763 ---help--- 767 ---help---
764 This driver provides support for the gmux device found on many 768 This driver provides support for the gmux device found on many
765 Apple laptops, which controls the display mux for the hybrid 769 Apple laptops, which controls the display mux for the hybrid
diff --git a/drivers/platform/x86/apple-gmux.c b/drivers/platform/x86/apple-gmux.c
index 905fa01ac8df..dfb1a92ce949 100644
--- a/drivers/platform/x86/apple-gmux.c
+++ b/drivers/platform/x86/apple-gmux.c
@@ -2,6 +2,7 @@
2 * Gmux driver for Apple laptops 2 * Gmux driver for Apple laptops
3 * 3 *
4 * Copyright (C) Canonical Ltd. <seth.forshee@canonical.com> 4 * Copyright (C) Canonical Ltd. <seth.forshee@canonical.com>
5 * Copyright (C) 2010-2012 Andreas Heider <andreas@meetr.de>
5 * 6 *
6 * This program is free software; you can redistribute it and/or modify 7 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License version 2 as 8 * it under the terms of the GNU General Public License version 2 as
@@ -18,16 +19,30 @@
18#include <linux/pnp.h> 19#include <linux/pnp.h>
19#include <linux/apple_bl.h> 20#include <linux/apple_bl.h>
20#include <linux/slab.h> 21#include <linux/slab.h>
22#include <linux/delay.h>
23#include <linux/pci.h>
24#include <linux/vga_switcheroo.h>
21#include <acpi/video.h> 25#include <acpi/video.h>
22#include <asm/io.h> 26#include <asm/io.h>
23 27
24struct apple_gmux_data { 28struct apple_gmux_data {
25 unsigned long iostart; 29 unsigned long iostart;
26 unsigned long iolen; 30 unsigned long iolen;
31 bool indexed;
32 struct mutex index_lock;
27 33
28 struct backlight_device *bdev; 34 struct backlight_device *bdev;
35
36 /* switcheroo data */
37 acpi_handle dhandle;
38 int gpe;
39 enum vga_switcheroo_client_id resume_client_id;
40 enum vga_switcheroo_state power_state;
41 struct completion powerchange_done;
29}; 42};
30 43
44static struct apple_gmux_data *apple_gmux_data;
45
31/* 46/*
32 * gmux port offsets. Many of these are not yet used, but may be in the 47 * gmux port offsets. Many of these are not yet used, but may be in the
33 * future, and it's useful to have them documented here anyhow. 48 * future, and it's useful to have them documented here anyhow.
@@ -45,6 +60,9 @@ struct apple_gmux_data {
45#define GMUX_PORT_DISCRETE_POWER 0x50 60#define GMUX_PORT_DISCRETE_POWER 0x50
46#define GMUX_PORT_MAX_BRIGHTNESS 0x70 61#define GMUX_PORT_MAX_BRIGHTNESS 0x70
47#define GMUX_PORT_BRIGHTNESS 0x74 62#define GMUX_PORT_BRIGHTNESS 0x74
63#define GMUX_PORT_VALUE 0xc2
64#define GMUX_PORT_READ 0xd0
65#define GMUX_PORT_WRITE 0xd4
48 66
49#define GMUX_MIN_IO_LEN (GMUX_PORT_BRIGHTNESS + 4) 67#define GMUX_MIN_IO_LEN (GMUX_PORT_BRIGHTNESS + 4)
50 68
@@ -59,22 +77,172 @@ struct apple_gmux_data {
59#define GMUX_BRIGHTNESS_MASK 0x00ffffff 77#define GMUX_BRIGHTNESS_MASK 0x00ffffff
60#define GMUX_MAX_BRIGHTNESS GMUX_BRIGHTNESS_MASK 78#define GMUX_MAX_BRIGHTNESS GMUX_BRIGHTNESS_MASK
61 79
62static inline u8 gmux_read8(struct apple_gmux_data *gmux_data, int port) 80static u8 gmux_pio_read8(struct apple_gmux_data *gmux_data, int port)
63{ 81{
64 return inb(gmux_data->iostart + port); 82 return inb(gmux_data->iostart + port);
65} 83}
66 84
67static inline void gmux_write8(struct apple_gmux_data *gmux_data, int port, 85static void gmux_pio_write8(struct apple_gmux_data *gmux_data, int port,
68 u8 val) 86 u8 val)
69{ 87{
70 outb(val, gmux_data->iostart + port); 88 outb(val, gmux_data->iostart + port);
71} 89}
72 90
73static inline u32 gmux_read32(struct apple_gmux_data *gmux_data, int port) 91static u32 gmux_pio_read32(struct apple_gmux_data *gmux_data, int port)
74{ 92{
75 return inl(gmux_data->iostart + port); 93 return inl(gmux_data->iostart + port);
76} 94}
77 95
96static void gmux_pio_write32(struct apple_gmux_data *gmux_data, int port,
97 u32 val)
98{
99 int i;
100 u8 tmpval;
101
102 for (i = 0; i < 4; i++) {
103 tmpval = (val >> (i * 8)) & 0xff;
104 outb(tmpval, port + i);
105 }
106}
107
108static int gmux_index_wait_ready(struct apple_gmux_data *gmux_data)
109{
110 int i = 200;
111 u8 gwr = inb(gmux_data->iostart + GMUX_PORT_WRITE);
112
113 while (i && (gwr & 0x01)) {
114 inb(gmux_data->iostart + GMUX_PORT_READ);
115 gwr = inb(gmux_data->iostart + GMUX_PORT_WRITE);
116 udelay(100);
117 i--;
118 }
119
120 return !!i;
121}
122
123static int gmux_index_wait_complete(struct apple_gmux_data *gmux_data)
124{
125 int i = 200;
126 u8 gwr = inb(gmux_data->iostart + GMUX_PORT_WRITE);
127
128 while (i && !(gwr & 0x01)) {
129 gwr = inb(gmux_data->iostart + GMUX_PORT_WRITE);
130 udelay(100);
131 i--;
132 }
133
134 if (gwr & 0x01)
135 inb(gmux_data->iostart + GMUX_PORT_READ);
136
137 return !!i;
138}
139
140static u8 gmux_index_read8(struct apple_gmux_data *gmux_data, int port)
141{
142 u8 val;
143
144 mutex_lock(&gmux_data->index_lock);
145 outb((port & 0xff), gmux_data->iostart + GMUX_PORT_READ);
146 gmux_index_wait_ready(gmux_data);
147 val = inb(gmux_data->iostart + GMUX_PORT_VALUE);
148 mutex_unlock(&gmux_data->index_lock);
149
150 return val;
151}
152
153static void gmux_index_write8(struct apple_gmux_data *gmux_data, int port,
154 u8 val)
155{
156 mutex_lock(&gmux_data->index_lock);
157 outb(val, gmux_data->iostart + GMUX_PORT_VALUE);
158 gmux_index_wait_ready(gmux_data);
159 outb(port & 0xff, gmux_data->iostart + GMUX_PORT_WRITE);
160 gmux_index_wait_complete(gmux_data);
161 mutex_unlock(&gmux_data->index_lock);
162}
163
164static u32 gmux_index_read32(struct apple_gmux_data *gmux_data, int port)
165{
166 u32 val;
167
168 mutex_lock(&gmux_data->index_lock);
169 outb((port & 0xff), gmux_data->iostart + GMUX_PORT_READ);
170 gmux_index_wait_ready(gmux_data);
171 val = inl(gmux_data->iostart + GMUX_PORT_VALUE);
172 mutex_unlock(&gmux_data->index_lock);
173
174 return val;
175}
176
177static void gmux_index_write32(struct apple_gmux_data *gmux_data, int port,
178 u32 val)
179{
180 int i;
181 u8 tmpval;
182
183 mutex_lock(&gmux_data->index_lock);
184
185 for (i = 0; i < 4; i++) {
186 tmpval = (val >> (i * 8)) & 0xff;
187 outb(tmpval, gmux_data->iostart + GMUX_PORT_VALUE + i);
188 }
189
190 gmux_index_wait_ready(gmux_data);
191 outb(port & 0xff, gmux_data->iostart + GMUX_PORT_WRITE);
192 gmux_index_wait_complete(gmux_data);
193 mutex_unlock(&gmux_data->index_lock);
194}
195
196static u8 gmux_read8(struct apple_gmux_data *gmux_data, int port)
197{
198 if (gmux_data->indexed)
199 return gmux_index_read8(gmux_data, port);
200 else
201 return gmux_pio_read8(gmux_data, port);
202}
203
204static void gmux_write8(struct apple_gmux_data *gmux_data, int port, u8 val)
205{
206 if (gmux_data->indexed)
207 gmux_index_write8(gmux_data, port, val);
208 else
209 gmux_pio_write8(gmux_data, port, val);
210}
211
212static u32 gmux_read32(struct apple_gmux_data *gmux_data, int port)
213{
214 if (gmux_data->indexed)
215 return gmux_index_read32(gmux_data, port);
216 else
217 return gmux_pio_read32(gmux_data, port);
218}
219
220static void gmux_write32(struct apple_gmux_data *gmux_data, int port,
221 u32 val)
222{
223 if (gmux_data->indexed)
224 gmux_index_write32(gmux_data, port, val);
225 else
226 gmux_pio_write32(gmux_data, port, val);
227}
228
229static bool gmux_is_indexed(struct apple_gmux_data *gmux_data)
230{
231 u16 val;
232
233 outb(0xaa, gmux_data->iostart + 0xcc);
234 outb(0x55, gmux_data->iostart + 0xcd);
235 outb(0x00, gmux_data->iostart + 0xce);
236
237 val = inb(gmux_data->iostart + 0xcc) |
238 (inb(gmux_data->iostart + 0xcd) << 8);
239
240 if (val == 0x55aa)
241 return true;
242
243 return false;
244}
245
78static int gmux_get_brightness(struct backlight_device *bd) 246static int gmux_get_brightness(struct backlight_device *bd)
79{ 247{
80 struct apple_gmux_data *gmux_data = bl_get_data(bd); 248 struct apple_gmux_data *gmux_data = bl_get_data(bd);
@@ -90,16 +258,7 @@ static int gmux_update_status(struct backlight_device *bd)
90 if (bd->props.state & BL_CORE_SUSPENDED) 258 if (bd->props.state & BL_CORE_SUSPENDED)
91 return 0; 259 return 0;
92 260
93 /* 261 gmux_write32(gmux_data, GMUX_PORT_BRIGHTNESS, brightness);
94 * Older gmux versions require writing out lower bytes first then
95 * setting the upper byte to 0 to flush the values. Newer versions
96 * accept a single u32 write, but the old method also works, so we
97 * just use the old method for all gmux versions.
98 */
99 gmux_write8(gmux_data, GMUX_PORT_BRIGHTNESS, brightness);
100 gmux_write8(gmux_data, GMUX_PORT_BRIGHTNESS + 1, brightness >> 8);
101 gmux_write8(gmux_data, GMUX_PORT_BRIGHTNESS + 2, brightness >> 16);
102 gmux_write8(gmux_data, GMUX_PORT_BRIGHTNESS + 3, 0);
103 262
104 return 0; 263 return 0;
105} 264}
@@ -110,6 +269,146 @@ static const struct backlight_ops gmux_bl_ops = {
110 .update_status = gmux_update_status, 269 .update_status = gmux_update_status,
111}; 270};
112 271
272static int gmux_switchto(enum vga_switcheroo_client_id id)
273{
274 if (id == VGA_SWITCHEROO_IGD) {
275 gmux_write8(apple_gmux_data, GMUX_PORT_SWITCH_DDC, 1);
276 gmux_write8(apple_gmux_data, GMUX_PORT_SWITCH_DISPLAY, 2);
277 gmux_write8(apple_gmux_data, GMUX_PORT_SWITCH_EXTERNAL, 2);
278 } else {
279 gmux_write8(apple_gmux_data, GMUX_PORT_SWITCH_DDC, 2);
280 gmux_write8(apple_gmux_data, GMUX_PORT_SWITCH_DISPLAY, 3);
281 gmux_write8(apple_gmux_data, GMUX_PORT_SWITCH_EXTERNAL, 3);
282 }
283
284 return 0;
285}
286
287static int gmux_set_discrete_state(struct apple_gmux_data *gmux_data,
288 enum vga_switcheroo_state state)
289{
290 INIT_COMPLETION(gmux_data->powerchange_done);
291
292 if (state == VGA_SWITCHEROO_ON) {
293 gmux_write8(gmux_data, GMUX_PORT_DISCRETE_POWER, 1);
294 gmux_write8(gmux_data, GMUX_PORT_DISCRETE_POWER, 3);
295 pr_debug("Discrete card powered up\n");
296 } else {
297 gmux_write8(gmux_data, GMUX_PORT_DISCRETE_POWER, 1);
298 gmux_write8(gmux_data, GMUX_PORT_DISCRETE_POWER, 0);
299 pr_debug("Discrete card powered down\n");
300 }
301
302 gmux_data->power_state = state;
303
304 if (gmux_data->gpe >= 0 &&
305 !wait_for_completion_interruptible_timeout(&gmux_data->powerchange_done,
306 msecs_to_jiffies(200)))
307 pr_warn("Timeout waiting for gmux switch to complete\n");
308
309 return 0;
310}
311
312static int gmux_set_power_state(enum vga_switcheroo_client_id id,
313 enum vga_switcheroo_state state)
314{
315 if (id == VGA_SWITCHEROO_IGD)
316 return 0;
317
318 return gmux_set_discrete_state(apple_gmux_data, state);
319}
320
321static int gmux_get_client_id(struct pci_dev *pdev)
322{
323 /*
324 * Early Macbook Pros with switchable graphics use nvidia
325 * integrated graphics. Hardcode that the 9400M is integrated.
326 */
327 if (pdev->vendor == PCI_VENDOR_ID_INTEL)
328 return VGA_SWITCHEROO_IGD;
329 else if (pdev->vendor == PCI_VENDOR_ID_NVIDIA &&
330 pdev->device == 0x0863)
331 return VGA_SWITCHEROO_IGD;
332 else
333 return VGA_SWITCHEROO_DIS;
334}
335
336static enum vga_switcheroo_client_id
337gmux_active_client(struct apple_gmux_data *gmux_data)
338{
339 if (gmux_read8(gmux_data, GMUX_PORT_SWITCH_DISPLAY) == 2)
340 return VGA_SWITCHEROO_IGD;
341
342 return VGA_SWITCHEROO_DIS;
343}
344
345static struct vga_switcheroo_handler gmux_handler = {
346 .switchto = gmux_switchto,
347 .power_state = gmux_set_power_state,
348 .get_client_id = gmux_get_client_id,
349};
350
351static inline void gmux_disable_interrupts(struct apple_gmux_data *gmux_data)
352{
353 gmux_write8(gmux_data, GMUX_PORT_INTERRUPT_ENABLE,
354 GMUX_INTERRUPT_DISABLE);
355}
356
357static inline void gmux_enable_interrupts(struct apple_gmux_data *gmux_data)
358{
359 gmux_write8(gmux_data, GMUX_PORT_INTERRUPT_ENABLE,
360 GMUX_INTERRUPT_ENABLE);
361}
362
363static inline u8 gmux_interrupt_get_status(struct apple_gmux_data *gmux_data)
364{
365 return gmux_read8(gmux_data, GMUX_PORT_INTERRUPT_STATUS);
366}
367
368static void gmux_clear_interrupts(struct apple_gmux_data *gmux_data)
369{
370 u8 status;
371
372 /* to clear interrupts write back current status */
373 status = gmux_interrupt_get_status(gmux_data);
374 gmux_write8(gmux_data, GMUX_PORT_INTERRUPT_STATUS, status);
375}
376
377static void gmux_notify_handler(acpi_handle device, u32 value, void *context)
378{
379 u8 status;
380 struct pnp_dev *pnp = (struct pnp_dev *)context;
381 struct apple_gmux_data *gmux_data = pnp_get_drvdata(pnp);
382
383 status = gmux_interrupt_get_status(gmux_data);
384 gmux_disable_interrupts(gmux_data);
385 pr_debug("Notify handler called: status %d\n", status);
386
387 gmux_clear_interrupts(gmux_data);
388 gmux_enable_interrupts(gmux_data);
389
390 if (status & GMUX_INTERRUPT_STATUS_POWER)
391 complete(&gmux_data->powerchange_done);
392}
393
394static int gmux_suspend(struct pnp_dev *pnp, pm_message_t state)
395{
396 struct apple_gmux_data *gmux_data = pnp_get_drvdata(pnp);
397 gmux_data->resume_client_id = gmux_active_client(gmux_data);
398 gmux_disable_interrupts(gmux_data);
399 return 0;
400}
401
402static int gmux_resume(struct pnp_dev *pnp)
403{
404 struct apple_gmux_data *gmux_data = pnp_get_drvdata(pnp);
405 gmux_enable_interrupts(gmux_data);
406 gmux_switchto(gmux_data->resume_client_id);
407 if (gmux_data->power_state == VGA_SWITCHEROO_OFF)
408 gmux_set_discrete_state(gmux_data, gmux_data->power_state);
409 return 0;
410}
411
113static int __devinit gmux_probe(struct pnp_dev *pnp, 412static int __devinit gmux_probe(struct pnp_dev *pnp,
114 const struct pnp_device_id *id) 413 const struct pnp_device_id *id)
115{ 414{
@@ -119,6 +418,11 @@ static int __devinit gmux_probe(struct pnp_dev *pnp,
119 struct backlight_device *bdev; 418 struct backlight_device *bdev;
120 u8 ver_major, ver_minor, ver_release; 419 u8 ver_major, ver_minor, ver_release;
121 int ret = -ENXIO; 420 int ret = -ENXIO;
421 acpi_status status;
422 unsigned long long gpe;
423
424 if (apple_gmux_data)
425 return -EBUSY;
122 426
123 gmux_data = kzalloc(sizeof(*gmux_data), GFP_KERNEL); 427 gmux_data = kzalloc(sizeof(*gmux_data), GFP_KERNEL);
124 if (!gmux_data) 428 if (!gmux_data)
@@ -147,22 +451,29 @@ static int __devinit gmux_probe(struct pnp_dev *pnp,
147 } 451 }
148 452
149 /* 453 /*
150 * On some machines the gmux is in ACPI even thought the machine 454 * Invalid version information may indicate either that the gmux
151 * doesn't really have a gmux. Check for invalid version information 455 * device isn't present or that it's a new one that uses indexed
152 * to detect this. 456 * io
153 */ 457 */
458
154 ver_major = gmux_read8(gmux_data, GMUX_PORT_VERSION_MAJOR); 459 ver_major = gmux_read8(gmux_data, GMUX_PORT_VERSION_MAJOR);
155 ver_minor = gmux_read8(gmux_data, GMUX_PORT_VERSION_MINOR); 460 ver_minor = gmux_read8(gmux_data, GMUX_PORT_VERSION_MINOR);
156 ver_release = gmux_read8(gmux_data, GMUX_PORT_VERSION_RELEASE); 461 ver_release = gmux_read8(gmux_data, GMUX_PORT_VERSION_RELEASE);
157 if (ver_major == 0xff && ver_minor == 0xff && ver_release == 0xff) { 462 if (ver_major == 0xff && ver_minor == 0xff && ver_release == 0xff) {
158 pr_info("gmux device not present\n"); 463 if (gmux_is_indexed(gmux_data)) {
159 ret = -ENODEV; 464 mutex_init(&gmux_data->index_lock);
160 goto err_release; 465 gmux_data->indexed = true;
466 } else {
467 pr_info("gmux device not present\n");
468 ret = -ENODEV;
469 goto err_release;
470 }
471 pr_info("Found indexed gmux\n");
472 } else {
473 pr_info("Found gmux version %d.%d.%d\n", ver_major, ver_minor,
474 ver_release);
161 } 475 }
162 476
163 pr_info("Found gmux version %d.%d.%d\n", ver_major, ver_minor,
164 ver_release);
165
166 memset(&props, 0, sizeof(props)); 477 memset(&props, 0, sizeof(props));
167 props.type = BACKLIGHT_PLATFORM; 478 props.type = BACKLIGHT_PLATFORM;
168 props.max_brightness = gmux_read32(gmux_data, GMUX_PORT_MAX_BRIGHTNESS); 479 props.max_brightness = gmux_read32(gmux_data, GMUX_PORT_MAX_BRIGHTNESS);
@@ -194,13 +505,67 @@ static int __devinit gmux_probe(struct pnp_dev *pnp,
194 * Disable the other backlight choices. 505 * Disable the other backlight choices.
195 */ 506 */
196 acpi_video_dmi_promote_vendor(); 507 acpi_video_dmi_promote_vendor();
197#ifdef CONFIG_ACPI_VIDEO 508#if defined (CONFIG_ACPI_VIDEO) || defined (CONFIG_ACPI_VIDEO_MODULE)
198 acpi_video_unregister(); 509 acpi_video_unregister();
199#endif 510#endif
200 apple_bl_unregister(); 511 apple_bl_unregister();
201 512
513 gmux_data->power_state = VGA_SWITCHEROO_ON;
514
515 gmux_data->dhandle = DEVICE_ACPI_HANDLE(&pnp->dev);
516 if (!gmux_data->dhandle) {
517 pr_err("Cannot find acpi handle for pnp device %s\n",
518 dev_name(&pnp->dev));
519 ret = -ENODEV;
520 goto err_notify;
521 }
522
523 status = acpi_evaluate_integer(gmux_data->dhandle, "GMGP", NULL, &gpe);
524 if (ACPI_SUCCESS(status)) {
525 gmux_data->gpe = (int)gpe;
526
527 status = acpi_install_notify_handler(gmux_data->dhandle,
528 ACPI_DEVICE_NOTIFY,
529 &gmux_notify_handler, pnp);
530 if (ACPI_FAILURE(status)) {
531 pr_err("Install notify handler failed: %s\n",
532 acpi_format_exception(status));
533 ret = -ENODEV;
534 goto err_notify;
535 }
536
537 status = acpi_enable_gpe(NULL, gmux_data->gpe);
538 if (ACPI_FAILURE(status)) {
539 pr_err("Cannot enable gpe: %s\n",
540 acpi_format_exception(status));
541 goto err_enable_gpe;
542 }
543 } else {
544 pr_warn("No GPE found for gmux\n");
545 gmux_data->gpe = -1;
546 }
547
548 if (vga_switcheroo_register_handler(&gmux_handler)) {
549 ret = -ENODEV;
550 goto err_register_handler;
551 }
552
553 init_completion(&gmux_data->powerchange_done);
554 apple_gmux_data = gmux_data;
555 gmux_enable_interrupts(gmux_data);
556
202 return 0; 557 return 0;
203 558
559err_register_handler:
560 if (gmux_data->gpe >= 0)
561 acpi_disable_gpe(NULL, gmux_data->gpe);
562err_enable_gpe:
563 if (gmux_data->gpe >= 0)
564 acpi_remove_notify_handler(gmux_data->dhandle,
565 ACPI_DEVICE_NOTIFY,
566 &gmux_notify_handler);
567err_notify:
568 backlight_device_unregister(bdev);
204err_release: 569err_release:
205 release_region(gmux_data->iostart, gmux_data->iolen); 570 release_region(gmux_data->iostart, gmux_data->iolen);
206err_free: 571err_free:
@@ -212,12 +577,23 @@ static void __devexit gmux_remove(struct pnp_dev *pnp)
212{ 577{
213 struct apple_gmux_data *gmux_data = pnp_get_drvdata(pnp); 578 struct apple_gmux_data *gmux_data = pnp_get_drvdata(pnp);
214 579
580 vga_switcheroo_unregister_handler();
581 gmux_disable_interrupts(gmux_data);
582 if (gmux_data->gpe >= 0) {
583 acpi_disable_gpe(NULL, gmux_data->gpe);
584 acpi_remove_notify_handler(gmux_data->dhandle,
585 ACPI_DEVICE_NOTIFY,
586 &gmux_notify_handler);
587 }
588
215 backlight_device_unregister(gmux_data->bdev); 589 backlight_device_unregister(gmux_data->bdev);
590
216 release_region(gmux_data->iostart, gmux_data->iolen); 591 release_region(gmux_data->iostart, gmux_data->iolen);
592 apple_gmux_data = NULL;
217 kfree(gmux_data); 593 kfree(gmux_data);
218 594
219 acpi_video_dmi_demote_vendor(); 595 acpi_video_dmi_demote_vendor();
220#ifdef CONFIG_ACPI_VIDEO 596#if defined (CONFIG_ACPI_VIDEO) || defined (CONFIG_ACPI_VIDEO_MODULE)
221 acpi_video_register(); 597 acpi_video_register();
222#endif 598#endif
223 apple_bl_register(); 599 apple_bl_register();
@@ -233,6 +609,8 @@ static struct pnp_driver gmux_pnp_driver = {
233 .probe = gmux_probe, 609 .probe = gmux_probe,
234 .remove = __devexit_p(gmux_remove), 610 .remove = __devexit_p(gmux_remove),
235 .id_table = gmux_device_ids, 611 .id_table = gmux_device_ids,
612 .suspend = gmux_suspend,
613 .resume = gmux_resume
236}; 614};
237 615
238static int __init apple_gmux_init(void) 616static int __init apple_gmux_init(void)
diff --git a/drivers/platform/x86/asus-wmi.c b/drivers/platform/x86/asus-wmi.c
index c7a36f6b0580..2eb9fe8e8efd 100644
--- a/drivers/platform/x86/asus-wmi.c
+++ b/drivers/platform/x86/asus-wmi.c
@@ -101,6 +101,7 @@ MODULE_LICENSE("GPL");
101#define ASUS_WMI_DEVID_WIRELESS_LED 0x00010002 101#define ASUS_WMI_DEVID_WIRELESS_LED 0x00010002
102#define ASUS_WMI_DEVID_CWAP 0x00010003 102#define ASUS_WMI_DEVID_CWAP 0x00010003
103#define ASUS_WMI_DEVID_WLAN 0x00010011 103#define ASUS_WMI_DEVID_WLAN 0x00010011
104#define ASUS_WMI_DEVID_WLAN_LED 0x00010012
104#define ASUS_WMI_DEVID_BLUETOOTH 0x00010013 105#define ASUS_WMI_DEVID_BLUETOOTH 0x00010013
105#define ASUS_WMI_DEVID_GPS 0x00010015 106#define ASUS_WMI_DEVID_GPS 0x00010015
106#define ASUS_WMI_DEVID_WIMAX 0x00010017 107#define ASUS_WMI_DEVID_WIMAX 0x00010017
@@ -731,8 +732,21 @@ static int asus_rfkill_set(void *data, bool blocked)
731{ 732{
732 struct asus_rfkill *priv = data; 733 struct asus_rfkill *priv = data;
733 u32 ctrl_param = !blocked; 734 u32 ctrl_param = !blocked;
735 u32 dev_id = priv->dev_id;
734 736
735 return asus_wmi_set_devstate(priv->dev_id, ctrl_param, NULL); 737 /*
738 * If the user bit is set, BIOS can't set and record the wlan status,
739 * it will report the value read from id ASUS_WMI_DEVID_WLAN_LED
740 * while we query the wlan status through WMI(ASUS_WMI_DEVID_WLAN).
741 * So, we have to record wlan status in id ASUS_WMI_DEVID_WLAN_LED
742 * while setting the wlan status through WMI.
743 * This is also the behavior that windows app will do.
744 */
745 if ((dev_id == ASUS_WMI_DEVID_WLAN) &&
746 priv->asus->driver->wlan_ctrl_by_user)
747 dev_id = ASUS_WMI_DEVID_WLAN_LED;
748
749 return asus_wmi_set_devstate(dev_id, ctrl_param, NULL);
736} 750}
737 751
738static void asus_rfkill_query(struct rfkill *rfkill, void *data) 752static void asus_rfkill_query(struct rfkill *rfkill, void *data)
@@ -1653,6 +1667,7 @@ static int asus_wmi_add(struct platform_device *pdev)
1653 struct asus_wmi *asus; 1667 struct asus_wmi *asus;
1654 acpi_status status; 1668 acpi_status status;
1655 int err; 1669 int err;
1670 u32 result;
1656 1671
1657 asus = kzalloc(sizeof(struct asus_wmi), GFP_KERNEL); 1672 asus = kzalloc(sizeof(struct asus_wmi), GFP_KERNEL);
1658 if (!asus) 1673 if (!asus)
@@ -1711,6 +1726,10 @@ static int asus_wmi_add(struct platform_device *pdev)
1711 if (err) 1726 if (err)
1712 goto fail_debugfs; 1727 goto fail_debugfs;
1713 1728
1729 asus_wmi_get_devstate(asus, ASUS_WMI_DEVID_WLAN, &result);
1730 if (result & (ASUS_WMI_DSTS_PRESENCE_BIT | ASUS_WMI_DSTS_USER_BIT))
1731 asus->driver->wlan_ctrl_by_user = 1;
1732
1714 return 0; 1733 return 0;
1715 1734
1716fail_debugfs: 1735fail_debugfs:
diff --git a/drivers/platform/x86/asus-wmi.h b/drivers/platform/x86/asus-wmi.h
index 9c1da8b81bea..4c9bd38bb0a2 100644
--- a/drivers/platform/x86/asus-wmi.h
+++ b/drivers/platform/x86/asus-wmi.h
@@ -46,6 +46,7 @@ struct quirk_entry {
46struct asus_wmi_driver { 46struct asus_wmi_driver {
47 int brightness; 47 int brightness;
48 int panel_power; 48 int panel_power;
49 int wlan_ctrl_by_user;
49 50
50 const char *name; 51 const char *name;
51 struct module *owner; 52 struct module *owner;
diff --git a/drivers/platform/x86/classmate-laptop.c b/drivers/platform/x86/classmate-laptop.c
index 2ca7dd1ab3e4..c87ff16873f9 100644
--- a/drivers/platform/x86/classmate-laptop.c
+++ b/drivers/platform/x86/classmate-laptop.c
@@ -350,6 +350,7 @@ static void cmpc_accel_idev_init_v4(struct input_dev *inputdev)
350 inputdev->close = cmpc_accel_close_v4; 350 inputdev->close = cmpc_accel_close_v4;
351} 351}
352 352
353#ifdef CONFIG_PM_SLEEP
353static int cmpc_accel_suspend_v4(struct device *dev) 354static int cmpc_accel_suspend_v4(struct device *dev)
354{ 355{
355 struct input_dev *inputdev; 356 struct input_dev *inputdev;
@@ -384,6 +385,7 @@ static int cmpc_accel_resume_v4(struct device *dev)
384 385
385 return 0; 386 return 0;
386} 387}
388#endif
387 389
388static int cmpc_accel_add_v4(struct acpi_device *acpi) 390static int cmpc_accel_add_v4(struct acpi_device *acpi)
389{ 391{
@@ -723,8 +725,10 @@ static void cmpc_tablet_handler(struct acpi_device *dev, u32 event)
723 struct input_dev *inputdev = dev_get_drvdata(&dev->dev); 725 struct input_dev *inputdev = dev_get_drvdata(&dev->dev);
724 726
725 if (event == 0x81) { 727 if (event == 0x81) {
726 if (ACPI_SUCCESS(cmpc_get_tablet(dev->handle, &val))) 728 if (ACPI_SUCCESS(cmpc_get_tablet(dev->handle, &val))) {
727 input_report_switch(inputdev, SW_TABLET_MODE, !val); 729 input_report_switch(inputdev, SW_TABLET_MODE, !val);
730 input_sync(inputdev);
731 }
728 } 732 }
729} 733}
730 734
@@ -737,8 +741,10 @@ static void cmpc_tablet_idev_init(struct input_dev *inputdev)
737 set_bit(SW_TABLET_MODE, inputdev->swbit); 741 set_bit(SW_TABLET_MODE, inputdev->swbit);
738 742
739 acpi = to_acpi_device(inputdev->dev.parent); 743 acpi = to_acpi_device(inputdev->dev.parent);
740 if (ACPI_SUCCESS(cmpc_get_tablet(acpi->handle, &val))) 744 if (ACPI_SUCCESS(cmpc_get_tablet(acpi->handle, &val))) {
741 input_report_switch(inputdev, SW_TABLET_MODE, !val); 745 input_report_switch(inputdev, SW_TABLET_MODE, !val);
746 input_sync(inputdev);
747 }
742} 748}
743 749
744static int cmpc_tablet_add(struct acpi_device *acpi) 750static int cmpc_tablet_add(struct acpi_device *acpi)
@@ -752,15 +758,19 @@ static int cmpc_tablet_remove(struct acpi_device *acpi, int type)
752 return cmpc_remove_acpi_notify_device(acpi); 758 return cmpc_remove_acpi_notify_device(acpi);
753} 759}
754 760
761#ifdef CONFIG_PM_SLEEP
755static int cmpc_tablet_resume(struct device *dev) 762static int cmpc_tablet_resume(struct device *dev)
756{ 763{
757 struct input_dev *inputdev = dev_get_drvdata(dev); 764 struct input_dev *inputdev = dev_get_drvdata(dev);
758 765
759 unsigned long long val = 0; 766 unsigned long long val = 0;
760 if (ACPI_SUCCESS(cmpc_get_tablet(to_acpi_device(dev)->handle, &val))) 767 if (ACPI_SUCCESS(cmpc_get_tablet(to_acpi_device(dev)->handle, &val))) {
761 input_report_switch(inputdev, SW_TABLET_MODE, !val); 768 input_report_switch(inputdev, SW_TABLET_MODE, !val);
769 input_sync(inputdev);
770 }
762 return 0; 771 return 0;
763} 772}
773#endif
764 774
765static SIMPLE_DEV_PM_OPS(cmpc_tablet_pm, NULL, cmpc_tablet_resume); 775static SIMPLE_DEV_PM_OPS(cmpc_tablet_pm, NULL, cmpc_tablet_resume);
766 776
diff --git a/drivers/platform/x86/dell-laptop.c b/drivers/platform/x86/dell-laptop.c
index 4e96e8c0b60f..927c33af67ec 100644
--- a/drivers/platform/x86/dell-laptop.c
+++ b/drivers/platform/x86/dell-laptop.c
@@ -211,7 +211,7 @@ static struct dmi_system_id __devinitdata dell_quirks[] = {
211 .ident = "Dell Inspiron 5420", 211 .ident = "Dell Inspiron 5420",
212 .matches = { 212 .matches = {
213 DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."), 213 DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
214 DMI_MATCH(DMI_PRODUCT_NAME, "Isnpiron 5420"), 214 DMI_MATCH(DMI_PRODUCT_NAME, "Inspiron 5420"),
215 }, 215 },
216 .driver_data = &quirk_dell_vostro_v130, 216 .driver_data = &quirk_dell_vostro_v130,
217 }, 217 },
@@ -220,7 +220,7 @@ static struct dmi_system_id __devinitdata dell_quirks[] = {
220 .ident = "Dell Inspiron 5520", 220 .ident = "Dell Inspiron 5520",
221 .matches = { 221 .matches = {
222 DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."), 222 DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
223 DMI_MATCH(DMI_PRODUCT_NAME, "Isnpiron 5520"), 223 DMI_MATCH(DMI_PRODUCT_NAME, "Inspiron 5520"),
224 }, 224 },
225 .driver_data = &quirk_dell_vostro_v130, 225 .driver_data = &quirk_dell_vostro_v130,
226 }, 226 },
@@ -229,7 +229,7 @@ static struct dmi_system_id __devinitdata dell_quirks[] = {
229 .ident = "Dell Inspiron 5720", 229 .ident = "Dell Inspiron 5720",
230 .matches = { 230 .matches = {
231 DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."), 231 DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
232 DMI_MATCH(DMI_PRODUCT_NAME, "Isnpiron 5720"), 232 DMI_MATCH(DMI_PRODUCT_NAME, "Inspiron 5720"),
233 }, 233 },
234 .driver_data = &quirk_dell_vostro_v130, 234 .driver_data = &quirk_dell_vostro_v130,
235 }, 235 },
@@ -238,7 +238,7 @@ static struct dmi_system_id __devinitdata dell_quirks[] = {
238 .ident = "Dell Inspiron 7420", 238 .ident = "Dell Inspiron 7420",
239 .matches = { 239 .matches = {
240 DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."), 240 DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
241 DMI_MATCH(DMI_PRODUCT_NAME, "Isnpiron 7420"), 241 DMI_MATCH(DMI_PRODUCT_NAME, "Inspiron 7420"),
242 }, 242 },
243 .driver_data = &quirk_dell_vostro_v130, 243 .driver_data = &quirk_dell_vostro_v130,
244 }, 244 },
@@ -247,7 +247,7 @@ static struct dmi_system_id __devinitdata dell_quirks[] = {
247 .ident = "Dell Inspiron 7520", 247 .ident = "Dell Inspiron 7520",
248 .matches = { 248 .matches = {
249 DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."), 249 DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
250 DMI_MATCH(DMI_PRODUCT_NAME, "Isnpiron 7520"), 250 DMI_MATCH(DMI_PRODUCT_NAME, "Inspiron 7520"),
251 }, 251 },
252 .driver_data = &quirk_dell_vostro_v130, 252 .driver_data = &quirk_dell_vostro_v130,
253 }, 253 },
@@ -256,7 +256,7 @@ static struct dmi_system_id __devinitdata dell_quirks[] = {
256 .ident = "Dell Inspiron 7720", 256 .ident = "Dell Inspiron 7720",
257 .matches = { 257 .matches = {
258 DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."), 258 DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
259 DMI_MATCH(DMI_PRODUCT_NAME, "Isnpiron 7720"), 259 DMI_MATCH(DMI_PRODUCT_NAME, "Inspiron 7720"),
260 }, 260 },
261 .driver_data = &quirk_dell_vostro_v130, 261 .driver_data = &quirk_dell_vostro_v130,
262 }, 262 },
diff --git a/drivers/platform/x86/fujitsu-tablet.c b/drivers/platform/x86/fujitsu-tablet.c
index d2e41735a47b..7acae3f85f3b 100644
--- a/drivers/platform/x86/fujitsu-tablet.c
+++ b/drivers/platform/x86/fujitsu-tablet.c
@@ -440,11 +440,13 @@ static int __devexit acpi_fujitsu_remove(struct acpi_device *adev, int type)
440 return 0; 440 return 0;
441} 441}
442 442
443#ifdef CONFIG_PM_SLEEP
443static int acpi_fujitsu_resume(struct device *dev) 444static int acpi_fujitsu_resume(struct device *dev)
444{ 445{
445 fujitsu_reset(); 446 fujitsu_reset();
446 return 0; 447 return 0;
447} 448}
449#endif
448 450
449static SIMPLE_DEV_PM_OPS(acpi_fujitsu_pm, NULL, acpi_fujitsu_resume); 451static SIMPLE_DEV_PM_OPS(acpi_fujitsu_pm, NULL, acpi_fujitsu_resume);
450 452
diff --git a/drivers/platform/x86/hdaps.c b/drivers/platform/x86/hdaps.c
index d9ab6f64dcec..777c7e3dda51 100644
--- a/drivers/platform/x86/hdaps.c
+++ b/drivers/platform/x86/hdaps.c
@@ -305,10 +305,12 @@ static int hdaps_probe(struct platform_device *dev)
305 return 0; 305 return 0;
306} 306}
307 307
308#ifdef CONFIG_PM_SLEEP
308static int hdaps_resume(struct device *dev) 309static int hdaps_resume(struct device *dev)
309{ 310{
310 return hdaps_device_init(); 311 return hdaps_device_init();
311} 312}
313#endif
312 314
313static SIMPLE_DEV_PM_OPS(hdaps_pm, NULL, hdaps_resume); 315static SIMPLE_DEV_PM_OPS(hdaps_pm, NULL, hdaps_resume);
314 316
diff --git a/drivers/platform/x86/hp_accel.c b/drivers/platform/x86/hp_accel.c
index f4d91154ad67..6b9af989632b 100644
--- a/drivers/platform/x86/hp_accel.c
+++ b/drivers/platform/x86/hp_accel.c
@@ -352,7 +352,7 @@ static int lis3lv02d_remove(struct acpi_device *device, int type)
352} 352}
353 353
354 354
355#ifdef CONFIG_PM 355#ifdef CONFIG_PM_SLEEP
356static int lis3lv02d_suspend(struct device *dev) 356static int lis3lv02d_suspend(struct device *dev)
357{ 357{
358 /* make sure the device is off when we suspend */ 358 /* make sure the device is off when we suspend */
diff --git a/drivers/platform/x86/ideapad-laptop.c b/drivers/platform/x86/ideapad-laptop.c
index 17f6dfd8dbfb..dae7abe1d711 100644
--- a/drivers/platform/x86/ideapad-laptop.c
+++ b/drivers/platform/x86/ideapad-laptop.c
@@ -36,6 +36,7 @@
36#include <linux/fb.h> 36#include <linux/fb.h>
37#include <linux/debugfs.h> 37#include <linux/debugfs.h>
38#include <linux/seq_file.h> 38#include <linux/seq_file.h>
39#include <linux/i8042.h>
39 40
40#define IDEAPAD_RFKILL_DEV_NUM (3) 41#define IDEAPAD_RFKILL_DEV_NUM (3)
41 42
@@ -63,8 +64,11 @@ enum {
63 VPCCMD_R_3G, 64 VPCCMD_R_3G,
64 VPCCMD_W_3G, 65 VPCCMD_W_3G,
65 VPCCMD_R_ODD, /* 0x21 */ 66 VPCCMD_R_ODD, /* 0x21 */
66 VPCCMD_R_RF = 0x23, 67 VPCCMD_W_FAN,
68 VPCCMD_R_RF,
67 VPCCMD_W_RF, 69 VPCCMD_W_RF,
70 VPCCMD_R_FAN = 0x2B,
71 VPCCMD_R_SPECIAL_BUTTONS = 0x31,
68 VPCCMD_W_BL_POWER = 0x33, 72 VPCCMD_W_BL_POWER = 0x33,
69}; 73};
70 74
@@ -356,14 +360,46 @@ static ssize_t store_ideapad_cam(struct device *dev,
356 return -EINVAL; 360 return -EINVAL;
357 ret = write_ec_cmd(ideapad_handle, VPCCMD_W_CAMERA, state); 361 ret = write_ec_cmd(ideapad_handle, VPCCMD_W_CAMERA, state);
358 if (ret < 0) 362 if (ret < 0)
359 return ret; 363 return -EIO;
360 return count; 364 return count;
361} 365}
362 366
363static DEVICE_ATTR(camera_power, 0644, show_ideapad_cam, store_ideapad_cam); 367static DEVICE_ATTR(camera_power, 0644, show_ideapad_cam, store_ideapad_cam);
364 368
369static ssize_t show_ideapad_fan(struct device *dev,
370 struct device_attribute *attr,
371 char *buf)
372{
373 unsigned long result;
374
375 if (read_ec_data(ideapad_handle, VPCCMD_R_FAN, &result))
376 return sprintf(buf, "-1\n");
377 return sprintf(buf, "%lu\n", result);
378}
379
380static ssize_t store_ideapad_fan(struct device *dev,
381 struct device_attribute *attr,
382 const char *buf, size_t count)
383{
384 int ret, state;
385
386 if (!count)
387 return 0;
388 if (sscanf(buf, "%i", &state) != 1)
389 return -EINVAL;
390 if (state < 0 || state > 4 || state == 3)
391 return -EINVAL;
392 ret = write_ec_cmd(ideapad_handle, VPCCMD_W_FAN, state);
393 if (ret < 0)
394 return -EIO;
395 return count;
396}
397
398static DEVICE_ATTR(fan_mode, 0644, show_ideapad_fan, store_ideapad_fan);
399
365static struct attribute *ideapad_attributes[] = { 400static struct attribute *ideapad_attributes[] = {
366 &dev_attr_camera_power.attr, 401 &dev_attr_camera_power.attr,
402 &dev_attr_fan_mode.attr,
367 NULL 403 NULL
368}; 404};
369 405
@@ -377,7 +413,10 @@ static umode_t ideapad_is_visible(struct kobject *kobj,
377 413
378 if (attr == &dev_attr_camera_power.attr) 414 if (attr == &dev_attr_camera_power.attr)
379 supported = test_bit(CFG_CAMERA_BIT, &(priv->cfg)); 415 supported = test_bit(CFG_CAMERA_BIT, &(priv->cfg));
380 else 416 else if (attr == &dev_attr_fan_mode.attr) {
417 unsigned long value;
418 supported = !read_ec_data(ideapad_handle, VPCCMD_R_FAN, &value);
419 } else
381 supported = true; 420 supported = true;
382 421
383 return supported ? attr->mode : 0; 422 return supported ? attr->mode : 0;
@@ -518,9 +557,15 @@ static void ideapad_platform_exit(struct ideapad_private *priv)
518 */ 557 */
519static const struct key_entry ideapad_keymap[] = { 558static const struct key_entry ideapad_keymap[] = {
520 { KE_KEY, 6, { KEY_SWITCHVIDEOMODE } }, 559 { KE_KEY, 6, { KEY_SWITCHVIDEOMODE } },
560 { KE_KEY, 7, { KEY_CAMERA } },
561 { KE_KEY, 11, { KEY_F16 } },
521 { KE_KEY, 13, { KEY_WLAN } }, 562 { KE_KEY, 13, { KEY_WLAN } },
522 { KE_KEY, 16, { KEY_PROG1 } }, 563 { KE_KEY, 16, { KEY_PROG1 } },
523 { KE_KEY, 17, { KEY_PROG2 } }, 564 { KE_KEY, 17, { KEY_PROG2 } },
565 { KE_KEY, 64, { KEY_PROG3 } },
566 { KE_KEY, 65, { KEY_PROG4 } },
567 { KE_KEY, 66, { KEY_TOUCHPAD_OFF } },
568 { KE_KEY, 67, { KEY_TOUCHPAD_ON } },
524 { KE_END, 0 }, 569 { KE_END, 0 },
525}; 570};
526 571
@@ -587,6 +632,28 @@ static void ideapad_input_novokey(struct ideapad_private *priv)
587 ideapad_input_report(priv, 16); 632 ideapad_input_report(priv, 16);
588} 633}
589 634
635static void ideapad_check_special_buttons(struct ideapad_private *priv)
636{
637 unsigned long bit, value;
638
639 read_ec_data(ideapad_handle, VPCCMD_R_SPECIAL_BUTTONS, &value);
640
641 for (bit = 0; bit < 16; bit++) {
642 if (test_bit(bit, &value)) {
643 switch (bit) {
644 case 6:
645 /* Thermal Management button */
646 ideapad_input_report(priv, 65);
647 break;
648 case 1:
649 /* OneKey Theater button */
650 ideapad_input_report(priv, 64);
651 break;
652 }
653 }
654 }
655}
656
590/* 657/*
591 * backlight 658 * backlight
592 */ 659 */
@@ -691,6 +758,24 @@ static const struct acpi_device_id ideapad_device_ids[] = {
691}; 758};
692MODULE_DEVICE_TABLE(acpi, ideapad_device_ids); 759MODULE_DEVICE_TABLE(acpi, ideapad_device_ids);
693 760
761static void ideapad_sync_touchpad_state(struct acpi_device *adevice)
762{
763 struct ideapad_private *priv = dev_get_drvdata(&adevice->dev);
764 unsigned long value;
765
766 /* Without reading from EC touchpad LED doesn't switch state */
767 if (!read_ec_data(adevice->handle, VPCCMD_R_TOUCHPAD, &value)) {
768 /* Some IdeaPads don't really turn off touchpad - they only
769 * switch the LED state. We (de)activate KBC AUX port to turn
770 * touchpad off and on. We send KEY_TOUCHPAD_OFF and
771 * KEY_TOUCHPAD_ON to not to get out of sync with LED */
772 unsigned char param;
773 i8042_command(&param, value ? I8042_CMD_AUX_ENABLE :
774 I8042_CMD_AUX_DISABLE);
775 ideapad_input_report(priv, value ? 67 : 66);
776 }
777}
778
694static int __devinit ideapad_acpi_add(struct acpi_device *adevice) 779static int __devinit ideapad_acpi_add(struct acpi_device *adevice)
695{ 780{
696 int ret, i; 781 int ret, i;
@@ -727,6 +812,7 @@ static int __devinit ideapad_acpi_add(struct acpi_device *adevice)
727 priv->rfk[i] = NULL; 812 priv->rfk[i] = NULL;
728 } 813 }
729 ideapad_sync_rfk_state(priv); 814 ideapad_sync_rfk_state(priv);
815 ideapad_sync_touchpad_state(adevice);
730 816
731 if (!acpi_video_backlight_support()) { 817 if (!acpi_video_backlight_support()) {
732 ret = ideapad_backlight_init(priv); 818 ret = ideapad_backlight_init(priv);
@@ -785,9 +871,14 @@ static void ideapad_acpi_notify(struct acpi_device *adevice, u32 event)
785 ideapad_sync_rfk_state(priv); 871 ideapad_sync_rfk_state(priv);
786 break; 872 break;
787 case 13: 873 case 13:
874 case 11:
875 case 7:
788 case 6: 876 case 6:
789 ideapad_input_report(priv, vpc_bit); 877 ideapad_input_report(priv, vpc_bit);
790 break; 878 break;
879 case 5:
880 ideapad_sync_touchpad_state(adevice);
881 break;
791 case 4: 882 case 4:
792 ideapad_backlight_notify_brightness(priv); 883 ideapad_backlight_notify_brightness(priv);
793 break; 884 break;
@@ -797,6 +888,9 @@ static void ideapad_acpi_notify(struct acpi_device *adevice, u32 event)
797 case 2: 888 case 2:
798 ideapad_backlight_notify_power(priv); 889 ideapad_backlight_notify_power(priv);
799 break; 890 break;
891 case 0:
892 ideapad_check_special_buttons(priv);
893 break;
800 default: 894 default:
801 pr_info("Unknown event: %lu\n", vpc_bit); 895 pr_info("Unknown event: %lu\n", vpc_bit);
802 } 896 }
@@ -804,6 +898,15 @@ static void ideapad_acpi_notify(struct acpi_device *adevice, u32 event)
804 } 898 }
805} 899}
806 900
901static int ideapad_acpi_resume(struct device *device)
902{
903 ideapad_sync_rfk_state(ideapad_priv);
904 ideapad_sync_touchpad_state(to_acpi_device(device));
905 return 0;
906}
907
908static SIMPLE_DEV_PM_OPS(ideapad_pm, NULL, ideapad_acpi_resume);
909
807static struct acpi_driver ideapad_acpi_driver = { 910static struct acpi_driver ideapad_acpi_driver = {
808 .name = "ideapad_acpi", 911 .name = "ideapad_acpi",
809 .class = "IdeaPad", 912 .class = "IdeaPad",
@@ -811,6 +914,7 @@ static struct acpi_driver ideapad_acpi_driver = {
811 .ops.add = ideapad_acpi_add, 914 .ops.add = ideapad_acpi_add,
812 .ops.remove = ideapad_acpi_remove, 915 .ops.remove = ideapad_acpi_remove,
813 .ops.notify = ideapad_acpi_notify, 916 .ops.notify = ideapad_acpi_notify,
917 .drv.pm = &ideapad_pm,
814 .owner = THIS_MODULE, 918 .owner = THIS_MODULE,
815}; 919};
816 920
diff --git a/drivers/platform/x86/msi-laptop.c b/drivers/platform/x86/msi-laptop.c
index f64441844317..2111dbb7e1e3 100644
--- a/drivers/platform/x86/msi-laptop.c
+++ b/drivers/platform/x86/msi-laptop.c
@@ -85,7 +85,9 @@
85#define MSI_STANDARD_EC_TOUCHPAD_ADDRESS 0xe4 85#define MSI_STANDARD_EC_TOUCHPAD_ADDRESS 0xe4
86#define MSI_STANDARD_EC_TOUCHPAD_MASK (1 << 4) 86#define MSI_STANDARD_EC_TOUCHPAD_MASK (1 << 4)
87 87
88#ifdef CONFIG_PM_SLEEP
88static int msi_laptop_resume(struct device *device); 89static int msi_laptop_resume(struct device *device);
90#endif
89static SIMPLE_DEV_PM_OPS(msi_laptop_pm, NULL, msi_laptop_resume); 91static SIMPLE_DEV_PM_OPS(msi_laptop_pm, NULL, msi_laptop_resume);
90 92
91#define MSI_STANDARD_EC_DEVICES_EXISTS_ADDRESS 0x2f 93#define MSI_STANDARD_EC_DEVICES_EXISTS_ADDRESS 0x2f
@@ -753,6 +755,7 @@ err_bluetooth:
753 return retval; 755 return retval;
754} 756}
755 757
758#ifdef CONFIG_PM_SLEEP
756static int msi_laptop_resume(struct device *device) 759static int msi_laptop_resume(struct device *device)
757{ 760{
758 u8 data; 761 u8 data;
@@ -773,6 +776,7 @@ static int msi_laptop_resume(struct device *device)
773 776
774 return 0; 777 return 0;
775} 778}
779#endif
776 780
777static int __init msi_laptop_input_setup(void) 781static int __init msi_laptop_input_setup(void)
778{ 782{
diff --git a/drivers/platform/x86/panasonic-laptop.c b/drivers/platform/x86/panasonic-laptop.c
index 24480074bcf0..8e8caa767d6a 100644
--- a/drivers/platform/x86/panasonic-laptop.c
+++ b/drivers/platform/x86/panasonic-laptop.c
@@ -188,7 +188,9 @@ static const struct acpi_device_id pcc_device_ids[] = {
188}; 188};
189MODULE_DEVICE_TABLE(acpi, pcc_device_ids); 189MODULE_DEVICE_TABLE(acpi, pcc_device_ids);
190 190
191#ifdef CONFIG_PM_SLEEP
191static int acpi_pcc_hotkey_resume(struct device *dev); 192static int acpi_pcc_hotkey_resume(struct device *dev);
193#endif
192static SIMPLE_DEV_PM_OPS(acpi_pcc_hotkey_pm, NULL, acpi_pcc_hotkey_resume); 194static SIMPLE_DEV_PM_OPS(acpi_pcc_hotkey_pm, NULL, acpi_pcc_hotkey_resume);
193 195
194static struct acpi_driver acpi_pcc_driver = { 196static struct acpi_driver acpi_pcc_driver = {
@@ -540,6 +542,7 @@ static void acpi_pcc_destroy_input(struct pcc_acpi *pcc)
540 542
541/* kernel module interface */ 543/* kernel module interface */
542 544
545#ifdef CONFIG_PM_SLEEP
543static int acpi_pcc_hotkey_resume(struct device *dev) 546static int acpi_pcc_hotkey_resume(struct device *dev)
544{ 547{
545 struct pcc_acpi *pcc; 548 struct pcc_acpi *pcc;
@@ -556,6 +559,7 @@ static int acpi_pcc_hotkey_resume(struct device *dev)
556 559
557 return acpi_pcc_write_sset(pcc, SINF_STICKY_KEY, pcc->sticky_mode); 560 return acpi_pcc_write_sset(pcc, SINF_STICKY_KEY, pcc->sticky_mode);
558} 561}
562#endif
559 563
560static int acpi_pcc_hotkey_add(struct acpi_device *device) 564static int acpi_pcc_hotkey_add(struct acpi_device *device)
561{ 565{
diff --git a/drivers/platform/x86/sony-laptop.c b/drivers/platform/x86/sony-laptop.c
index 9363969ad07a..daaddec68def 100644
--- a/drivers/platform/x86/sony-laptop.c
+++ b/drivers/platform/x86/sony-laptop.c
@@ -140,7 +140,10 @@ MODULE_PARM_DESC(kbd_backlight_timeout,
140 "1 for 30 seconds, 2 for 60 seconds and 3 to disable timeout " 140 "1 for 30 seconds, 2 for 60 seconds and 3 to disable timeout "
141 "(default: 0)"); 141 "(default: 0)");
142 142
143#ifdef CONFIG_PM_SLEEP
143static void sony_nc_kbd_backlight_resume(void); 144static void sony_nc_kbd_backlight_resume(void);
145static void sony_nc_thermal_resume(void);
146#endif
144static int sony_nc_kbd_backlight_setup(struct platform_device *pd, 147static int sony_nc_kbd_backlight_setup(struct platform_device *pd,
145 unsigned int handle); 148 unsigned int handle);
146static void sony_nc_kbd_backlight_cleanup(struct platform_device *pd); 149static void sony_nc_kbd_backlight_cleanup(struct platform_device *pd);
@@ -151,7 +154,6 @@ static void sony_nc_battery_care_cleanup(struct platform_device *pd);
151 154
152static int sony_nc_thermal_setup(struct platform_device *pd); 155static int sony_nc_thermal_setup(struct platform_device *pd);
153static void sony_nc_thermal_cleanup(struct platform_device *pd); 156static void sony_nc_thermal_cleanup(struct platform_device *pd);
154static void sony_nc_thermal_resume(void);
155 157
156static int sony_nc_lid_resume_setup(struct platform_device *pd); 158static int sony_nc_lid_resume_setup(struct platform_device *pd);
157static void sony_nc_lid_resume_cleanup(struct platform_device *pd); 159static void sony_nc_lid_resume_cleanup(struct platform_device *pd);
@@ -1431,6 +1433,7 @@ static void sony_nc_function_cleanup(struct platform_device *pd)
1431 sony_nc_handles_cleanup(pd); 1433 sony_nc_handles_cleanup(pd);
1432} 1434}
1433 1435
1436#ifdef CONFIG_PM_SLEEP
1434static void sony_nc_function_resume(void) 1437static void sony_nc_function_resume(void)
1435{ 1438{
1436 unsigned int i, result, bitmask, arg; 1439 unsigned int i, result, bitmask, arg;
@@ -1508,6 +1511,7 @@ static int sony_nc_resume(struct device *dev)
1508 1511
1509 return 0; 1512 return 0;
1510} 1513}
1514#endif
1511 1515
1512static SIMPLE_DEV_PM_OPS(sony_nc_pm, NULL, sony_nc_resume); 1516static SIMPLE_DEV_PM_OPS(sony_nc_pm, NULL, sony_nc_resume);
1513 1517
@@ -1872,6 +1876,7 @@ static void sony_nc_kbd_backlight_cleanup(struct platform_device *pd)
1872 } 1876 }
1873} 1877}
1874 1878
1879#ifdef CONFIG_PM_SLEEP
1875static void sony_nc_kbd_backlight_resume(void) 1880static void sony_nc_kbd_backlight_resume(void)
1876{ 1881{
1877 int ignore = 0; 1882 int ignore = 0;
@@ -1888,6 +1893,7 @@ static void sony_nc_kbd_backlight_resume(void)
1888 (kbdbl_ctl->base + 0x200) | 1893 (kbdbl_ctl->base + 0x200) |
1889 (kbdbl_ctl->timeout << 0x10), &ignore); 1894 (kbdbl_ctl->timeout << 0x10), &ignore);
1890} 1895}
1896#endif
1891 1897
1892struct battery_care_control { 1898struct battery_care_control {
1893 struct device_attribute attrs[2]; 1899 struct device_attribute attrs[2];
@@ -2210,6 +2216,7 @@ static void sony_nc_thermal_cleanup(struct platform_device *pd)
2210 } 2216 }
2211} 2217}
2212 2218
2219#ifdef CONFIG_PM_SLEEP
2213static void sony_nc_thermal_resume(void) 2220static void sony_nc_thermal_resume(void)
2214{ 2221{
2215 unsigned int status = sony_nc_thermal_mode_get(); 2222 unsigned int status = sony_nc_thermal_mode_get();
@@ -2217,6 +2224,7 @@ static void sony_nc_thermal_resume(void)
2217 if (status != th_handle->mode) 2224 if (status != th_handle->mode)
2218 sony_nc_thermal_mode_set(th_handle->mode); 2225 sony_nc_thermal_mode_set(th_handle->mode);
2219} 2226}
2227#endif
2220 2228
2221/* resume on LID open */ 2229/* resume on LID open */
2222struct snc_lid_resume_control { 2230struct snc_lid_resume_control {
@@ -4287,6 +4295,7 @@ err_free_resources:
4287 return result; 4295 return result;
4288} 4296}
4289 4297
4298#ifdef CONFIG_PM_SLEEP
4290static int sony_pic_suspend(struct device *dev) 4299static int sony_pic_suspend(struct device *dev)
4291{ 4300{
4292 if (sony_pic_disable(to_acpi_device(dev))) 4301 if (sony_pic_disable(to_acpi_device(dev)))
@@ -4300,6 +4309,7 @@ static int sony_pic_resume(struct device *dev)
4300 spic_dev.cur_ioport, spic_dev.cur_irq); 4309 spic_dev.cur_ioport, spic_dev.cur_irq);
4301 return 0; 4310 return 0;
4302} 4311}
4312#endif
4303 4313
4304static SIMPLE_DEV_PM_OPS(sony_pic_pm, sony_pic_suspend, sony_pic_resume); 4314static SIMPLE_DEV_PM_OPS(sony_pic_pm, sony_pic_suspend, sony_pic_resume);
4305 4315
diff --git a/drivers/platform/x86/thinkpad_acpi.c b/drivers/platform/x86/thinkpad_acpi.c
index e7f73287636c..80e377949314 100644
--- a/drivers/platform/x86/thinkpad_acpi.c
+++ b/drivers/platform/x86/thinkpad_acpi.c
@@ -922,6 +922,7 @@ static struct input_dev *tpacpi_inputdev;
922static struct mutex tpacpi_inputdev_send_mutex; 922static struct mutex tpacpi_inputdev_send_mutex;
923static LIST_HEAD(tpacpi_all_drivers); 923static LIST_HEAD(tpacpi_all_drivers);
924 924
925#ifdef CONFIG_PM_SLEEP
925static int tpacpi_suspend_handler(struct device *dev) 926static int tpacpi_suspend_handler(struct device *dev)
926{ 927{
927 struct ibm_struct *ibm, *itmp; 928 struct ibm_struct *ibm, *itmp;
@@ -949,6 +950,7 @@ static int tpacpi_resume_handler(struct device *dev)
949 950
950 return 0; 951 return 0;
951} 952}
953#endif
952 954
953static SIMPLE_DEV_PM_OPS(tpacpi_pm, 955static SIMPLE_DEV_PM_OPS(tpacpi_pm,
954 tpacpi_suspend_handler, tpacpi_resume_handler); 956 tpacpi_suspend_handler, tpacpi_resume_handler);
@@ -8662,6 +8664,13 @@ static int __must_check __init get_thinkpad_model_data(
8662 tp->model_str = kstrdup(s, GFP_KERNEL); 8664 tp->model_str = kstrdup(s, GFP_KERNEL);
8663 if (!tp->model_str) 8665 if (!tp->model_str)
8664 return -ENOMEM; 8666 return -ENOMEM;
8667 } else {
8668 s = dmi_get_system_info(DMI_BIOS_VENDOR);
8669 if (s && !(strnicmp(s, "Lenovo", 6))) {
8670 tp->model_str = kstrdup(s, GFP_KERNEL);
8671 if (!tp->model_str)
8672 return -ENOMEM;
8673 }
8665 } 8674 }
8666 8675
8667 s = dmi_get_system_info(DMI_PRODUCT_NAME); 8676 s = dmi_get_system_info(DMI_PRODUCT_NAME);
diff --git a/drivers/platform/x86/toshiba_acpi.c b/drivers/platform/x86/toshiba_acpi.c
index c13ba5bac93f..5f1256d5e933 100644
--- a/drivers/platform/x86/toshiba_acpi.c
+++ b/drivers/platform/x86/toshiba_acpi.c
@@ -1296,6 +1296,7 @@ static void toshiba_acpi_notify(struct acpi_device *acpi_dev, u32 event)
1296 } 1296 }
1297} 1297}
1298 1298
1299#ifdef CONFIG_PM_SLEEP
1299static int toshiba_acpi_suspend(struct device *device) 1300static int toshiba_acpi_suspend(struct device *device)
1300{ 1301{
1301 struct toshiba_acpi_dev *dev = acpi_driver_data(to_acpi_device(device)); 1302 struct toshiba_acpi_dev *dev = acpi_driver_data(to_acpi_device(device));
@@ -1317,6 +1318,7 @@ static int toshiba_acpi_resume(struct device *device)
1317 1318
1318 return 0; 1319 return 0;
1319} 1320}
1321#endif
1320 1322
1321static SIMPLE_DEV_PM_OPS(toshiba_acpi_pm, 1323static SIMPLE_DEV_PM_OPS(toshiba_acpi_pm,
1322 toshiba_acpi_suspend, toshiba_acpi_resume); 1324 toshiba_acpi_suspend, toshiba_acpi_resume);
diff --git a/drivers/platform/x86/toshiba_bluetooth.c b/drivers/platform/x86/toshiba_bluetooth.c
index 715a43cb5e3c..5e5d6317d690 100644
--- a/drivers/platform/x86/toshiba_bluetooth.c
+++ b/drivers/platform/x86/toshiba_bluetooth.c
@@ -41,7 +41,9 @@ static const struct acpi_device_id bt_device_ids[] = {
41}; 41};
42MODULE_DEVICE_TABLE(acpi, bt_device_ids); 42MODULE_DEVICE_TABLE(acpi, bt_device_ids);
43 43
44#ifdef CONFIG_PM_SLEEP
44static int toshiba_bt_resume(struct device *dev); 45static int toshiba_bt_resume(struct device *dev);
46#endif
45static SIMPLE_DEV_PM_OPS(toshiba_bt_pm, NULL, toshiba_bt_resume); 47static SIMPLE_DEV_PM_OPS(toshiba_bt_pm, NULL, toshiba_bt_resume);
46 48
47static struct acpi_driver toshiba_bt_rfkill_driver = { 49static struct acpi_driver toshiba_bt_rfkill_driver = {
@@ -90,10 +92,12 @@ static void toshiba_bt_rfkill_notify(struct acpi_device *device, u32 event)
90 toshiba_bluetooth_enable(device->handle); 92 toshiba_bluetooth_enable(device->handle);
91} 93}
92 94
95#ifdef CONFIG_PM_SLEEP
93static int toshiba_bt_resume(struct device *dev) 96static int toshiba_bt_resume(struct device *dev)
94{ 97{
95 return toshiba_bluetooth_enable(to_acpi_device(dev)->handle); 98 return toshiba_bluetooth_enable(to_acpi_device(dev)->handle);
96} 99}
100#endif
97 101
98static int toshiba_bt_rfkill_add(struct acpi_device *device) 102static int toshiba_bt_rfkill_add(struct acpi_device *device)
99{ 103{
diff --git a/drivers/platform/x86/xo15-ebook.c b/drivers/platform/x86/xo15-ebook.c
index 849c07c13bf6..38ba39d7ca7d 100644
--- a/drivers/platform/x86/xo15-ebook.c
+++ b/drivers/platform/x86/xo15-ebook.c
@@ -77,10 +77,12 @@ static void ebook_switch_notify(struct acpi_device *device, u32 event)
77 } 77 }
78} 78}
79 79
80#ifdef CONFIG_PM_SLEEP
80static int ebook_switch_resume(struct device *dev) 81static int ebook_switch_resume(struct device *dev)
81{ 82{
82 return ebook_send_state(to_acpi_device(dev)); 83 return ebook_send_state(to_acpi_device(dev));
83} 84}
85#endif
84 86
85static SIMPLE_DEV_PM_OPS(ebook_switch_pm, NULL, ebook_switch_resume); 87static SIMPLE_DEV_PM_OPS(ebook_switch_pm, NULL, ebook_switch_resume);
86 88