aboutsummaryrefslogtreecommitdiffstats
path: root/drivers
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2013-03-03 13:16:19 -0500
committerLinus Torvalds <torvalds@linux-foundation.org>2013-03-03 13:16:19 -0500
commit23caaeea271cfe3176f0e27374d2016bd7583ea8 (patch)
treeb603b654347c87cf211ce667e2406daa1339164a /drivers
parenta7c1120d2dcc83691bafa034d98f70285757e826 (diff)
parent445e8d007c29d7f4d497c7912236b69f608340c6 (diff)
Merge branch 'for_linus' of git://cavan.codon.org.uk/platform-drivers-x86
Pull x86 platform driver updates from Matthew Garrett: "Mostly relatively small updates, along with some hardware enablement for Sony hardware and a pile of updates to Google's Chromebook driver" * 'for_linus' of git://cavan.codon.org.uk/platform-drivers-x86: (49 commits) ideapad-laptop: Depend on BACKLIGHT_CLASS_DEVICE instead of selecting it ideapad: depends on backlight subsystem and update comment Platform: x86: chromeos_laptop - add i915 gmbuses to adapter names Platform: x86: chromeos_laptop - Add isl light sensor for Pixel Platform: x86: chromeos_laptop - Add a more general add_i2c_device Platform: x86: chromeos_laptop - Add Pixel Touchscreen Platform: x86: chromeos_laptop - Add support for probing devices Platform: x86: chromeos_laptop - Add Pixel Trackpad hp-wmi: fix handling of platform device sony-laptop: leak in error handling sony_nc_lid_resume_setup() hp-wmi: Add support for SMBus hotkeys asus-wmi: Fix unused function build warning acer-wmi: avoid the warning of 'devices' may be used uninitialized drivers/platform/x86/thinkpad_acpi.c: Handle HKEY event 0x6040 Platform: x86: chromeos_laptop - Add HP Pavilion 14 Platform: x86: chromeos_laptop - Add Taos tsl2583 device Platform: x86: chromeos_laptop - Add Taos tsl2563 device Platform: x86: chromeos_laptop - Add Acer C7 trackpad Platform: x86: chromeos_laptop - Rename setup_lumpy_tp to setup_cyapa_smbus_tp asus-laptop: always report brightness key events ...
Diffstat (limited to 'drivers')
-rw-r--r--drivers/platform/x86/Kconfig15
-rw-r--r--drivers/platform/x86/Makefile1
-rw-r--r--drivers/platform/x86/acer-wmi.c21
-rw-r--r--drivers/platform/x86/asus-laptop.c85
-rw-r--r--drivers/platform/x86/asus-nb-wmi.c76
-rw-r--r--drivers/platform/x86/asus-wmi.c108
-rw-r--r--drivers/platform/x86/asus-wmi.h9
-rw-r--r--drivers/platform/x86/chromeos_laptop.c371
-rw-r--r--drivers/platform/x86/eeepc-wmi.c2
-rw-r--r--drivers/platform/x86/hp-wmi.c117
-rw-r--r--drivers/platform/x86/msi-laptop.c374
-rw-r--r--drivers/platform/x86/msi-wmi.c224
-rw-r--r--drivers/platform/x86/sony-laptop.c145
-rw-r--r--drivers/platform/x86/thinkpad_acpi.c17
14 files changed, 1292 insertions, 273 deletions
diff --git a/drivers/platform/x86/Kconfig b/drivers/platform/x86/Kconfig
index 7ab0b2fba503..3338437b559b 100644
--- a/drivers/platform/x86/Kconfig
+++ b/drivers/platform/x86/Kconfig
@@ -79,6 +79,17 @@ config ASUS_LAPTOP
79 79
80 If you have an ACPI-compatible ASUS laptop, say Y or M here. 80 If you have an ACPI-compatible ASUS laptop, say Y or M here.
81 81
82config CHROMEOS_LAPTOP
83 tristate "Chrome OS Laptop"
84 depends on I2C
85 depends on DMI
86 ---help---
87 This driver instantiates i2c and smbus devices such as
88 light sensors and touchpads.
89
90 If you have a supported Chromebook, choose Y or M here.
91 The module will be called chromeos_laptop.
92
82config DELL_LAPTOP 93config DELL_LAPTOP
83 tristate "Dell Laptop Extras" 94 tristate "Dell Laptop Extras"
84 depends on X86 95 depends on X86
@@ -288,9 +299,11 @@ config IDEAPAD_LAPTOP
288 depends on ACPI 299 depends on ACPI
289 depends on RFKILL && INPUT 300 depends on RFKILL && INPUT
290 depends on SERIO_I8042 301 depends on SERIO_I8042
302 depends on BACKLIGHT_CLASS_DEVICE
291 select INPUT_SPARSEKMAP 303 select INPUT_SPARSEKMAP
292 help 304 help
293 This is a driver for the rfkill switches on Lenovo IdeaPad netbooks. 305 This is a driver for Lenovo IdeaPad netbooks contains drivers for
306 rfkill switch, hotkey, fan control and backlight control.
294 307
295config THINKPAD_ACPI 308config THINKPAD_ACPI
296 tristate "ThinkPad ACPI Laptop Extras" 309 tristate "ThinkPad ACPI Laptop Extras"
diff --git a/drivers/platform/x86/Makefile b/drivers/platform/x86/Makefile
index bf7e4f935b17..ace2b38942fe 100644
--- a/drivers/platform/x86/Makefile
+++ b/drivers/platform/x86/Makefile
@@ -50,3 +50,4 @@ obj-$(CONFIG_INTEL_MID_POWER_BUTTON) += intel_mid_powerbtn.o
50obj-$(CONFIG_INTEL_OAKTRAIL) += intel_oaktrail.o 50obj-$(CONFIG_INTEL_OAKTRAIL) += intel_oaktrail.o
51obj-$(CONFIG_SAMSUNG_Q10) += samsung-q10.o 51obj-$(CONFIG_SAMSUNG_Q10) += samsung-q10.o
52obj-$(CONFIG_APPLE_GMUX) += apple-gmux.o 52obj-$(CONFIG_APPLE_GMUX) += apple-gmux.o
53obj-$(CONFIG_CHROMEOS_LAPTOP) += chromeos_laptop.o
diff --git a/drivers/platform/x86/acer-wmi.c b/drivers/platform/x86/acer-wmi.c
index afed7018a2b5..c9076bdaf2c1 100644
--- a/drivers/platform/x86/acer-wmi.c
+++ b/drivers/platform/x86/acer-wmi.c
@@ -511,6 +511,24 @@ static struct dmi_system_id acer_quirks[] = {
511 }, 511 },
512 .driver_data = &quirk_fujitsu_amilo_li_1718, 512 .driver_data = &quirk_fujitsu_amilo_li_1718,
513 }, 513 },
514 {
515 .callback = dmi_matched,
516 .ident = "Lenovo Ideapad S205-10382JG",
517 .matches = {
518 DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
519 DMI_MATCH(DMI_PRODUCT_NAME, "10382JG"),
520 },
521 .driver_data = &quirk_lenovo_ideapad_s205,
522 },
523 {
524 .callback = dmi_matched,
525 .ident = "Lenovo Ideapad S205-1038DPG",
526 .matches = {
527 DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
528 DMI_MATCH(DMI_PRODUCT_NAME, "1038DPG"),
529 },
530 .driver_data = &quirk_lenovo_ideapad_s205,
531 },
514 {} 532 {}
515}; 533};
516 534
@@ -1204,6 +1222,9 @@ static acpi_status WMID_set_capabilities(void)
1204 devices = *((u32 *) obj->buffer.pointer); 1222 devices = *((u32 *) obj->buffer.pointer);
1205 } else if (obj->type == ACPI_TYPE_INTEGER) { 1223 } else if (obj->type == ACPI_TYPE_INTEGER) {
1206 devices = (u32) obj->integer.value; 1224 devices = (u32) obj->integer.value;
1225 } else {
1226 kfree(out.pointer);
1227 return AE_ERROR;
1207 } 1228 }
1208 } else { 1229 } else {
1209 kfree(out.pointer); 1230 kfree(out.pointer);
diff --git a/drivers/platform/x86/asus-laptop.c b/drivers/platform/x86/asus-laptop.c
index d9f9a0dbc6f3..0eea09c1c134 100644
--- a/drivers/platform/x86/asus-laptop.c
+++ b/drivers/platform/x86/asus-laptop.c
@@ -128,10 +128,12 @@ MODULE_PARM_DESC(als_status, "Set the ALS status on boot "
128/* 128/*
129 * Some events we use, same for all Asus 129 * Some events we use, same for all Asus
130 */ 130 */
131#define ATKD_BR_UP 0x10 /* (event & ~ATKD_BR_UP) = brightness level */ 131#define ATKD_BRNUP_MIN 0x10
132#define ATKD_BR_DOWN 0x20 /* (event & ~ATKD_BR_DOWN) = britghness level */ 132#define ATKD_BRNUP_MAX 0x1f
133#define ATKD_BR_MIN ATKD_BR_UP 133#define ATKD_BRNDOWN_MIN 0x20
134#define ATKD_BR_MAX (ATKD_BR_DOWN | 0xF) /* 0x2f */ 134#define ATKD_BRNDOWN_MAX 0x2f
135#define ATKD_BRNDOWN 0x20
136#define ATKD_BRNUP 0x2f
135#define ATKD_LCD_ON 0x33 137#define ATKD_LCD_ON 0x33
136#define ATKD_LCD_OFF 0x34 138#define ATKD_LCD_OFF 0x34
137 139
@@ -301,40 +303,65 @@ static const struct key_entry asus_keymap[] = {
301 {KE_KEY, 0x17, { KEY_ZOOM } }, 303 {KE_KEY, 0x17, { KEY_ZOOM } },
302 {KE_KEY, 0x1f, { KEY_BATTERY } }, 304 {KE_KEY, 0x1f, { KEY_BATTERY } },
303 /* End of Lenovo SL Specific keycodes */ 305 /* End of Lenovo SL Specific keycodes */
306 {KE_KEY, ATKD_BRNDOWN, { KEY_BRIGHTNESSDOWN } },
307 {KE_KEY, ATKD_BRNUP, { KEY_BRIGHTNESSUP } },
304 {KE_KEY, 0x30, { KEY_VOLUMEUP } }, 308 {KE_KEY, 0x30, { KEY_VOLUMEUP } },
305 {KE_KEY, 0x31, { KEY_VOLUMEDOWN } }, 309 {KE_KEY, 0x31, { KEY_VOLUMEDOWN } },
306 {KE_KEY, 0x32, { KEY_MUTE } }, 310 {KE_KEY, 0x32, { KEY_MUTE } },
307 {KE_KEY, 0x33, { KEY_SWITCHVIDEOMODE } }, 311 {KE_KEY, 0x33, { KEY_DISPLAYTOGGLE } }, /* LCD on */
308 {KE_KEY, 0x34, { KEY_SWITCHVIDEOMODE } }, 312 {KE_KEY, 0x34, { KEY_DISPLAY_OFF } }, /* LCD off */
309 {KE_KEY, 0x40, { KEY_PREVIOUSSONG } }, 313 {KE_KEY, 0x40, { KEY_PREVIOUSSONG } },
310 {KE_KEY, 0x41, { KEY_NEXTSONG } }, 314 {KE_KEY, 0x41, { KEY_NEXTSONG } },
311 {KE_KEY, 0x43, { KEY_STOPCD } }, 315 {KE_KEY, 0x43, { KEY_STOPCD } }, /* Stop/Eject */
312 {KE_KEY, 0x45, { KEY_PLAYPAUSE } }, 316 {KE_KEY, 0x45, { KEY_PLAYPAUSE } },
313 {KE_KEY, 0x4c, { KEY_MEDIA } }, 317 {KE_KEY, 0x4c, { KEY_MEDIA } }, /* WMP Key */
314 {KE_KEY, 0x50, { KEY_EMAIL } }, 318 {KE_KEY, 0x50, { KEY_EMAIL } },
315 {KE_KEY, 0x51, { KEY_WWW } }, 319 {KE_KEY, 0x51, { KEY_WWW } },
316 {KE_KEY, 0x55, { KEY_CALC } }, 320 {KE_KEY, 0x55, { KEY_CALC } },
321 {KE_IGNORE, 0x57, }, /* Battery mode */
322 {KE_IGNORE, 0x58, }, /* AC mode */
317 {KE_KEY, 0x5C, { KEY_SCREENLOCK } }, /* Screenlock */ 323 {KE_KEY, 0x5C, { KEY_SCREENLOCK } }, /* Screenlock */
318 {KE_KEY, 0x5D, { KEY_WLAN } }, 324 {KE_KEY, 0x5D, { KEY_WLAN } }, /* WLAN Toggle */
319 {KE_KEY, 0x5E, { KEY_WLAN } }, 325 {KE_KEY, 0x5E, { KEY_WLAN } }, /* WLAN Enable */
320 {KE_KEY, 0x5F, { KEY_WLAN } }, 326 {KE_KEY, 0x5F, { KEY_WLAN } }, /* WLAN Disable */
321 {KE_KEY, 0x60, { KEY_SWITCHVIDEOMODE } }, 327 {KE_KEY, 0x60, { KEY_TOUCHPAD_ON } },
322 {KE_KEY, 0x61, { KEY_SWITCHVIDEOMODE } }, 328 {KE_KEY, 0x61, { KEY_SWITCHVIDEOMODE } }, /* SDSP LCD only */
323 {KE_KEY, 0x62, { KEY_SWITCHVIDEOMODE } }, 329 {KE_KEY, 0x62, { KEY_SWITCHVIDEOMODE } }, /* SDSP CRT only */
324 {KE_KEY, 0x63, { KEY_SWITCHVIDEOMODE } }, 330 {KE_KEY, 0x63, { KEY_SWITCHVIDEOMODE } }, /* SDSP LCD + CRT */
325 {KE_KEY, 0x6B, { KEY_F13 } }, /* Lock Touchpad */ 331 {KE_KEY, 0x64, { KEY_SWITCHVIDEOMODE } }, /* SDSP TV */
332 {KE_KEY, 0x65, { KEY_SWITCHVIDEOMODE } }, /* SDSP LCD + TV */
333 {KE_KEY, 0x66, { KEY_SWITCHVIDEOMODE } }, /* SDSP CRT + TV */
334 {KE_KEY, 0x67, { KEY_SWITCHVIDEOMODE } }, /* SDSP LCD + CRT + TV */
335 {KE_KEY, 0x6B, { KEY_TOUCHPAD_TOGGLE } }, /* Lock Touchpad */
326 {KE_KEY, 0x6C, { KEY_SLEEP } }, /* Suspend */ 336 {KE_KEY, 0x6C, { KEY_SLEEP } }, /* Suspend */
327 {KE_KEY, 0x6D, { KEY_SLEEP } }, /* Hibernate */ 337 {KE_KEY, 0x6D, { KEY_SLEEP } }, /* Hibernate */
328 {KE_KEY, 0x7E, { KEY_BLUETOOTH } }, 338 {KE_IGNORE, 0x6E, }, /* Low Battery notification */
329 {KE_KEY, 0x7D, { KEY_BLUETOOTH } }, 339 {KE_KEY, 0x7D, { KEY_BLUETOOTH } }, /* Bluetooth Enable */
340 {KE_KEY, 0x7E, { KEY_BLUETOOTH } }, /* Bluetooth Disable */
330 {KE_KEY, 0x82, { KEY_CAMERA } }, 341 {KE_KEY, 0x82, { KEY_CAMERA } },
331 {KE_KEY, 0x88, { KEY_WLAN } }, 342 {KE_KEY, 0x88, { KEY_RFKILL } }, /* Radio Toggle Key */
332 {KE_KEY, 0x8A, { KEY_PROG1 } }, 343 {KE_KEY, 0x8A, { KEY_PROG1 } }, /* Color enhancement mode */
344 {KE_KEY, 0x8C, { KEY_SWITCHVIDEOMODE } }, /* SDSP DVI only */
345 {KE_KEY, 0x8D, { KEY_SWITCHVIDEOMODE } }, /* SDSP LCD + DVI */
346 {KE_KEY, 0x8E, { KEY_SWITCHVIDEOMODE } }, /* SDSP CRT + DVI */
347 {KE_KEY, 0x8F, { KEY_SWITCHVIDEOMODE } }, /* SDSP TV + DVI */
348 {KE_KEY, 0x90, { KEY_SWITCHVIDEOMODE } }, /* SDSP LCD + CRT + DVI */
349 {KE_KEY, 0x91, { KEY_SWITCHVIDEOMODE } }, /* SDSP LCD + TV + DVI */
350 {KE_KEY, 0x92, { KEY_SWITCHVIDEOMODE } }, /* SDSP CRT + TV + DVI */
351 {KE_KEY, 0x93, { KEY_SWITCHVIDEOMODE } }, /* SDSP LCD + CRT + TV + DVI */
333 {KE_KEY, 0x95, { KEY_MEDIA } }, 352 {KE_KEY, 0x95, { KEY_MEDIA } },
334 {KE_KEY, 0x99, { KEY_PHONE } }, 353 {KE_KEY, 0x99, { KEY_PHONE } },
335 {KE_KEY, 0xc4, { KEY_KBDILLUMUP } }, 354 {KE_KEY, 0xA0, { KEY_SWITCHVIDEOMODE } }, /* SDSP HDMI only */
336 {KE_KEY, 0xc5, { KEY_KBDILLUMDOWN } }, 355 {KE_KEY, 0xA1, { KEY_SWITCHVIDEOMODE } }, /* SDSP LCD + HDMI */
337 {KE_KEY, 0xb5, { KEY_CALC } }, 356 {KE_KEY, 0xA2, { KEY_SWITCHVIDEOMODE } }, /* SDSP CRT + HDMI */
357 {KE_KEY, 0xA3, { KEY_SWITCHVIDEOMODE } }, /* SDSP TV + HDMI */
358 {KE_KEY, 0xA4, { KEY_SWITCHVIDEOMODE } }, /* SDSP LCD + CRT + HDMI */
359 {KE_KEY, 0xA5, { KEY_SWITCHVIDEOMODE } }, /* SDSP LCD + TV + HDMI */
360 {KE_KEY, 0xA6, { KEY_SWITCHVIDEOMODE } }, /* SDSP CRT + TV + HDMI */
361 {KE_KEY, 0xA7, { KEY_SWITCHVIDEOMODE } }, /* SDSP LCD + CRT + TV + HDMI */
362 {KE_KEY, 0xB5, { KEY_CALC } },
363 {KE_KEY, 0xC4, { KEY_KBDILLUMUP } },
364 {KE_KEY, 0xC5, { KEY_KBDILLUMDOWN } },
338 {KE_END, 0}, 365 {KE_END, 0},
339}; 366};
340 367
@@ -1521,15 +1548,19 @@ static void asus_acpi_notify(struct acpi_device *device, u32 event)
1521 dev_name(&asus->device->dev), event, 1548 dev_name(&asus->device->dev), event,
1522 count); 1549 count);
1523 1550
1524 /* Brightness events are special */ 1551 if (event >= ATKD_BRNUP_MIN && event <= ATKD_BRNUP_MAX)
1525 if (event >= ATKD_BR_MIN && event <= ATKD_BR_MAX) { 1552 event = ATKD_BRNUP;
1553 else if (event >= ATKD_BRNDOWN_MIN &&
1554 event <= ATKD_BRNDOWN_MAX)
1555 event = ATKD_BRNDOWN;
1526 1556
1527 /* Ignore them completely if the acpi video driver is used */ 1557 /* Brightness events are special */
1558 if (event == ATKD_BRNDOWN || event == ATKD_BRNUP) {
1528 if (asus->backlight_device != NULL) { 1559 if (asus->backlight_device != NULL) {
1529 /* Update the backlight device. */ 1560 /* Update the backlight device. */
1530 asus_backlight_notify(asus); 1561 asus_backlight_notify(asus);
1562 return ;
1531 } 1563 }
1532 return ;
1533 } 1564 }
1534 1565
1535 /* Accelerometer "coarse orientation change" event */ 1566 /* Accelerometer "coarse orientation change" event */
diff --git a/drivers/platform/x86/asus-nb-wmi.c b/drivers/platform/x86/asus-nb-wmi.c
index be790402e0f1..210b5b872125 100644
--- a/drivers/platform/x86/asus-nb-wmi.c
+++ b/drivers/platform/x86/asus-nb-wmi.c
@@ -59,6 +59,17 @@ static struct quirk_entry quirk_asus_unknown = {
59 .wapf = 0, 59 .wapf = 0,
60}; 60};
61 61
62/*
63 * For those machines that need software to control bt/wifi status
64 * and can't adjust brightness through ACPI interface
65 * and have duplicate events(ACPI and WMI) for display toggle
66 */
67static struct quirk_entry quirk_asus_x55u = {
68 .wapf = 4,
69 .wmi_backlight_power = true,
70 .no_display_toggle = true,
71};
72
62static struct quirk_entry quirk_asus_x401u = { 73static struct quirk_entry quirk_asus_x401u = {
63 .wapf = 4, 74 .wapf = 4,
64}; 75};
@@ -77,6 +88,15 @@ static struct dmi_system_id asus_quirks[] = {
77 DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."), 88 DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."),
78 DMI_MATCH(DMI_PRODUCT_NAME, "X401U"), 89 DMI_MATCH(DMI_PRODUCT_NAME, "X401U"),
79 }, 90 },
91 .driver_data = &quirk_asus_x55u,
92 },
93 {
94 .callback = dmi_matched,
95 .ident = "ASUSTeK COMPUTER INC. X401A",
96 .matches = {
97 DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."),
98 DMI_MATCH(DMI_PRODUCT_NAME, "X401A"),
99 },
80 .driver_data = &quirk_asus_x401u, 100 .driver_data = &quirk_asus_x401u,
81 }, 101 },
82 { 102 {
@@ -95,6 +115,15 @@ static struct dmi_system_id asus_quirks[] = {
95 DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."), 115 DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."),
96 DMI_MATCH(DMI_PRODUCT_NAME, "X501U"), 116 DMI_MATCH(DMI_PRODUCT_NAME, "X501U"),
97 }, 117 },
118 .driver_data = &quirk_asus_x55u,
119 },
120 {
121 .callback = dmi_matched,
122 .ident = "ASUSTeK COMPUTER INC. X501A",
123 .matches = {
124 DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."),
125 DMI_MATCH(DMI_PRODUCT_NAME, "X501A"),
126 },
98 .driver_data = &quirk_asus_x401u, 127 .driver_data = &quirk_asus_x401u,
99 }, 128 },
100 { 129 {
@@ -131,7 +160,7 @@ static struct dmi_system_id asus_quirks[] = {
131 DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."), 160 DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."),
132 DMI_MATCH(DMI_PRODUCT_NAME, "X55U"), 161 DMI_MATCH(DMI_PRODUCT_NAME, "X55U"),
133 }, 162 },
134 .driver_data = &quirk_asus_x401u, 163 .driver_data = &quirk_asus_x55u,
135 }, 164 },
136 { 165 {
137 .callback = dmi_matched, 166 .callback = dmi_matched,
@@ -161,6 +190,8 @@ static void asus_nb_wmi_quirks(struct asus_wmi_driver *driver)
161} 190}
162 191
163static const struct key_entry asus_nb_wmi_keymap[] = { 192static const struct key_entry asus_nb_wmi_keymap[] = {
193 { KE_KEY, ASUS_WMI_BRN_DOWN, { KEY_BRIGHTNESSDOWN } },
194 { KE_KEY, ASUS_WMI_BRN_UP, { KEY_BRIGHTNESSUP } },
164 { KE_KEY, 0x30, { KEY_VOLUMEUP } }, 195 { KE_KEY, 0x30, { KEY_VOLUMEUP } },
165 { KE_KEY, 0x31, { KEY_VOLUMEDOWN } }, 196 { KE_KEY, 0x31, { KEY_VOLUMEDOWN } },
166 { KE_KEY, 0x32, { KEY_MUTE } }, 197 { KE_KEY, 0x32, { KEY_MUTE } },
@@ -168,9 +199,9 @@ static const struct key_entry asus_nb_wmi_keymap[] = {
168 { KE_KEY, 0x34, { KEY_DISPLAY_OFF } }, /* LCD off */ 199 { KE_KEY, 0x34, { KEY_DISPLAY_OFF } }, /* LCD off */
169 { KE_KEY, 0x40, { KEY_PREVIOUSSONG } }, 200 { KE_KEY, 0x40, { KEY_PREVIOUSSONG } },
170 { KE_KEY, 0x41, { KEY_NEXTSONG } }, 201 { KE_KEY, 0x41, { KEY_NEXTSONG } },
171 { KE_KEY, 0x43, { KEY_STOPCD } }, 202 { KE_KEY, 0x43, { KEY_STOPCD } }, /* Stop/Eject */
172 { KE_KEY, 0x45, { KEY_PLAYPAUSE } }, 203 { KE_KEY, 0x45, { KEY_PLAYPAUSE } },
173 { KE_KEY, 0x4c, { KEY_MEDIA } }, 204 { KE_KEY, 0x4c, { KEY_MEDIA } }, /* WMP Key */
174 { KE_KEY, 0x50, { KEY_EMAIL } }, 205 { KE_KEY, 0x50, { KEY_EMAIL } },
175 { KE_KEY, 0x51, { KEY_WWW } }, 206 { KE_KEY, 0x51, { KEY_WWW } },
176 { KE_KEY, 0x55, { KEY_CALC } }, 207 { KE_KEY, 0x55, { KEY_CALC } },
@@ -180,25 +211,42 @@ static const struct key_entry asus_nb_wmi_keymap[] = {
180 { KE_KEY, 0x5D, { KEY_WLAN } }, /* Wireless console Toggle */ 211 { KE_KEY, 0x5D, { KEY_WLAN } }, /* Wireless console Toggle */
181 { KE_KEY, 0x5E, { KEY_WLAN } }, /* Wireless console Enable */ 212 { KE_KEY, 0x5E, { KEY_WLAN } }, /* Wireless console Enable */
182 { KE_KEY, 0x5F, { KEY_WLAN } }, /* Wireless console Disable */ 213 { KE_KEY, 0x5F, { KEY_WLAN } }, /* Wireless console Disable */
183 { KE_KEY, 0x60, { KEY_SWITCHVIDEOMODE } }, 214 { KE_KEY, 0x60, { KEY_TOUCHPAD_ON } },
184 { KE_KEY, 0x61, { KEY_SWITCHVIDEOMODE } }, 215 { KE_KEY, 0x61, { KEY_SWITCHVIDEOMODE } }, /* SDSP LCD only */
185 { KE_KEY, 0x62, { KEY_SWITCHVIDEOMODE } }, 216 { KE_KEY, 0x62, { KEY_SWITCHVIDEOMODE } }, /* SDSP CRT only */
186 { KE_KEY, 0x63, { KEY_SWITCHVIDEOMODE } }, 217 { KE_KEY, 0x63, { KEY_SWITCHVIDEOMODE } }, /* SDSP LCD + CRT */
218 { KE_KEY, 0x64, { KEY_SWITCHVIDEOMODE } }, /* SDSP TV */
219 { KE_KEY, 0x65, { KEY_SWITCHVIDEOMODE } }, /* SDSP LCD + TV */
220 { KE_KEY, 0x66, { KEY_SWITCHVIDEOMODE } }, /* SDSP CRT + TV */
221 { KE_KEY, 0x67, { KEY_SWITCHVIDEOMODE } }, /* SDSP LCD + CRT + TV */
187 { KE_KEY, 0x6B, { KEY_TOUCHPAD_TOGGLE } }, 222 { KE_KEY, 0x6B, { KEY_TOUCHPAD_TOGGLE } },
188 { KE_KEY, 0x7D, { KEY_BLUETOOTH } }, 223 { KE_IGNORE, 0x6E, }, /* Low Battery notification */
189 { KE_KEY, 0x7E, { KEY_BLUETOOTH } }, 224 { KE_KEY, 0x7D, { KEY_BLUETOOTH } }, /* Bluetooth Enable */
225 { KE_KEY, 0x7E, { KEY_BLUETOOTH } }, /* Bluetooth Disable */
190 { KE_KEY, 0x82, { KEY_CAMERA } }, 226 { KE_KEY, 0x82, { KEY_CAMERA } },
191 { KE_KEY, 0x88, { KEY_RFKILL } }, 227 { KE_KEY, 0x88, { KEY_RFKILL } }, /* Radio Toggle Key */
192 { KE_KEY, 0x8A, { KEY_PROG1 } }, 228 { KE_KEY, 0x8A, { KEY_PROG1 } }, /* Color enhancement mode */
229 { KE_KEY, 0x8C, { KEY_SWITCHVIDEOMODE } }, /* SDSP DVI only */
230 { KE_KEY, 0x8D, { KEY_SWITCHVIDEOMODE } }, /* SDSP LCD + DVI */
231 { KE_KEY, 0x8E, { KEY_SWITCHVIDEOMODE } }, /* SDSP CRT + DVI */
232 { KE_KEY, 0x8F, { KEY_SWITCHVIDEOMODE } }, /* SDSP TV + DVI */
233 { KE_KEY, 0x90, { KEY_SWITCHVIDEOMODE } }, /* SDSP LCD + CRT + DVI */
234 { KE_KEY, 0x91, { KEY_SWITCHVIDEOMODE } }, /* SDSP LCD + TV + DVI */
235 { KE_KEY, 0x92, { KEY_SWITCHVIDEOMODE } }, /* SDSP CRT + TV + DVI */
236 { KE_KEY, 0x93, { KEY_SWITCHVIDEOMODE } }, /* SDSP LCD + CRT + TV + DVI */
193 { KE_KEY, 0x95, { KEY_MEDIA } }, 237 { KE_KEY, 0x95, { KEY_MEDIA } },
194 { KE_KEY, 0x99, { KEY_PHONE } }, 238 { KE_KEY, 0x99, { KEY_PHONE } },
195 { KE_KEY, 0xA0, { KEY_SWITCHVIDEOMODE } }, /* SDSP HDMI only */ 239 { KE_KEY, 0xA0, { KEY_SWITCHVIDEOMODE } }, /* SDSP HDMI only */
196 { KE_KEY, 0xA1, { KEY_SWITCHVIDEOMODE } }, /* SDSP LCD + HDMI */ 240 { KE_KEY, 0xA1, { KEY_SWITCHVIDEOMODE } }, /* SDSP LCD + HDMI */
197 { KE_KEY, 0xA2, { KEY_SWITCHVIDEOMODE } }, /* SDSP CRT + HDMI */ 241 { KE_KEY, 0xA2, { KEY_SWITCHVIDEOMODE } }, /* SDSP CRT + HDMI */
198 { KE_KEY, 0xA3, { KEY_SWITCHVIDEOMODE } }, /* SDSP TV + HDMI */ 242 { KE_KEY, 0xA3, { KEY_SWITCHVIDEOMODE } }, /* SDSP TV + HDMI */
199 { KE_KEY, 0xb5, { KEY_CALC } }, 243 { KE_KEY, 0xA4, { KEY_SWITCHVIDEOMODE } }, /* SDSP LCD + CRT + HDMI */
200 { KE_KEY, 0xc4, { KEY_KBDILLUMUP } }, 244 { KE_KEY, 0xA5, { KEY_SWITCHVIDEOMODE } }, /* SDSP LCD + TV + HDMI */
201 { KE_KEY, 0xc5, { KEY_KBDILLUMDOWN } }, 245 { KE_KEY, 0xA6, { KEY_SWITCHVIDEOMODE } }, /* SDSP CRT + TV + HDMI */
246 { KE_KEY, 0xA7, { KEY_SWITCHVIDEOMODE } }, /* SDSP LCD + CRT + TV + HDMI */
247 { KE_KEY, 0xB5, { KEY_CALC } },
248 { KE_KEY, 0xC4, { KEY_KBDILLUMUP } },
249 { KE_KEY, 0xC5, { KEY_KBDILLUMDOWN } },
202 { KE_END, 0}, 250 { KE_END, 0},
203}; 251};
204 252
diff --git a/drivers/platform/x86/asus-wmi.c b/drivers/platform/x86/asus-wmi.c
index f80ae4d10f68..c11b2426dac1 100644
--- a/drivers/platform/x86/asus-wmi.c
+++ b/drivers/platform/x86/asus-wmi.c
@@ -187,6 +187,8 @@ struct asus_wmi {
187 struct device *hwmon_device; 187 struct device *hwmon_device;
188 struct platform_device *platform_device; 188 struct platform_device *platform_device;
189 189
190 struct led_classdev wlan_led;
191 int wlan_led_wk;
190 struct led_classdev tpd_led; 192 struct led_classdev tpd_led;
191 int tpd_led_wk; 193 int tpd_led_wk;
192 struct led_classdev kbd_led; 194 struct led_classdev kbd_led;
@@ -194,6 +196,7 @@ struct asus_wmi {
194 struct workqueue_struct *led_workqueue; 196 struct workqueue_struct *led_workqueue;
195 struct work_struct tpd_led_work; 197 struct work_struct tpd_led_work;
196 struct work_struct kbd_led_work; 198 struct work_struct kbd_led_work;
199 struct work_struct wlan_led_work;
197 200
198 struct asus_rfkill wlan; 201 struct asus_rfkill wlan;
199 struct asus_rfkill bluetooth; 202 struct asus_rfkill bluetooth;
@@ -456,12 +459,65 @@ static enum led_brightness kbd_led_get(struct led_classdev *led_cdev)
456 return value; 459 return value;
457} 460}
458 461
462static int wlan_led_unknown_state(struct asus_wmi *asus)
463{
464 u32 result;
465
466 asus_wmi_get_devstate(asus, ASUS_WMI_DEVID_WIRELESS_LED, &result);
467
468 return result & ASUS_WMI_DSTS_UNKNOWN_BIT;
469}
470
471static int wlan_led_presence(struct asus_wmi *asus)
472{
473 u32 result;
474
475 asus_wmi_get_devstate(asus, ASUS_WMI_DEVID_WIRELESS_LED, &result);
476
477 return result & ASUS_WMI_DSTS_PRESENCE_BIT;
478}
479
480static void wlan_led_update(struct work_struct *work)
481{
482 int ctrl_param;
483 struct asus_wmi *asus;
484
485 asus = container_of(work, struct asus_wmi, wlan_led_work);
486
487 ctrl_param = asus->wlan_led_wk;
488 asus_wmi_set_devstate(ASUS_WMI_DEVID_WIRELESS_LED, ctrl_param, NULL);
489}
490
491static void wlan_led_set(struct led_classdev *led_cdev,
492 enum led_brightness value)
493{
494 struct asus_wmi *asus;
495
496 asus = container_of(led_cdev, struct asus_wmi, wlan_led);
497
498 asus->wlan_led_wk = !!value;
499 queue_work(asus->led_workqueue, &asus->wlan_led_work);
500}
501
502static enum led_brightness wlan_led_get(struct led_classdev *led_cdev)
503{
504 struct asus_wmi *asus;
505 u32 result;
506
507 asus = container_of(led_cdev, struct asus_wmi, wlan_led);
508 asus_wmi_get_devstate(asus, ASUS_WMI_DEVID_WIRELESS_LED, &result);
509
510 return result & ASUS_WMI_DSTS_BRIGHTNESS_MASK;
511}
512
459static void asus_wmi_led_exit(struct asus_wmi *asus) 513static void asus_wmi_led_exit(struct asus_wmi *asus)
460{ 514{
461 if (!IS_ERR_OR_NULL(asus->kbd_led.dev)) 515 if (!IS_ERR_OR_NULL(asus->kbd_led.dev))
462 led_classdev_unregister(&asus->kbd_led); 516 led_classdev_unregister(&asus->kbd_led);
463 if (!IS_ERR_OR_NULL(asus->tpd_led.dev)) 517 if (!IS_ERR_OR_NULL(asus->tpd_led.dev))
464 led_classdev_unregister(&asus->tpd_led); 518 led_classdev_unregister(&asus->tpd_led);
519 if (!IS_ERR_OR_NULL(asus->wlan_led.dev))
520 led_classdev_unregister(&asus->wlan_led);
465 if (asus->led_workqueue) 521 if (asus->led_workqueue)
466 destroy_workqueue(asus->led_workqueue); 522 destroy_workqueue(asus->led_workqueue);
467} 523}
@@ -498,6 +554,23 @@ static int asus_wmi_led_init(struct asus_wmi *asus)
498 554
499 rv = led_classdev_register(&asus->platform_device->dev, 555 rv = led_classdev_register(&asus->platform_device->dev,
500 &asus->kbd_led); 556 &asus->kbd_led);
557 if (rv)
558 goto error;
559 }
560
561 if (wlan_led_presence(asus)) {
562 INIT_WORK(&asus->wlan_led_work, wlan_led_update);
563
564 asus->wlan_led.name = "asus::wlan";
565 asus->wlan_led.brightness_set = wlan_led_set;
566 if (!wlan_led_unknown_state(asus))
567 asus->wlan_led.brightness_get = wlan_led_get;
568 asus->wlan_led.flags = LED_CORE_SUSPENDRESUME;
569 asus->wlan_led.max_brightness = 1;
570 asus->wlan_led.default_trigger = "asus-wlan";
571
572 rv = led_classdev_register(&asus->platform_device->dev,
573 &asus->wlan_led);
501 } 574 }
502 575
503error: 576error:
@@ -813,6 +886,9 @@ static int asus_new_rfkill(struct asus_wmi *asus,
813 if (!*rfkill) 886 if (!*rfkill)
814 return -EINVAL; 887 return -EINVAL;
815 888
889 if (dev_id == ASUS_WMI_DEVID_WLAN)
890 rfkill_set_led_trigger_name(*rfkill, "asus-wlan");
891
816 rfkill_init_sw_state(*rfkill, !result); 892 rfkill_init_sw_state(*rfkill, !result);
817 result = rfkill_register(*rfkill); 893 result = rfkill_register(*rfkill);
818 if (result) { 894 if (result) {
@@ -1265,6 +1341,18 @@ static void asus_wmi_backlight_exit(struct asus_wmi *asus)
1265 asus->backlight_device = NULL; 1341 asus->backlight_device = NULL;
1266} 1342}
1267 1343
1344static int is_display_toggle(int code)
1345{
1346 /* display toggle keys */
1347 if ((code >= 0x61 && code <= 0x67) ||
1348 (code >= 0x8c && code <= 0x93) ||
1349 (code >= 0xa0 && code <= 0xa7) ||
1350 (code >= 0xd0 && code <= 0xd5))
1351 return 1;
1352
1353 return 0;
1354}
1355
1268static void asus_wmi_notify(u32 value, void *context) 1356static void asus_wmi_notify(u32 value, void *context)
1269{ 1357{
1270 struct asus_wmi *asus = context; 1358 struct asus_wmi *asus = context;
@@ -1298,16 +1386,24 @@ static void asus_wmi_notify(u32 value, void *context)
1298 } 1386 }
1299 1387
1300 if (code >= NOTIFY_BRNUP_MIN && code <= NOTIFY_BRNUP_MAX) 1388 if (code >= NOTIFY_BRNUP_MIN && code <= NOTIFY_BRNUP_MAX)
1301 code = NOTIFY_BRNUP_MIN; 1389 code = ASUS_WMI_BRN_UP;
1302 else if (code >= NOTIFY_BRNDOWN_MIN && 1390 else if (code >= NOTIFY_BRNDOWN_MIN &&
1303 code <= NOTIFY_BRNDOWN_MAX) 1391 code <= NOTIFY_BRNDOWN_MAX)
1304 code = NOTIFY_BRNDOWN_MIN; 1392 code = ASUS_WMI_BRN_DOWN;
1305 1393
1306 if (code == NOTIFY_BRNUP_MIN || code == NOTIFY_BRNDOWN_MIN) { 1394 if (code == ASUS_WMI_BRN_DOWN || code == ASUS_WMI_BRN_UP) {
1307 if (!acpi_video_backlight_support()) 1395 if (!acpi_video_backlight_support()) {
1308 asus_wmi_backlight_notify(asus, orig_code); 1396 asus_wmi_backlight_notify(asus, orig_code);
1309 } else if (!sparse_keymap_report_event(asus->inputdev, code, 1397 goto exit;
1310 key_value, autorelease)) 1398 }
1399 }
1400
1401 if (is_display_toggle(code) &&
1402 asus->driver->quirks->no_display_toggle)
1403 goto exit;
1404
1405 if (!sparse_keymap_report_event(asus->inputdev, code,
1406 key_value, autorelease))
1311 pr_info("Unknown key %x pressed\n", code); 1407 pr_info("Unknown key %x pressed\n", code);
1312 1408
1313exit: 1409exit:
diff --git a/drivers/platform/x86/asus-wmi.h b/drivers/platform/x86/asus-wmi.h
index 4c9bd38bb0a2..4da4c8bafe70 100644
--- a/drivers/platform/x86/asus-wmi.h
+++ b/drivers/platform/x86/asus-wmi.h
@@ -30,6 +30,8 @@
30#include <linux/platform_device.h> 30#include <linux/platform_device.h>
31 31
32#define ASUS_WMI_KEY_IGNORE (-1) 32#define ASUS_WMI_KEY_IGNORE (-1)
33#define ASUS_WMI_BRN_DOWN 0x20
34#define ASUS_WMI_BRN_UP 0x2f
33 35
34struct module; 36struct module;
35struct key_entry; 37struct key_entry;
@@ -41,6 +43,13 @@ struct quirk_entry {
41 bool store_backlight_power; 43 bool store_backlight_power;
42 bool wmi_backlight_power; 44 bool wmi_backlight_power;
43 int wapf; 45 int wapf;
46 /*
47 * For machines with AMD graphic chips, it will send out WMI event
48 * and ACPI interrupt at the same time while hitting the hotkey.
49 * To simplify the problem, we just have to ignore the WMI event,
50 * and let the ACPI interrupt to send out the key event.
51 */
52 int no_display_toggle;
44}; 53};
45 54
46struct asus_wmi_driver { 55struct asus_wmi_driver {
diff --git a/drivers/platform/x86/chromeos_laptop.c b/drivers/platform/x86/chromeos_laptop.c
new file mode 100644
index 000000000000..93d66809355a
--- /dev/null
+++ b/drivers/platform/x86/chromeos_laptop.c
@@ -0,0 +1,371 @@
1/*
2 * chromeos_laptop.c - Driver to instantiate Chromebook i2c/smbus devices.
3 *
4 * Author : Benson Leung <bleung@chromium.org>
5 *
6 * Copyright (C) 2012 Google, Inc.
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
21 *
22 */
23
24#include <linux/dmi.h>
25#include <linux/i2c.h>
26#include <linux/module.h>
27
28#define ATMEL_TP_I2C_ADDR 0x4b
29#define ATMEL_TP_I2C_BL_ADDR 0x25
30#define ATMEL_TS_I2C_ADDR 0x4a
31#define ATMEL_TS_I2C_BL_ADDR 0x26
32#define CYAPA_TP_I2C_ADDR 0x67
33#define ISL_ALS_I2C_ADDR 0x44
34#define TAOS_ALS_I2C_ADDR 0x29
35
36static struct i2c_client *als;
37static struct i2c_client *tp;
38static struct i2c_client *ts;
39
40const char *i2c_adapter_names[] = {
41 "SMBus I801 adapter",
42 "i915 gmbus vga",
43 "i915 gmbus panel",
44};
45
46/* Keep this enum consistent with i2c_adapter_names */
47enum i2c_adapter_type {
48 I2C_ADAPTER_SMBUS = 0,
49 I2C_ADAPTER_VGADDC,
50 I2C_ADAPTER_PANEL,
51};
52
53static struct i2c_board_info __initdata cyapa_device = {
54 I2C_BOARD_INFO("cyapa", CYAPA_TP_I2C_ADDR),
55 .flags = I2C_CLIENT_WAKE,
56};
57
58static struct i2c_board_info __initdata isl_als_device = {
59 I2C_BOARD_INFO("isl29018", ISL_ALS_I2C_ADDR),
60};
61
62static struct i2c_board_info __initdata tsl2583_als_device = {
63 I2C_BOARD_INFO("tsl2583", TAOS_ALS_I2C_ADDR),
64};
65
66static struct i2c_board_info __initdata tsl2563_als_device = {
67 I2C_BOARD_INFO("tsl2563", TAOS_ALS_I2C_ADDR),
68};
69
70static struct i2c_board_info __initdata atmel_224s_tp_device = {
71 I2C_BOARD_INFO("atmel_mxt_tp", ATMEL_TP_I2C_ADDR),
72 .platform_data = NULL,
73 .flags = I2C_CLIENT_WAKE,
74};
75
76static struct i2c_board_info __initdata atmel_1664s_device = {
77 I2C_BOARD_INFO("atmel_mxt_ts", ATMEL_TS_I2C_ADDR),
78 .platform_data = NULL,
79 .flags = I2C_CLIENT_WAKE,
80};
81
82static struct i2c_client __init *__add_probed_i2c_device(
83 const char *name,
84 int bus,
85 struct i2c_board_info *info,
86 const unsigned short *addrs)
87{
88 const struct dmi_device *dmi_dev;
89 const struct dmi_dev_onboard *dev_data;
90 struct i2c_adapter *adapter;
91 struct i2c_client *client;
92
93 if (bus < 0)
94 return NULL;
95 /*
96 * If a name is specified, look for irq platform information stashed
97 * in DMI_DEV_TYPE_DEV_ONBOARD by the Chrome OS custom system firmware.
98 */
99 if (name) {
100 dmi_dev = dmi_find_device(DMI_DEV_TYPE_DEV_ONBOARD, name, NULL);
101 if (!dmi_dev) {
102 pr_err("%s failed to dmi find device %s.\n",
103 __func__,
104 name);
105 return NULL;
106 }
107 dev_data = (struct dmi_dev_onboard *)dmi_dev->device_data;
108 if (!dev_data) {
109 pr_err("%s failed to get data from dmi for %s.\n",
110 __func__, name);
111 return NULL;
112 }
113 info->irq = dev_data->instance;
114 }
115
116 adapter = i2c_get_adapter(bus);
117 if (!adapter) {
118 pr_err("%s failed to get i2c adapter %d.\n", __func__, bus);
119 return NULL;
120 }
121
122 /* add the i2c device */
123 client = i2c_new_probed_device(adapter, info, addrs, NULL);
124 if (!client)
125 pr_err("%s failed to register device %d-%02x\n",
126 __func__, bus, info->addr);
127 else
128 pr_debug("%s added i2c device %d-%02x\n",
129 __func__, bus, info->addr);
130
131 i2c_put_adapter(adapter);
132 return client;
133}
134
135static int __init __find_i2c_adap(struct device *dev, void *data)
136{
137 const char *name = data;
138 static const char *prefix = "i2c-";
139 struct i2c_adapter *adapter;
140 if (strncmp(dev_name(dev), prefix, strlen(prefix)) != 0)
141 return 0;
142 adapter = to_i2c_adapter(dev);
143 return (strncmp(adapter->name, name, strlen(name)) == 0);
144}
145
146static int __init find_i2c_adapter_num(enum i2c_adapter_type type)
147{
148 struct device *dev = NULL;
149 struct i2c_adapter *adapter;
150 const char *name = i2c_adapter_names[type];
151 /* find the adapter by name */
152 dev = bus_find_device(&i2c_bus_type, NULL, (void *)name,
153 __find_i2c_adap);
154 if (!dev) {
155 pr_err("%s: i2c adapter %s not found on system.\n", __func__,
156 name);
157 return -ENODEV;
158 }
159 adapter = to_i2c_adapter(dev);
160 return adapter->nr;
161}
162
163/*
164 * Takes a list of addresses in addrs as such :
165 * { addr1, ... , addrn, I2C_CLIENT_END };
166 * add_probed_i2c_device will use i2c_new_probed_device
167 * and probe for devices at all of the addresses listed.
168 * Returns NULL if no devices found.
169 * See Documentation/i2c/instantiating-devices for more information.
170 */
171static __init struct i2c_client *add_probed_i2c_device(
172 const char *name,
173 enum i2c_adapter_type type,
174 struct i2c_board_info *info,
175 const unsigned short *addrs)
176{
177 return __add_probed_i2c_device(name,
178 find_i2c_adapter_num(type),
179 info,
180 addrs);
181}
182
183/*
184 * Probes for a device at a single address, the one provided by
185 * info->addr.
186 * Returns NULL if no device found.
187 */
188static __init struct i2c_client *add_i2c_device(const char *name,
189 enum i2c_adapter_type type,
190 struct i2c_board_info *info)
191{
192 const unsigned short addr_list[] = { info->addr, I2C_CLIENT_END };
193 return __add_probed_i2c_device(name,
194 find_i2c_adapter_num(type),
195 info,
196 addr_list);
197}
198
199
200static struct i2c_client __init *add_smbus_device(const char *name,
201 struct i2c_board_info *info)
202{
203 return add_i2c_device(name, I2C_ADAPTER_SMBUS, info);
204}
205
206static int __init setup_cyapa_smbus_tp(const struct dmi_system_id *id)
207{
208 /* add cyapa touchpad on smbus */
209 tp = add_smbus_device("trackpad", &cyapa_device);
210 return 0;
211}
212
213static int __init setup_atmel_224s_tp(const struct dmi_system_id *id)
214{
215 const unsigned short addr_list[] = { ATMEL_TP_I2C_BL_ADDR,
216 ATMEL_TP_I2C_ADDR,
217 I2C_CLIENT_END };
218
219 /* add atmel mxt touchpad on VGA DDC GMBus */
220 tp = add_probed_i2c_device("trackpad", I2C_ADAPTER_VGADDC,
221 &atmel_224s_tp_device, addr_list);
222 return 0;
223}
224
225static int __init setup_atmel_1664s_ts(const struct dmi_system_id *id)
226{
227 const unsigned short addr_list[] = { ATMEL_TS_I2C_BL_ADDR,
228 ATMEL_TS_I2C_ADDR,
229 I2C_CLIENT_END };
230
231 /* add atmel mxt touch device on PANEL GMBus */
232 ts = add_probed_i2c_device("touchscreen", I2C_ADAPTER_PANEL,
233 &atmel_1664s_device, addr_list);
234 return 0;
235}
236
237
238static int __init setup_isl29018_als(const struct dmi_system_id *id)
239{
240 /* add isl29018 light sensor */
241 als = add_smbus_device("lightsensor", &isl_als_device);
242 return 0;
243}
244
245static int __init setup_isl29023_als(const struct dmi_system_id *id)
246{
247 /* add isl29023 light sensor on Panel GMBus */
248 als = add_i2c_device("lightsensor", I2C_ADAPTER_PANEL,
249 &isl_als_device);
250 return 0;
251}
252
253static int __init setup_tsl2583_als(const struct dmi_system_id *id)
254{
255 /* add tsl2583 light sensor on smbus */
256 als = add_smbus_device(NULL, &tsl2583_als_device);
257 return 0;
258}
259
260static int __init setup_tsl2563_als(const struct dmi_system_id *id)
261{
262 /* add tsl2563 light sensor on smbus */
263 als = add_smbus_device(NULL, &tsl2563_als_device);
264 return 0;
265}
266
267static struct dmi_system_id __initdata chromeos_laptop_dmi_table[] = {
268 {
269 .ident = "Samsung Series 5 550 - Touchpad",
270 .matches = {
271 DMI_MATCH(DMI_SYS_VENDOR, "SAMSUNG"),
272 DMI_MATCH(DMI_PRODUCT_NAME, "Lumpy"),
273 },
274 .callback = setup_cyapa_smbus_tp,
275 },
276 {
277 .ident = "Chromebook Pixel - Touchscreen",
278 .matches = {
279 DMI_MATCH(DMI_SYS_VENDOR, "GOOGLE"),
280 DMI_MATCH(DMI_PRODUCT_NAME, "Link"),
281 },
282 .callback = setup_atmel_1664s_ts,
283 },
284 {
285 .ident = "Chromebook Pixel - Touchpad",
286 .matches = {
287 DMI_MATCH(DMI_SYS_VENDOR, "GOOGLE"),
288 DMI_MATCH(DMI_PRODUCT_NAME, "Link"),
289 },
290 .callback = setup_atmel_224s_tp,
291 },
292 {
293 .ident = "Samsung Series 5 550 - Light Sensor",
294 .matches = {
295 DMI_MATCH(DMI_SYS_VENDOR, "SAMSUNG"),
296 DMI_MATCH(DMI_PRODUCT_NAME, "Lumpy"),
297 },
298 .callback = setup_isl29018_als,
299 },
300 {
301 .ident = "Chromebook Pixel - Light Sensor",
302 .matches = {
303 DMI_MATCH(DMI_SYS_VENDOR, "GOOGLE"),
304 DMI_MATCH(DMI_PRODUCT_NAME, "Link"),
305 },
306 .callback = setup_isl29023_als,
307 },
308 {
309 .ident = "Acer C7 Chromebook - Touchpad",
310 .matches = {
311 DMI_MATCH(DMI_PRODUCT_NAME, "Parrot"),
312 },
313 .callback = setup_cyapa_smbus_tp,
314 },
315 {
316 .ident = "HP Pavilion 14 Chromebook - Touchpad",
317 .matches = {
318 DMI_MATCH(DMI_PRODUCT_NAME, "Butterfly"),
319 },
320 .callback = setup_cyapa_smbus_tp,
321 },
322 {
323 .ident = "Samsung Series 5 - Light Sensor",
324 .matches = {
325 DMI_MATCH(DMI_PRODUCT_NAME, "Alex"),
326 },
327 .callback = setup_tsl2583_als,
328 },
329 {
330 .ident = "Cr-48 - Light Sensor",
331 .matches = {
332 DMI_MATCH(DMI_PRODUCT_NAME, "Mario"),
333 },
334 .callback = setup_tsl2563_als,
335 },
336 {
337 .ident = "Acer AC700 - Light Sensor",
338 .matches = {
339 DMI_MATCH(DMI_PRODUCT_NAME, "ZGB"),
340 },
341 .callback = setup_tsl2563_als,
342 },
343 { }
344};
345MODULE_DEVICE_TABLE(dmi, chromeos_laptop_dmi_table);
346
347static int __init chromeos_laptop_init(void)
348{
349 if (!dmi_check_system(chromeos_laptop_dmi_table)) {
350 pr_debug("%s unsupported system.\n", __func__);
351 return -ENODEV;
352 }
353 return 0;
354}
355
356static void __exit chromeos_laptop_exit(void)
357{
358 if (als)
359 i2c_unregister_device(als);
360 if (tp)
361 i2c_unregister_device(tp);
362 if (ts)
363 i2c_unregister_device(ts);
364}
365
366module_init(chromeos_laptop_init);
367module_exit(chromeos_laptop_exit);
368
369MODULE_DESCRIPTION("Chrome OS Laptop driver");
370MODULE_AUTHOR("Benson Leung <bleung@chromium.org>");
371MODULE_LICENSE("GPL");
diff --git a/drivers/platform/x86/eeepc-wmi.c b/drivers/platform/x86/eeepc-wmi.c
index 60cb76a5b513..af67e6e56ebb 100644
--- a/drivers/platform/x86/eeepc-wmi.c
+++ b/drivers/platform/x86/eeepc-wmi.c
@@ -63,6 +63,8 @@ MODULE_PARM_DESC(hotplug_wireless,
63#define HOME_RELEASE 0xe5 63#define HOME_RELEASE 0xe5
64 64
65static const struct key_entry eeepc_wmi_keymap[] = { 65static const struct key_entry eeepc_wmi_keymap[] = {
66 { KE_KEY, ASUS_WMI_BRN_DOWN, { KEY_BRIGHTNESSDOWN } },
67 { KE_KEY, ASUS_WMI_BRN_UP, { KEY_BRIGHTNESSUP } },
66 /* Sleep already handled via generic ACPI code */ 68 /* Sleep already handled via generic ACPI code */
67 { KE_KEY, 0x30, { KEY_VOLUMEUP } }, 69 { KE_KEY, 0x30, { KEY_VOLUMEUP } },
68 { KE_KEY, 0x31, { KEY_VOLUMEDOWN } }, 70 { KE_KEY, 0x31, { KEY_VOLUMEDOWN } },
diff --git a/drivers/platform/x86/hp-wmi.c b/drivers/platform/x86/hp-wmi.c
index 1dde7accf27c..45cacf79f3a7 100644
--- a/drivers/platform/x86/hp-wmi.c
+++ b/drivers/platform/x86/hp-wmi.c
@@ -60,6 +60,7 @@ enum hp_wmi_radio {
60 HPWMI_WIFI = 0, 60 HPWMI_WIFI = 0,
61 HPWMI_BLUETOOTH = 1, 61 HPWMI_BLUETOOTH = 1,
62 HPWMI_WWAN = 2, 62 HPWMI_WWAN = 2,
63 HPWMI_GPS = 3,
63}; 64};
64 65
65enum hp_wmi_event_ids { 66enum hp_wmi_event_ids {
@@ -72,10 +73,6 @@ enum hp_wmi_event_ids {
72 HPWMI_LOCK_SWITCH = 7, 73 HPWMI_LOCK_SWITCH = 7,
73}; 74};
74 75
75static int hp_wmi_bios_setup(struct platform_device *device);
76static int __exit hp_wmi_bios_remove(struct platform_device *device);
77static int hp_wmi_resume_handler(struct device *device);
78
79struct bios_args { 76struct bios_args {
80 u32 signature; 77 u32 signature;
81 u32 command; 78 u32 command;
@@ -137,6 +134,7 @@ static const struct key_entry hp_wmi_keymap[] = {
137 { KE_KEY, 0x2142, { KEY_MEDIA } }, 134 { KE_KEY, 0x2142, { KEY_MEDIA } },
138 { KE_KEY, 0x213b, { KEY_INFO } }, 135 { KE_KEY, 0x213b, { KEY_INFO } },
139 { KE_KEY, 0x2169, { KEY_DIRECTION } }, 136 { KE_KEY, 0x2169, { KEY_DIRECTION } },
137 { KE_KEY, 0x216a, { KEY_SETUP } },
140 { KE_KEY, 0x231b, { KEY_HELP } }, 138 { KE_KEY, 0x231b, { KEY_HELP } },
141 { KE_END, 0 } 139 { KE_END, 0 }
142}; 140};
@@ -147,6 +145,7 @@ static struct platform_device *hp_wmi_platform_dev;
147static struct rfkill *wifi_rfkill; 145static struct rfkill *wifi_rfkill;
148static struct rfkill *bluetooth_rfkill; 146static struct rfkill *bluetooth_rfkill;
149static struct rfkill *wwan_rfkill; 147static struct rfkill *wwan_rfkill;
148static struct rfkill *gps_rfkill;
150 149
151struct rfkill2_device { 150struct rfkill2_device {
152 u8 id; 151 u8 id;
@@ -157,21 +156,6 @@ struct rfkill2_device {
157static int rfkill2_count; 156static int rfkill2_count;
158static struct rfkill2_device rfkill2[HPWMI_MAX_RFKILL2_DEVICES]; 157static struct rfkill2_device rfkill2[HPWMI_MAX_RFKILL2_DEVICES];
159 158
160static const struct dev_pm_ops hp_wmi_pm_ops = {
161 .resume = hp_wmi_resume_handler,
162 .restore = hp_wmi_resume_handler,
163};
164
165static struct platform_driver hp_wmi_driver = {
166 .driver = {
167 .name = "hp-wmi",
168 .owner = THIS_MODULE,
169 .pm = &hp_wmi_pm_ops,
170 },
171 .probe = hp_wmi_bios_setup,
172 .remove = hp_wmi_bios_remove,
173};
174
175/* 159/*
176 * hp_wmi_perform_query 160 * hp_wmi_perform_query
177 * 161 *
@@ -543,6 +527,10 @@ static void hp_wmi_notify(u32 value, void *context)
543 rfkill_set_states(wwan_rfkill, 527 rfkill_set_states(wwan_rfkill,
544 hp_wmi_get_sw_state(HPWMI_WWAN), 528 hp_wmi_get_sw_state(HPWMI_WWAN),
545 hp_wmi_get_hw_state(HPWMI_WWAN)); 529 hp_wmi_get_hw_state(HPWMI_WWAN));
530 if (gps_rfkill)
531 rfkill_set_states(gps_rfkill,
532 hp_wmi_get_sw_state(HPWMI_GPS),
533 hp_wmi_get_hw_state(HPWMI_GPS));
546 break; 534 break;
547 case HPWMI_CPU_BATTERY_THROTTLE: 535 case HPWMI_CPU_BATTERY_THROTTLE:
548 pr_info("Unimplemented CPU throttle because of 3 Cell battery event detected\n"); 536 pr_info("Unimplemented CPU throttle because of 3 Cell battery event detected\n");
@@ -670,7 +658,7 @@ static int hp_wmi_rfkill_setup(struct platform_device *device)
670 (void *) HPWMI_WWAN); 658 (void *) HPWMI_WWAN);
671 if (!wwan_rfkill) { 659 if (!wwan_rfkill) {
672 err = -ENOMEM; 660 err = -ENOMEM;
673 goto register_bluetooth_error; 661 goto register_gps_error;
674 } 662 }
675 rfkill_init_sw_state(wwan_rfkill, 663 rfkill_init_sw_state(wwan_rfkill,
676 hp_wmi_get_sw_state(HPWMI_WWAN)); 664 hp_wmi_get_sw_state(HPWMI_WWAN));
@@ -681,10 +669,33 @@ static int hp_wmi_rfkill_setup(struct platform_device *device)
681 goto register_wwan_err; 669 goto register_wwan_err;
682 } 670 }
683 671
672 if (wireless & 0x8) {
673 gps_rfkill = rfkill_alloc("hp-gps", &device->dev,
674 RFKILL_TYPE_GPS,
675 &hp_wmi_rfkill_ops,
676 (void *) HPWMI_GPS);
677 if (!gps_rfkill) {
678 err = -ENOMEM;
679 goto register_bluetooth_error;
680 }
681 rfkill_init_sw_state(gps_rfkill,
682 hp_wmi_get_sw_state(HPWMI_GPS));
683 rfkill_set_hw_state(bluetooth_rfkill,
684 hp_wmi_get_hw_state(HPWMI_GPS));
685 err = rfkill_register(gps_rfkill);
686 if (err)
687 goto register_gps_error;
688 }
689
684 return 0; 690 return 0;
685register_wwan_err: 691register_wwan_err:
686 rfkill_destroy(wwan_rfkill); 692 rfkill_destroy(wwan_rfkill);
687 wwan_rfkill = NULL; 693 wwan_rfkill = NULL;
694 if (gps_rfkill)
695 rfkill_unregister(gps_rfkill);
696register_gps_error:
697 rfkill_destroy(gps_rfkill);
698 gps_rfkill = NULL;
688 if (bluetooth_rfkill) 699 if (bluetooth_rfkill)
689 rfkill_unregister(bluetooth_rfkill); 700 rfkill_unregister(bluetooth_rfkill);
690register_bluetooth_error: 701register_bluetooth_error:
@@ -729,6 +740,10 @@ static int hp_wmi_rfkill2_setup(struct platform_device *device)
729 type = RFKILL_TYPE_WWAN; 740 type = RFKILL_TYPE_WWAN;
730 name = "hp-wwan"; 741 name = "hp-wwan";
731 break; 742 break;
743 case HPWMI_GPS:
744 type = RFKILL_TYPE_GPS;
745 name = "hp-gps";
746 break;
732 default: 747 default:
733 pr_warn("unknown device type 0x%x\n", 748 pr_warn("unknown device type 0x%x\n",
734 state.device[i].radio_type); 749 state.device[i].radio_type);
@@ -778,7 +793,7 @@ fail:
778 return err; 793 return err;
779} 794}
780 795
781static int hp_wmi_bios_setup(struct platform_device *device) 796static int __init hp_wmi_bios_setup(struct platform_device *device)
782{ 797{
783 int err; 798 int err;
784 799
@@ -786,6 +801,7 @@ static int hp_wmi_bios_setup(struct platform_device *device)
786 wifi_rfkill = NULL; 801 wifi_rfkill = NULL;
787 bluetooth_rfkill = NULL; 802 bluetooth_rfkill = NULL;
788 wwan_rfkill = NULL; 803 wwan_rfkill = NULL;
804 gps_rfkill = NULL;
789 rfkill2_count = 0; 805 rfkill2_count = 0;
790 806
791 if (hp_wmi_rfkill_setup(device)) 807 if (hp_wmi_rfkill_setup(device))
@@ -835,6 +851,10 @@ static int __exit hp_wmi_bios_remove(struct platform_device *device)
835 rfkill_unregister(wwan_rfkill); 851 rfkill_unregister(wwan_rfkill);
836 rfkill_destroy(wwan_rfkill); 852 rfkill_destroy(wwan_rfkill);
837 } 853 }
854 if (gps_rfkill) {
855 rfkill_unregister(gps_rfkill);
856 rfkill_destroy(gps_rfkill);
857 }
838 858
839 return 0; 859 return 0;
840} 860}
@@ -870,51 +890,70 @@ static int hp_wmi_resume_handler(struct device *device)
870 rfkill_set_states(wwan_rfkill, 890 rfkill_set_states(wwan_rfkill,
871 hp_wmi_get_sw_state(HPWMI_WWAN), 891 hp_wmi_get_sw_state(HPWMI_WWAN),
872 hp_wmi_get_hw_state(HPWMI_WWAN)); 892 hp_wmi_get_hw_state(HPWMI_WWAN));
893 if (gps_rfkill)
894 rfkill_set_states(gps_rfkill,
895 hp_wmi_get_sw_state(HPWMI_GPS),
896 hp_wmi_get_hw_state(HPWMI_GPS));
873 897
874 return 0; 898 return 0;
875} 899}
876 900
901static const struct dev_pm_ops hp_wmi_pm_ops = {
902 .resume = hp_wmi_resume_handler,
903 .restore = hp_wmi_resume_handler,
904};
905
906static struct platform_driver hp_wmi_driver = {
907 .driver = {
908 .name = "hp-wmi",
909 .owner = THIS_MODULE,
910 .pm = &hp_wmi_pm_ops,
911 },
912 .remove = __exit_p(hp_wmi_bios_remove),
913};
914
877static int __init hp_wmi_init(void) 915static int __init hp_wmi_init(void)
878{ 916{
879 int err; 917 int err;
880 int event_capable = wmi_has_guid(HPWMI_EVENT_GUID); 918 int event_capable = wmi_has_guid(HPWMI_EVENT_GUID);
881 int bios_capable = wmi_has_guid(HPWMI_BIOS_GUID); 919 int bios_capable = wmi_has_guid(HPWMI_BIOS_GUID);
882 920
921 if (!bios_capable && !event_capable)
922 return -ENODEV;
923
883 if (event_capable) { 924 if (event_capable) {
884 err = hp_wmi_input_setup(); 925 err = hp_wmi_input_setup();
885 if (err) 926 if (err)
886 return err; 927 return err;
928
929 //Enable magic for hotkeys that run on the SMBus
930 ec_write(0xe6,0x6e);
887 } 931 }
888 932
889 if (bios_capable) { 933 if (bios_capable) {
890 err = platform_driver_register(&hp_wmi_driver); 934 hp_wmi_platform_dev =
891 if (err) 935 platform_device_register_simple("hp-wmi", -1, NULL, 0);
892 goto err_driver_reg; 936 if (IS_ERR(hp_wmi_platform_dev)) {
893 hp_wmi_platform_dev = platform_device_alloc("hp-wmi", -1); 937 err = PTR_ERR(hp_wmi_platform_dev);
894 if (!hp_wmi_platform_dev) { 938 goto err_destroy_input;
895 err = -ENOMEM;
896 goto err_device_alloc;
897 } 939 }
898 err = platform_device_add(hp_wmi_platform_dev); 940
941 err = platform_driver_probe(&hp_wmi_driver, hp_wmi_bios_setup);
899 if (err) 942 if (err)
900 goto err_device_add; 943 goto err_unregister_device;
901 } 944 }
902 945
903 if (!bios_capable && !event_capable)
904 return -ENODEV;
905
906 return 0; 946 return 0;
907 947
908err_device_add: 948err_unregister_device:
909 platform_device_put(hp_wmi_platform_dev); 949 platform_device_unregister(hp_wmi_platform_dev);
910err_device_alloc: 950err_destroy_input:
911 platform_driver_unregister(&hp_wmi_driver);
912err_driver_reg:
913 if (event_capable) 951 if (event_capable)
914 hp_wmi_input_destroy(); 952 hp_wmi_input_destroy();
915 953
916 return err; 954 return err;
917} 955}
956module_init(hp_wmi_init);
918 957
919static void __exit hp_wmi_exit(void) 958static void __exit hp_wmi_exit(void)
920{ 959{
@@ -926,6 +965,4 @@ static void __exit hp_wmi_exit(void)
926 platform_driver_unregister(&hp_wmi_driver); 965 platform_driver_unregister(&hp_wmi_driver);
927 } 966 }
928} 967}
929
930module_init(hp_wmi_init);
931module_exit(hp_wmi_exit); 968module_exit(hp_wmi_exit);
diff --git a/drivers/platform/x86/msi-laptop.c b/drivers/platform/x86/msi-laptop.c
index 2111dbb7e1e3..6b2293875672 100644
--- a/drivers/platform/x86/msi-laptop.c
+++ b/drivers/platform/x86/msi-laptop.c
@@ -82,8 +82,19 @@
82#define MSI_STANDARD_EC_SCM_LOAD_ADDRESS 0x2d 82#define MSI_STANDARD_EC_SCM_LOAD_ADDRESS 0x2d
83#define MSI_STANDARD_EC_SCM_LOAD_MASK (1 << 0) 83#define MSI_STANDARD_EC_SCM_LOAD_MASK (1 << 0)
84 84
85#define MSI_STANDARD_EC_TOUCHPAD_ADDRESS 0xe4 85#define MSI_STANDARD_EC_FUNCTIONS_ADDRESS 0xe4
86/* Power LED is orange - Turbo mode */
87#define MSI_STANDARD_EC_TURBO_MASK (1 << 1)
88/* Power LED is green - ECO mode */
89#define MSI_STANDARD_EC_ECO_MASK (1 << 3)
90/* Touchpad is turned on */
86#define MSI_STANDARD_EC_TOUCHPAD_MASK (1 << 4) 91#define MSI_STANDARD_EC_TOUCHPAD_MASK (1 << 4)
92/* If this bit != bit 1, turbo mode can't be toggled */
93#define MSI_STANDARD_EC_TURBO_COOLDOWN_MASK (1 << 7)
94
95#define MSI_STANDARD_EC_FAN_ADDRESS 0x33
96/* If zero, fan rotates at maximal speed */
97#define MSI_STANDARD_EC_AUTOFAN_MASK (1 << 0)
87 98
88#ifdef CONFIG_PM_SLEEP 99#ifdef CONFIG_PM_SLEEP
89static int msi_laptop_resume(struct device *device); 100static int msi_laptop_resume(struct device *device);
@@ -108,23 +119,38 @@ static const struct key_entry msi_laptop_keymap[] = {
108 119
109static struct input_dev *msi_laptop_input_dev; 120static struct input_dev *msi_laptop_input_dev;
110 121
111static bool old_ec_model;
112static int wlan_s, bluetooth_s, threeg_s; 122static int wlan_s, bluetooth_s, threeg_s;
113static int threeg_exists; 123static int threeg_exists;
114
115/* Some MSI 3G netbook only have one fn key to control Wlan/Bluetooth/3G,
116 * those netbook will load the SCM (windows app) to disable the original
117 * Wlan/Bluetooth control by BIOS when user press fn key, then control
118 * Wlan/Bluetooth/3G by SCM (software control by OS). Without SCM, user
119 * cann't on/off 3G module on those 3G netbook.
120 * On Linux, msi-laptop driver will do the same thing to disable the
121 * original BIOS control, then might need use HAL or other userland
122 * application to do the software control that simulate with SCM.
123 * e.g. MSI N034 netbook
124 */
125static bool load_scm_model;
126static struct rfkill *rfk_wlan, *rfk_bluetooth, *rfk_threeg; 124static struct rfkill *rfk_wlan, *rfk_bluetooth, *rfk_threeg;
127 125
126/* MSI laptop quirks */
127struct quirk_entry {
128 bool old_ec_model;
129
130 /* Some MSI 3G netbook only have one fn key to control
131 * Wlan/Bluetooth/3G, those netbook will load the SCM (windows app) to
132 * disable the original Wlan/Bluetooth control by BIOS when user press
133 * fn key, then control Wlan/Bluetooth/3G by SCM (software control by
134 * OS). Without SCM, user cann't on/off 3G module on those 3G netbook.
135 * On Linux, msi-laptop driver will do the same thing to disable the
136 * original BIOS control, then might need use HAL or other userland
137 * application to do the software control that simulate with SCM.
138 * e.g. MSI N034 netbook
139 */
140 bool load_scm_model;
141
142 /* Some MSI laptops need delay before reading from EC */
143 bool ec_delay;
144
145 /* Some MSI Wind netbooks (e.g. MSI Wind U100) need loading SCM to get
146 * some features working (e.g. ECO mode), but we cannot change
147 * Wlan/Bluetooth state in software and we can only read its state.
148 */
149 bool ec_read_only;
150};
151
152static struct quirk_entry *quirks;
153
128/* Hardware access */ 154/* Hardware access */
129 155
130static int set_lcd_level(int level) 156static int set_lcd_level(int level)
@@ -195,10 +221,13 @@ static ssize_t set_device_state(const char *buf, size_t count, u8 mask)
195 if (sscanf(buf, "%i", &status) != 1 || (status < 0 || status > 1)) 221 if (sscanf(buf, "%i", &status) != 1 || (status < 0 || status > 1))
196 return -EINVAL; 222 return -EINVAL;
197 223
224 if (quirks->ec_read_only)
225 return -EOPNOTSUPP;
226
198 /* read current device state */ 227 /* read current device state */
199 result = ec_read(MSI_STANDARD_EC_COMMAND_ADDRESS, &rdata); 228 result = ec_read(MSI_STANDARD_EC_COMMAND_ADDRESS, &rdata);
200 if (result < 0) 229 if (result < 0)
201 return -EINVAL; 230 return result;
202 231
203 if (!!(rdata & mask) != status) { 232 if (!!(rdata & mask) != status) {
204 /* reverse device bit */ 233 /* reverse device bit */
@@ -209,7 +238,7 @@ static ssize_t set_device_state(const char *buf, size_t count, u8 mask)
209 238
210 result = ec_write(MSI_STANDARD_EC_COMMAND_ADDRESS, wdata); 239 result = ec_write(MSI_STANDARD_EC_COMMAND_ADDRESS, wdata);
211 if (result < 0) 240 if (result < 0)
212 return -EINVAL; 241 return result;
213 } 242 }
214 243
215 return count; 244 return count;
@@ -222,7 +251,7 @@ static int get_wireless_state(int *wlan, int *bluetooth)
222 251
223 result = ec_transaction(MSI_EC_COMMAND_WIRELESS, &wdata, 1, &rdata, 1); 252 result = ec_transaction(MSI_EC_COMMAND_WIRELESS, &wdata, 1, &rdata, 1);
224 if (result < 0) 253 if (result < 0)
225 return -1; 254 return result;
226 255
227 if (wlan) 256 if (wlan)
228 *wlan = !!(rdata & 8); 257 *wlan = !!(rdata & 8);
@@ -240,7 +269,7 @@ static int get_wireless_state_ec_standard(void)
240 269
241 result = ec_read(MSI_STANDARD_EC_COMMAND_ADDRESS, &rdata); 270 result = ec_read(MSI_STANDARD_EC_COMMAND_ADDRESS, &rdata);
242 if (result < 0) 271 if (result < 0)
243 return -1; 272 return result;
244 273
245 wlan_s = !!(rdata & MSI_STANDARD_EC_WLAN_MASK); 274 wlan_s = !!(rdata & MSI_STANDARD_EC_WLAN_MASK);
246 275
@@ -258,7 +287,7 @@ static int get_threeg_exists(void)
258 287
259 result = ec_read(MSI_STANDARD_EC_DEVICES_EXISTS_ADDRESS, &rdata); 288 result = ec_read(MSI_STANDARD_EC_DEVICES_EXISTS_ADDRESS, &rdata);
260 if (result < 0) 289 if (result < 0)
261 return -1; 290 return result;
262 291
263 threeg_exists = !!(rdata & MSI_STANDARD_EC_3G_MASK); 292 threeg_exists = !!(rdata & MSI_STANDARD_EC_3G_MASK);
264 293
@@ -291,9 +320,9 @@ static ssize_t show_wlan(struct device *dev,
291 struct device_attribute *attr, char *buf) 320 struct device_attribute *attr, char *buf)
292{ 321{
293 322
294 int ret, enabled; 323 int ret, enabled = 0;
295 324
296 if (old_ec_model) { 325 if (quirks->old_ec_model) {
297 ret = get_wireless_state(&enabled, NULL); 326 ret = get_wireless_state(&enabled, NULL);
298 } else { 327 } else {
299 ret = get_wireless_state_ec_standard(); 328 ret = get_wireless_state_ec_standard();
@@ -315,9 +344,9 @@ static ssize_t show_bluetooth(struct device *dev,
315 struct device_attribute *attr, char *buf) 344 struct device_attribute *attr, char *buf)
316{ 345{
317 346
318 int ret, enabled; 347 int ret, enabled = 0;
319 348
320 if (old_ec_model) { 349 if (quirks->old_ec_model) {
321 ret = get_wireless_state(NULL, &enabled); 350 ret = get_wireless_state(NULL, &enabled);
322 } else { 351 } else {
323 ret = get_wireless_state_ec_standard(); 352 ret = get_wireless_state_ec_standard();
@@ -342,8 +371,8 @@ static ssize_t show_threeg(struct device *dev,
342 int ret; 371 int ret;
343 372
344 /* old msi ec not support 3G */ 373 /* old msi ec not support 3G */
345 if (old_ec_model) 374 if (quirks->old_ec_model)
346 return -1; 375 return -ENODEV;
347 376
348 ret = get_wireless_state_ec_standard(); 377 ret = get_wireless_state_ec_standard();
349 if (ret < 0) 378 if (ret < 0)
@@ -417,18 +446,119 @@ static ssize_t store_auto_brightness(struct device *dev,
417 return count; 446 return count;
418} 447}
419 448
449static ssize_t show_touchpad(struct device *dev,
450 struct device_attribute *attr, char *buf)
451{
452
453 u8 rdata;
454 int result;
455
456 result = ec_read(MSI_STANDARD_EC_FUNCTIONS_ADDRESS, &rdata);
457 if (result < 0)
458 return result;
459
460 return sprintf(buf, "%i\n", !!(rdata & MSI_STANDARD_EC_TOUCHPAD_MASK));
461}
462
463static ssize_t show_turbo(struct device *dev,
464 struct device_attribute *attr, char *buf)
465{
466
467 u8 rdata;
468 int result;
469
470 result = ec_read(MSI_STANDARD_EC_FUNCTIONS_ADDRESS, &rdata);
471 if (result < 0)
472 return result;
473
474 return sprintf(buf, "%i\n", !!(rdata & MSI_STANDARD_EC_TURBO_MASK));
475}
476
477static ssize_t show_eco(struct device *dev,
478 struct device_attribute *attr, char *buf)
479{
480
481 u8 rdata;
482 int result;
483
484 result = ec_read(MSI_STANDARD_EC_FUNCTIONS_ADDRESS, &rdata);
485 if (result < 0)
486 return result;
487
488 return sprintf(buf, "%i\n", !!(rdata & MSI_STANDARD_EC_ECO_MASK));
489}
490
491static ssize_t show_turbo_cooldown(struct device *dev,
492 struct device_attribute *attr, char *buf)
493{
494
495 u8 rdata;
496 int result;
497
498 result = ec_read(MSI_STANDARD_EC_FUNCTIONS_ADDRESS, &rdata);
499 if (result < 0)
500 return result;
501
502 return sprintf(buf, "%i\n", (!!(rdata & MSI_STANDARD_EC_TURBO_MASK)) |
503 (!!(rdata & MSI_STANDARD_EC_TURBO_COOLDOWN_MASK) << 1));
504}
505
506static ssize_t show_auto_fan(struct device *dev,
507 struct device_attribute *attr, char *buf)
508{
509
510 u8 rdata;
511 int result;
512
513 result = ec_read(MSI_STANDARD_EC_FAN_ADDRESS, &rdata);
514 if (result < 0)
515 return result;
516
517 return sprintf(buf, "%i\n", !!(rdata & MSI_STANDARD_EC_AUTOFAN_MASK));
518}
519
520static ssize_t store_auto_fan(struct device *dev,
521 struct device_attribute *attr, const char *buf, size_t count)
522{
523
524 int enable, result;
525
526 if (sscanf(buf, "%i", &enable) != 1 || (enable != (enable & 1)))
527 return -EINVAL;
528
529 result = ec_write(MSI_STANDARD_EC_FAN_ADDRESS, enable);
530 if (result < 0)
531 return result;
532
533 return count;
534}
535
420static DEVICE_ATTR(lcd_level, 0644, show_lcd_level, store_lcd_level); 536static DEVICE_ATTR(lcd_level, 0644, show_lcd_level, store_lcd_level);
421static DEVICE_ATTR(auto_brightness, 0644, show_auto_brightness, 537static DEVICE_ATTR(auto_brightness, 0644, show_auto_brightness,
422 store_auto_brightness); 538 store_auto_brightness);
423static DEVICE_ATTR(bluetooth, 0444, show_bluetooth, NULL); 539static DEVICE_ATTR(bluetooth, 0444, show_bluetooth, NULL);
424static DEVICE_ATTR(wlan, 0444, show_wlan, NULL); 540static DEVICE_ATTR(wlan, 0444, show_wlan, NULL);
425static DEVICE_ATTR(threeg, 0444, show_threeg, NULL); 541static DEVICE_ATTR(threeg, 0444, show_threeg, NULL);
542static DEVICE_ATTR(touchpad, 0444, show_touchpad, NULL);
543static DEVICE_ATTR(turbo_mode, 0444, show_turbo, NULL);
544static DEVICE_ATTR(eco_mode, 0444, show_eco, NULL);
545static DEVICE_ATTR(turbo_cooldown, 0444, show_turbo_cooldown, NULL);
546static DEVICE_ATTR(auto_fan, 0644, show_auto_fan, store_auto_fan);
426 547
427static struct attribute *msipf_attributes[] = { 548static struct attribute *msipf_attributes[] = {
428 &dev_attr_lcd_level.attr,
429 &dev_attr_auto_brightness.attr,
430 &dev_attr_bluetooth.attr, 549 &dev_attr_bluetooth.attr,
431 &dev_attr_wlan.attr, 550 &dev_attr_wlan.attr,
551 &dev_attr_touchpad.attr,
552 &dev_attr_turbo_mode.attr,
553 &dev_attr_eco_mode.attr,
554 &dev_attr_turbo_cooldown.attr,
555 &dev_attr_auto_fan.attr,
556 NULL
557};
558
559static struct attribute *msipf_old_attributes[] = {
560 &dev_attr_lcd_level.attr,
561 &dev_attr_auto_brightness.attr,
432 NULL 562 NULL
433}; 563};
434 564
@@ -436,6 +566,10 @@ static struct attribute_group msipf_attribute_group = {
436 .attrs = msipf_attributes 566 .attrs = msipf_attributes
437}; 567};
438 568
569static struct attribute_group msipf_old_attribute_group = {
570 .attrs = msipf_old_attributes
571};
572
439static struct platform_driver msipf_driver = { 573static struct platform_driver msipf_driver = {
440 .driver = { 574 .driver = {
441 .name = "msi-laptop-pf", 575 .name = "msi-laptop-pf",
@@ -448,9 +582,26 @@ static struct platform_device *msipf_device;
448 582
449/* Initialization */ 583/* Initialization */
450 584
451static int dmi_check_cb(const struct dmi_system_id *id) 585static struct quirk_entry quirk_old_ec_model = {
586 .old_ec_model = true,
587};
588
589static struct quirk_entry quirk_load_scm_model = {
590 .load_scm_model = true,
591 .ec_delay = true,
592};
593
594static struct quirk_entry quirk_load_scm_ro_model = {
595 .load_scm_model = true,
596 .ec_read_only = true,
597};
598
599static int dmi_check_cb(const struct dmi_system_id *dmi)
452{ 600{
453 pr_info("Identified laptop model '%s'\n", id->ident); 601 pr_info("Identified laptop model '%s'\n", dmi->ident);
602
603 quirks = dmi->driver_data;
604
454 return 1; 605 return 1;
455} 606}
456 607
@@ -464,6 +615,7 @@ static struct dmi_system_id __initdata msi_dmi_table[] = {
464 DMI_MATCH(DMI_CHASSIS_VENDOR, 615 DMI_MATCH(DMI_CHASSIS_VENDOR,
465 "MICRO-STAR INT'L CO.,LTD") 616 "MICRO-STAR INT'L CO.,LTD")
466 }, 617 },
618 .driver_data = &quirk_old_ec_model,
467 .callback = dmi_check_cb 619 .callback = dmi_check_cb
468 }, 620 },
469 { 621 {
@@ -474,6 +626,7 @@ static struct dmi_system_id __initdata msi_dmi_table[] = {
474 DMI_MATCH(DMI_PRODUCT_VERSION, "0581"), 626 DMI_MATCH(DMI_PRODUCT_VERSION, "0581"),
475 DMI_MATCH(DMI_BOARD_NAME, "MS-1058") 627 DMI_MATCH(DMI_BOARD_NAME, "MS-1058")
476 }, 628 },
629 .driver_data = &quirk_old_ec_model,
477 .callback = dmi_check_cb 630 .callback = dmi_check_cb
478 }, 631 },
479 { 632 {
@@ -484,6 +637,7 @@ static struct dmi_system_id __initdata msi_dmi_table[] = {
484 DMI_MATCH(DMI_BOARD_VENDOR, "MSI"), 637 DMI_MATCH(DMI_BOARD_VENDOR, "MSI"),
485 DMI_MATCH(DMI_BOARD_NAME, "MS-1412") 638 DMI_MATCH(DMI_BOARD_NAME, "MS-1412")
486 }, 639 },
640 .driver_data = &quirk_old_ec_model,
487 .callback = dmi_check_cb 641 .callback = dmi_check_cb
488 }, 642 },
489 { 643 {
@@ -495,12 +649,9 @@ static struct dmi_system_id __initdata msi_dmi_table[] = {
495 DMI_MATCH(DMI_CHASSIS_VENDOR, 649 DMI_MATCH(DMI_CHASSIS_VENDOR,
496 "MICRO-STAR INT'L CO.,LTD") 650 "MICRO-STAR INT'L CO.,LTD")
497 }, 651 },
652 .driver_data = &quirk_old_ec_model,
498 .callback = dmi_check_cb 653 .callback = dmi_check_cb
499 }, 654 },
500 { }
501};
502
503static struct dmi_system_id __initdata msi_load_scm_models_dmi_table[] = {
504 { 655 {
505 .ident = "MSI N034", 656 .ident = "MSI N034",
506 .matches = { 657 .matches = {
@@ -510,6 +661,7 @@ static struct dmi_system_id __initdata msi_load_scm_models_dmi_table[] = {
510 DMI_MATCH(DMI_CHASSIS_VENDOR, 661 DMI_MATCH(DMI_CHASSIS_VENDOR,
511 "MICRO-STAR INTERNATIONAL CO., LTD") 662 "MICRO-STAR INTERNATIONAL CO., LTD")
512 }, 663 },
664 .driver_data = &quirk_load_scm_model,
513 .callback = dmi_check_cb 665 .callback = dmi_check_cb
514 }, 666 },
515 { 667 {
@@ -521,6 +673,7 @@ static struct dmi_system_id __initdata msi_load_scm_models_dmi_table[] = {
521 DMI_MATCH(DMI_CHASSIS_VENDOR, 673 DMI_MATCH(DMI_CHASSIS_VENDOR,
522 "MICRO-STAR INTERNATIONAL CO., LTD") 674 "MICRO-STAR INTERNATIONAL CO., LTD")
523 }, 675 },
676 .driver_data = &quirk_load_scm_model,
524 .callback = dmi_check_cb 677 .callback = dmi_check_cb
525 }, 678 },
526 { 679 {
@@ -530,6 +683,7 @@ static struct dmi_system_id __initdata msi_load_scm_models_dmi_table[] = {
530 "MICRO-STAR INTERNATIONAL CO., LTD"), 683 "MICRO-STAR INTERNATIONAL CO., LTD"),
531 DMI_MATCH(DMI_PRODUCT_NAME, "MS-N014"), 684 DMI_MATCH(DMI_PRODUCT_NAME, "MS-N014"),
532 }, 685 },
686 .driver_data = &quirk_load_scm_model,
533 .callback = dmi_check_cb 687 .callback = dmi_check_cb
534 }, 688 },
535 { 689 {
@@ -539,6 +693,7 @@ static struct dmi_system_id __initdata msi_load_scm_models_dmi_table[] = {
539 "Micro-Star International"), 693 "Micro-Star International"),
540 DMI_MATCH(DMI_PRODUCT_NAME, "CR620"), 694 DMI_MATCH(DMI_PRODUCT_NAME, "CR620"),
541 }, 695 },
696 .driver_data = &quirk_load_scm_model,
542 .callback = dmi_check_cb 697 .callback = dmi_check_cb
543 }, 698 },
544 { 699 {
@@ -548,6 +703,17 @@ static struct dmi_system_id __initdata msi_load_scm_models_dmi_table[] = {
548 "Micro-Star International Co., Ltd."), 703 "Micro-Star International Co., Ltd."),
549 DMI_MATCH(DMI_PRODUCT_NAME, "U270 series"), 704 DMI_MATCH(DMI_PRODUCT_NAME, "U270 series"),
550 }, 705 },
706 .driver_data = &quirk_load_scm_model,
707 .callback = dmi_check_cb
708 },
709 {
710 .ident = "MSI U90/U100",
711 .matches = {
712 DMI_MATCH(DMI_SYS_VENDOR,
713 "MICRO-STAR INTERNATIONAL CO., LTD"),
714 DMI_MATCH(DMI_PRODUCT_NAME, "U90/U100"),
715 },
716 .driver_data = &quirk_load_scm_ro_model,
551 .callback = dmi_check_cb 717 .callback = dmi_check_cb
552 }, 718 },
553 { } 719 { }
@@ -560,32 +726,26 @@ static int rfkill_bluetooth_set(void *data, bool blocked)
560 * blocked == false is on 726 * blocked == false is on
561 * blocked == true is off 727 * blocked == true is off
562 */ 728 */
563 if (blocked) 729 int result = set_device_state(blocked ? "0" : "1", 0,
564 set_device_state("0", 0, MSI_STANDARD_EC_BLUETOOTH_MASK); 730 MSI_STANDARD_EC_BLUETOOTH_MASK);
565 else
566 set_device_state("1", 0, MSI_STANDARD_EC_BLUETOOTH_MASK);
567 731
568 return 0; 732 return min(result, 0);
569} 733}
570 734
571static int rfkill_wlan_set(void *data, bool blocked) 735static int rfkill_wlan_set(void *data, bool blocked)
572{ 736{
573 if (blocked) 737 int result = set_device_state(blocked ? "0" : "1", 0,
574 set_device_state("0", 0, MSI_STANDARD_EC_WLAN_MASK); 738 MSI_STANDARD_EC_WLAN_MASK);
575 else
576 set_device_state("1", 0, MSI_STANDARD_EC_WLAN_MASK);
577 739
578 return 0; 740 return min(result, 0);
579} 741}
580 742
581static int rfkill_threeg_set(void *data, bool blocked) 743static int rfkill_threeg_set(void *data, bool blocked)
582{ 744{
583 if (blocked) 745 int result = set_device_state(blocked ? "0" : "1", 0,
584 set_device_state("0", 0, MSI_STANDARD_EC_3G_MASK); 746 MSI_STANDARD_EC_3G_MASK);
585 else
586 set_device_state("1", 0, MSI_STANDARD_EC_3G_MASK);
587 747
588 return 0; 748 return min(result, 0);
589} 749}
590 750
591static const struct rfkill_ops rfkill_bluetooth_ops = { 751static const struct rfkill_ops rfkill_bluetooth_ops = {
@@ -618,25 +778,34 @@ static void rfkill_cleanup(void)
618 } 778 }
619} 779}
620 780
781static bool msi_rfkill_set_state(struct rfkill *rfkill, bool blocked)
782{
783 if (quirks->ec_read_only)
784 return rfkill_set_hw_state(rfkill, blocked);
785 else
786 return rfkill_set_sw_state(rfkill, blocked);
787}
788
621static void msi_update_rfkill(struct work_struct *ignored) 789static void msi_update_rfkill(struct work_struct *ignored)
622{ 790{
623 get_wireless_state_ec_standard(); 791 get_wireless_state_ec_standard();
624 792
625 if (rfk_wlan) 793 if (rfk_wlan)
626 rfkill_set_sw_state(rfk_wlan, !wlan_s); 794 msi_rfkill_set_state(rfk_wlan, !wlan_s);
627 if (rfk_bluetooth) 795 if (rfk_bluetooth)
628 rfkill_set_sw_state(rfk_bluetooth, !bluetooth_s); 796 msi_rfkill_set_state(rfk_bluetooth, !bluetooth_s);
629 if (rfk_threeg) 797 if (rfk_threeg)
630 rfkill_set_sw_state(rfk_threeg, !threeg_s); 798 msi_rfkill_set_state(rfk_threeg, !threeg_s);
631} 799}
632static DECLARE_DELAYED_WORK(msi_rfkill_work, msi_update_rfkill); 800static DECLARE_DELAYED_WORK(msi_rfkill_dwork, msi_update_rfkill);
801static DECLARE_WORK(msi_rfkill_work, msi_update_rfkill);
633 802
634static void msi_send_touchpad_key(struct work_struct *ignored) 803static void msi_send_touchpad_key(struct work_struct *ignored)
635{ 804{
636 u8 rdata; 805 u8 rdata;
637 int result; 806 int result;
638 807
639 result = ec_read(MSI_STANDARD_EC_TOUCHPAD_ADDRESS, &rdata); 808 result = ec_read(MSI_STANDARD_EC_FUNCTIONS_ADDRESS, &rdata);
640 if (result < 0) 809 if (result < 0)
641 return; 810 return;
642 811
@@ -644,7 +813,8 @@ static void msi_send_touchpad_key(struct work_struct *ignored)
644 (rdata & MSI_STANDARD_EC_TOUCHPAD_MASK) ? 813 (rdata & MSI_STANDARD_EC_TOUCHPAD_MASK) ?
645 KEY_TOUCHPAD_ON : KEY_TOUCHPAD_OFF, 1, true); 814 KEY_TOUCHPAD_ON : KEY_TOUCHPAD_OFF, 1, true);
646} 815}
647static DECLARE_DELAYED_WORK(msi_touchpad_work, msi_send_touchpad_key); 816static DECLARE_DELAYED_WORK(msi_touchpad_dwork, msi_send_touchpad_key);
817static DECLARE_WORK(msi_touchpad_work, msi_send_touchpad_key);
648 818
649static bool msi_laptop_i8042_filter(unsigned char data, unsigned char str, 819static bool msi_laptop_i8042_filter(unsigned char data, unsigned char str,
650 struct serio *port) 820 struct serio *port)
@@ -662,14 +832,20 @@ static bool msi_laptop_i8042_filter(unsigned char data, unsigned char str,
662 extended = false; 832 extended = false;
663 switch (data) { 833 switch (data) {
664 case 0xE4: 834 case 0xE4:
665 schedule_delayed_work(&msi_touchpad_work, 835 if (quirks->ec_delay) {
666 round_jiffies_relative(0.5 * HZ)); 836 schedule_delayed_work(&msi_touchpad_dwork,
837 round_jiffies_relative(0.5 * HZ));
838 } else
839 schedule_work(&msi_touchpad_work);
667 break; 840 break;
668 case 0x54: 841 case 0x54:
669 case 0x62: 842 case 0x62:
670 case 0x76: 843 case 0x76:
671 schedule_delayed_work(&msi_rfkill_work, 844 if (quirks->ec_delay) {
672 round_jiffies_relative(0.5 * HZ)); 845 schedule_delayed_work(&msi_rfkill_dwork,
846 round_jiffies_relative(0.5 * HZ));
847 } else
848 schedule_work(&msi_rfkill_work);
673 break; 849 break;
674 } 850 }
675 } 851 }
@@ -736,8 +912,11 @@ static int rfkill_init(struct platform_device *sdev)
736 } 912 }
737 913
738 /* schedule to run rfkill state initial */ 914 /* schedule to run rfkill state initial */
739 schedule_delayed_work(&msi_rfkill_init, 915 if (quirks->ec_delay) {
740 round_jiffies_relative(1 * HZ)); 916 schedule_delayed_work(&msi_rfkill_init,
917 round_jiffies_relative(1 * HZ));
918 } else
919 schedule_work(&msi_rfkill_work);
741 920
742 return 0; 921 return 0;
743 922
@@ -761,7 +940,7 @@ static int msi_laptop_resume(struct device *device)
761 u8 data; 940 u8 data;
762 int result; 941 int result;
763 942
764 if (!load_scm_model) 943 if (!quirks->load_scm_model)
765 return 0; 944 return 0;
766 945
767 /* set load SCM to disable hardware control by fn key */ 946 /* set load SCM to disable hardware control by fn key */
@@ -819,13 +998,15 @@ static int __init load_scm_model_init(struct platform_device *sdev)
819 u8 data; 998 u8 data;
820 int result; 999 int result;
821 1000
822 /* allow userland write sysfs file */ 1001 if (!quirks->ec_read_only) {
823 dev_attr_bluetooth.store = store_bluetooth; 1002 /* allow userland write sysfs file */
824 dev_attr_wlan.store = store_wlan; 1003 dev_attr_bluetooth.store = store_bluetooth;
825 dev_attr_threeg.store = store_threeg; 1004 dev_attr_wlan.store = store_wlan;
826 dev_attr_bluetooth.attr.mode |= S_IWUSR; 1005 dev_attr_threeg.store = store_threeg;
827 dev_attr_wlan.attr.mode |= S_IWUSR; 1006 dev_attr_bluetooth.attr.mode |= S_IWUSR;
828 dev_attr_threeg.attr.mode |= S_IWUSR; 1007 dev_attr_wlan.attr.mode |= S_IWUSR;
1008 dev_attr_threeg.attr.mode |= S_IWUSR;
1009 }
829 1010
830 /* disable hardware control by fn key */ 1011 /* disable hardware control by fn key */
831 result = ec_read(MSI_STANDARD_EC_SCM_LOAD_ADDRESS, &data); 1012 result = ec_read(MSI_STANDARD_EC_SCM_LOAD_ADDRESS, &data);
@@ -874,21 +1055,22 @@ static int __init msi_init(void)
874 if (acpi_disabled) 1055 if (acpi_disabled)
875 return -ENODEV; 1056 return -ENODEV;
876 1057
877 if (force || dmi_check_system(msi_dmi_table)) 1058 dmi_check_system(msi_dmi_table);
878 old_ec_model = 1; 1059 if (!quirks)
1060 /* quirks may be NULL if no match in DMI table */
1061 quirks = &quirk_load_scm_model;
1062 if (force)
1063 quirks = &quirk_old_ec_model;
879 1064
880 if (!old_ec_model) 1065 if (!quirks->old_ec_model)
881 get_threeg_exists(); 1066 get_threeg_exists();
882 1067
883 if (!old_ec_model && dmi_check_system(msi_load_scm_models_dmi_table))
884 load_scm_model = 1;
885
886 if (auto_brightness < 0 || auto_brightness > 2) 1068 if (auto_brightness < 0 || auto_brightness > 2)
887 return -EINVAL; 1069 return -EINVAL;
888 1070
889 /* Register backlight stuff */ 1071 /* Register backlight stuff */
890 1072
891 if (acpi_video_backlight_support()) { 1073 if (!quirks->old_ec_model || acpi_video_backlight_support()) {
892 pr_info("Brightness ignored, must be controlled by ACPI video driver\n"); 1074 pr_info("Brightness ignored, must be controlled by ACPI video driver\n");
893 } else { 1075 } else {
894 struct backlight_properties props; 1076 struct backlight_properties props;
@@ -918,7 +1100,7 @@ static int __init msi_init(void)
918 if (ret) 1100 if (ret)
919 goto fail_platform_device1; 1101 goto fail_platform_device1;
920 1102
921 if (load_scm_model && (load_scm_model_init(msipf_device) < 0)) { 1103 if (quirks->load_scm_model && (load_scm_model_init(msipf_device) < 0)) {
922 ret = -EINVAL; 1104 ret = -EINVAL;
923 goto fail_platform_device1; 1105 goto fail_platform_device1;
924 } 1106 }
@@ -928,20 +1110,25 @@ static int __init msi_init(void)
928 if (ret) 1110 if (ret)
929 goto fail_platform_device2; 1111 goto fail_platform_device2;
930 1112
931 if (!old_ec_model) { 1113 if (!quirks->old_ec_model) {
932 if (threeg_exists) 1114 if (threeg_exists)
933 ret = device_create_file(&msipf_device->dev, 1115 ret = device_create_file(&msipf_device->dev,
934 &dev_attr_threeg); 1116 &dev_attr_threeg);
935 if (ret) 1117 if (ret)
936 goto fail_platform_device2; 1118 goto fail_platform_device2;
937 } 1119 } else {
1120 ret = sysfs_create_group(&msipf_device->dev.kobj,
1121 &msipf_old_attribute_group);
1122 if (ret)
1123 goto fail_platform_device2;
938 1124
939 /* Disable automatic brightness control by default because 1125 /* Disable automatic brightness control by default because
940 * this module was probably loaded to do brightness control in 1126 * this module was probably loaded to do brightness control in
941 * software. */ 1127 * software. */
942 1128
943 if (auto_brightness != 2) 1129 if (auto_brightness != 2)
944 set_auto_brightness(auto_brightness); 1130 set_auto_brightness(auto_brightness);
1131 }
945 1132
946 pr_info("driver " MSI_DRIVER_VERSION " successfully loaded\n"); 1133 pr_info("driver " MSI_DRIVER_VERSION " successfully loaded\n");
947 1134
@@ -949,9 +1136,10 @@ static int __init msi_init(void)
949 1136
950fail_platform_device2: 1137fail_platform_device2:
951 1138
952 if (load_scm_model) { 1139 if (quirks->load_scm_model) {
953 i8042_remove_filter(msi_laptop_i8042_filter); 1140 i8042_remove_filter(msi_laptop_i8042_filter);
954 cancel_delayed_work_sync(&msi_rfkill_work); 1141 cancel_delayed_work_sync(&msi_rfkill_dwork);
1142 cancel_work_sync(&msi_rfkill_work);
955 rfkill_cleanup(); 1143 rfkill_cleanup();
956 } 1144 }
957 platform_device_del(msipf_device); 1145 platform_device_del(msipf_device);
@@ -973,23 +1161,26 @@ fail_backlight:
973 1161
974static void __exit msi_cleanup(void) 1162static void __exit msi_cleanup(void)
975{ 1163{
976 if (load_scm_model) { 1164 if (quirks->load_scm_model) {
977 i8042_remove_filter(msi_laptop_i8042_filter); 1165 i8042_remove_filter(msi_laptop_i8042_filter);
978 msi_laptop_input_destroy(); 1166 msi_laptop_input_destroy();
979 cancel_delayed_work_sync(&msi_rfkill_work); 1167 cancel_delayed_work_sync(&msi_rfkill_dwork);
1168 cancel_work_sync(&msi_rfkill_work);
980 rfkill_cleanup(); 1169 rfkill_cleanup();
981 } 1170 }
982 1171
983 sysfs_remove_group(&msipf_device->dev.kobj, &msipf_attribute_group); 1172 sysfs_remove_group(&msipf_device->dev.kobj, &msipf_attribute_group);
984 if (!old_ec_model && threeg_exists) 1173 if (!quirks->old_ec_model && threeg_exists)
985 device_remove_file(&msipf_device->dev, &dev_attr_threeg); 1174 device_remove_file(&msipf_device->dev, &dev_attr_threeg);
986 platform_device_unregister(msipf_device); 1175 platform_device_unregister(msipf_device);
987 platform_driver_unregister(&msipf_driver); 1176 platform_driver_unregister(&msipf_driver);
988 backlight_device_unregister(msibl_device); 1177 backlight_device_unregister(msibl_device);
989 1178
990 /* Enable automatic brightness control again */ 1179 if (quirks->old_ec_model) {
991 if (auto_brightness != 2) 1180 /* Enable automatic brightness control again */
992 set_auto_brightness(1); 1181 if (auto_brightness != 2)
1182 set_auto_brightness(1);
1183 }
993 1184
994 pr_info("driver unloaded\n"); 1185 pr_info("driver unloaded\n");
995} 1186}
@@ -1011,3 +1202,4 @@ MODULE_ALIAS("dmi:*:svnMICRO-STARINTERNATIONAL*:pnMS-N051:*");
1011MODULE_ALIAS("dmi:*:svnMICRO-STARINTERNATIONAL*:pnMS-N014:*"); 1202MODULE_ALIAS("dmi:*:svnMICRO-STARINTERNATIONAL*:pnMS-N014:*");
1012MODULE_ALIAS("dmi:*:svnMicro-StarInternational*:pnCR620:*"); 1203MODULE_ALIAS("dmi:*:svnMicro-StarInternational*:pnCR620:*");
1013MODULE_ALIAS("dmi:*:svnMicro-StarInternational*:pnU270series:*"); 1204MODULE_ALIAS("dmi:*:svnMicro-StarInternational*:pnU270series:*");
1205MODULE_ALIAS("dmi:*:svnMICRO-STARINTERNATIONAL*:pnU90/U100:*");
diff --git a/drivers/platform/x86/msi-wmi.c b/drivers/platform/x86/msi-wmi.c
index 2264331bd48e..70222f265f68 100644
--- a/drivers/platform/x86/msi-wmi.c
+++ b/drivers/platform/x86/msi-wmi.c
@@ -34,29 +34,65 @@ MODULE_AUTHOR("Thomas Renninger <trenn@suse.de>");
34MODULE_DESCRIPTION("MSI laptop WMI hotkeys driver"); 34MODULE_DESCRIPTION("MSI laptop WMI hotkeys driver");
35MODULE_LICENSE("GPL"); 35MODULE_LICENSE("GPL");
36 36
37MODULE_ALIAS("wmi:551A1F84-FBDD-4125-91DB-3EA8F44F1D45");
38MODULE_ALIAS("wmi:B6F3EEF2-3D2F-49DC-9DE3-85BCE18C62F2");
39
40#define DRV_NAME "msi-wmi" 37#define DRV_NAME "msi-wmi"
41 38
42#define MSIWMI_BIOS_GUID "551A1F84-FBDD-4125-91DB-3EA8F44F1D45" 39#define MSIWMI_BIOS_GUID "551A1F84-FBDD-4125-91DB-3EA8F44F1D45"
43#define MSIWMI_EVENT_GUID "B6F3EEF2-3D2F-49DC-9DE3-85BCE18C62F2" 40#define MSIWMI_MSI_EVENT_GUID "B6F3EEF2-3D2F-49DC-9DE3-85BCE18C62F2"
44 41#define MSIWMI_WIND_EVENT_GUID "5B3CC38A-40D9-7245-8AE6-1145B751BE3F"
45#define SCANCODE_BASE 0xD0 42
46#define MSI_WMI_BRIGHTNESSUP SCANCODE_BASE 43MODULE_ALIAS("wmi:" MSIWMI_BIOS_GUID);
47#define MSI_WMI_BRIGHTNESSDOWN (SCANCODE_BASE + 1) 44MODULE_ALIAS("wmi:" MSIWMI_MSI_EVENT_GUID);
48#define MSI_WMI_VOLUMEUP (SCANCODE_BASE + 2) 45MODULE_ALIAS("wmi:" MSIWMI_WIND_EVENT_GUID);
49#define MSI_WMI_VOLUMEDOWN (SCANCODE_BASE + 3) 46
50#define MSI_WMI_MUTE (SCANCODE_BASE + 4) 47enum msi_scancodes {
48 /* Generic MSI keys (not present on MSI Wind) */
49 MSI_KEY_BRIGHTNESSUP = 0xD0,
50 MSI_KEY_BRIGHTNESSDOWN,
51 MSI_KEY_VOLUMEUP,
52 MSI_KEY_VOLUMEDOWN,
53 MSI_KEY_MUTE,
54 /* MSI Wind keys */
55 WIND_KEY_TOUCHPAD = 0x08, /* Fn+F3 touchpad toggle */
56 WIND_KEY_BLUETOOTH = 0x56, /* Fn+F11 Bluetooth toggle */
57 WIND_KEY_CAMERA, /* Fn+F6 webcam toggle */
58 WIND_KEY_WLAN = 0x5f, /* Fn+F11 Wi-Fi toggle */
59 WIND_KEY_TURBO, /* Fn+F10 turbo mode toggle */
60 WIND_KEY_ECO = 0x69, /* Fn+F10 ECO mode toggle */
61};
51static struct key_entry msi_wmi_keymap[] = { 62static struct key_entry msi_wmi_keymap[] = {
52 { KE_KEY, MSI_WMI_BRIGHTNESSUP, {KEY_BRIGHTNESSUP} }, 63 { KE_KEY, MSI_KEY_BRIGHTNESSUP, {KEY_BRIGHTNESSUP} },
53 { KE_KEY, MSI_WMI_BRIGHTNESSDOWN, {KEY_BRIGHTNESSDOWN} }, 64 { KE_KEY, MSI_KEY_BRIGHTNESSDOWN, {KEY_BRIGHTNESSDOWN} },
54 { KE_KEY, MSI_WMI_VOLUMEUP, {KEY_VOLUMEUP} }, 65 { KE_KEY, MSI_KEY_VOLUMEUP, {KEY_VOLUMEUP} },
55 { KE_KEY, MSI_WMI_VOLUMEDOWN, {KEY_VOLUMEDOWN} }, 66 { KE_KEY, MSI_KEY_VOLUMEDOWN, {KEY_VOLUMEDOWN} },
56 { KE_KEY, MSI_WMI_MUTE, {KEY_MUTE} }, 67 { KE_KEY, MSI_KEY_MUTE, {KEY_MUTE} },
57 { KE_END, 0} 68
69 /* These keys work without WMI. Ignore them to avoid double keycodes */
70 { KE_IGNORE, WIND_KEY_TOUCHPAD, {KEY_TOUCHPAD_TOGGLE} },
71 { KE_IGNORE, WIND_KEY_BLUETOOTH, {KEY_BLUETOOTH} },
72 { KE_IGNORE, WIND_KEY_CAMERA, {KEY_CAMERA} },
73 { KE_IGNORE, WIND_KEY_WLAN, {KEY_WLAN} },
74
75 /* These are unknown WMI events found on MSI Wind */
76 { KE_IGNORE, 0x00 },
77 { KE_IGNORE, 0x62 },
78 { KE_IGNORE, 0x63 },
79
80 /* These are MSI Wind keys that should be handled via WMI */
81 { KE_KEY, WIND_KEY_TURBO, {KEY_PROG1} },
82 { KE_KEY, WIND_KEY_ECO, {KEY_PROG2} },
83
84 { KE_END, 0 }
85};
86
87static ktime_t last_pressed;
88
89static const struct {
90 const char *guid;
91 bool quirk_last_pressed;
92} *event_wmi, event_wmis[] = {
93 { MSIWMI_MSI_EVENT_GUID, true },
94 { MSIWMI_WIND_EVENT_GUID, false },
58}; 95};
59static ktime_t last_pressed[ARRAY_SIZE(msi_wmi_keymap) - 1];
60 96
61static struct backlight_device *backlight; 97static struct backlight_device *backlight;
62 98
@@ -149,7 +185,6 @@ static void msi_wmi_notify(u32 value, void *context)
149 struct acpi_buffer response = { ACPI_ALLOCATE_BUFFER, NULL }; 185 struct acpi_buffer response = { ACPI_ALLOCATE_BUFFER, NULL };
150 static struct key_entry *key; 186 static struct key_entry *key;
151 union acpi_object *obj; 187 union acpi_object *obj;
152 ktime_t cur;
153 acpi_status status; 188 acpi_status status;
154 189
155 status = wmi_get_event_data(value, &response); 190 status = wmi_get_event_data(value, &response);
@@ -165,39 +200,67 @@ static void msi_wmi_notify(u32 value, void *context)
165 pr_debug("Eventcode: 0x%x\n", eventcode); 200 pr_debug("Eventcode: 0x%x\n", eventcode);
166 key = sparse_keymap_entry_from_scancode(msi_wmi_input_dev, 201 key = sparse_keymap_entry_from_scancode(msi_wmi_input_dev,
167 eventcode); 202 eventcode);
168 if (key) { 203 if (!key) {
169 ktime_t diff; 204 pr_info("Unknown key pressed - %x\n", eventcode);
170 cur = ktime_get_real(); 205 goto msi_wmi_notify_exit;
171 diff = ktime_sub(cur, last_pressed[key->code - 206 }
172 SCANCODE_BASE]); 207
173 /* Ignore event if the same event happened in a 50 ms 208 if (event_wmi->quirk_last_pressed) {
209 ktime_t cur = ktime_get_real();
210 ktime_t diff = ktime_sub(cur, last_pressed);
211 /* Ignore event if any event happened in a 50 ms
174 timeframe -> Key press may result in 10-20 GPEs */ 212 timeframe -> Key press may result in 10-20 GPEs */
175 if (ktime_to_us(diff) < 1000 * 50) { 213 if (ktime_to_us(diff) < 1000 * 50) {
176 pr_debug("Suppressed key event 0x%X - " 214 pr_debug("Suppressed key event 0x%X - "
177 "Last press was %lld us ago\n", 215 "Last press was %lld us ago\n",
178 key->code, ktime_to_us(diff)); 216 key->code, ktime_to_us(diff));
179 return; 217 goto msi_wmi_notify_exit;
180 }
181 last_pressed[key->code - SCANCODE_BASE] = cur;
182
183 if (key->type == KE_KEY &&
184 /* Brightness is served via acpi video driver */
185 (!acpi_video_backlight_support() ||
186 (key->code != MSI_WMI_BRIGHTNESSUP &&
187 key->code != MSI_WMI_BRIGHTNESSDOWN))) {
188 pr_debug("Send key: 0x%X - "
189 "Input layer keycode: %d\n",
190 key->code, key->keycode);
191 sparse_keymap_report_entry(msi_wmi_input_dev,
192 key, 1, true);
193 } 218 }
194 } else 219 last_pressed = cur;
195 pr_info("Unknown key pressed - %x\n", eventcode); 220 }
221
222 if (key->type == KE_KEY &&
223 /* Brightness is served via acpi video driver */
224 (backlight ||
225 (key->code != MSI_KEY_BRIGHTNESSUP &&
226 key->code != MSI_KEY_BRIGHTNESSDOWN))) {
227 pr_debug("Send key: 0x%X - Input layer keycode: %d\n",
228 key->code, key->keycode);
229 sparse_keymap_report_entry(msi_wmi_input_dev, key, 1,
230 true);
231 }
196 } else 232 } else
197 pr_info("Unknown event received\n"); 233 pr_info("Unknown event received\n");
234
235msi_wmi_notify_exit:
198 kfree(response.pointer); 236 kfree(response.pointer);
199} 237}
200 238
239static int __init msi_wmi_backlight_setup(void)
240{
241 int err;
242 struct backlight_properties props;
243
244 memset(&props, 0, sizeof(struct backlight_properties));
245 props.type = BACKLIGHT_PLATFORM;
246 props.max_brightness = ARRAY_SIZE(backlight_map) - 1;
247 backlight = backlight_device_register(DRV_NAME, NULL, NULL,
248 &msi_backlight_ops,
249 &props);
250 if (IS_ERR(backlight))
251 return PTR_ERR(backlight);
252
253 err = bl_get(NULL);
254 if (err < 0) {
255 backlight_device_unregister(backlight);
256 return err;
257 }
258
259 backlight->props.brightness = err;
260
261 return 0;
262}
263
201static int __init msi_wmi_input_setup(void) 264static int __init msi_wmi_input_setup(void)
202{ 265{
203 int err; 266 int err;
@@ -219,7 +282,7 @@ static int __init msi_wmi_input_setup(void)
219 if (err) 282 if (err)
220 goto err_free_keymap; 283 goto err_free_keymap;
221 284
222 memset(last_pressed, 0, sizeof(last_pressed)); 285 last_pressed = ktime_set(0, 0);
223 286
224 return 0; 287 return 0;
225 288
@@ -233,61 +296,66 @@ err_free_dev:
233static int __init msi_wmi_init(void) 296static int __init msi_wmi_init(void)
234{ 297{
235 int err; 298 int err;
299 int i;
236 300
237 if (!wmi_has_guid(MSIWMI_EVENT_GUID)) { 301 for (i = 0; i < ARRAY_SIZE(event_wmis); i++) {
238 pr_err("This machine doesn't have MSI-hotkeys through WMI\n"); 302 if (!wmi_has_guid(event_wmis[i].guid))
239 return -ENODEV; 303 continue;
240 }
241 err = wmi_install_notify_handler(MSIWMI_EVENT_GUID,
242 msi_wmi_notify, NULL);
243 if (ACPI_FAILURE(err))
244 return -EINVAL;
245 304
246 err = msi_wmi_input_setup(); 305 err = msi_wmi_input_setup();
247 if (err) 306 if (err) {
248 goto err_uninstall_notifier; 307 pr_err("Unable to setup input device\n");
249 308 return err;
250 if (!acpi_video_backlight_support()) { 309 }
251 struct backlight_properties props; 310
252 memset(&props, 0, sizeof(struct backlight_properties)); 311 err = wmi_install_notify_handler(event_wmis[i].guid,
253 props.type = BACKLIGHT_PLATFORM; 312 msi_wmi_notify, NULL);
254 props.max_brightness = ARRAY_SIZE(backlight_map) - 1; 313 if (ACPI_FAILURE(err)) {
255 backlight = backlight_device_register(DRV_NAME, NULL, NULL, 314 pr_err("Unable to setup WMI notify handler\n");
256 &msi_backlight_ops,
257 &props);
258 if (IS_ERR(backlight)) {
259 err = PTR_ERR(backlight);
260 goto err_free_input; 315 goto err_free_input;
261 } 316 }
262 317
263 err = bl_get(NULL); 318 pr_debug("Event handler installed\n");
264 if (err < 0) 319 event_wmi = &event_wmis[i];
265 goto err_free_backlight; 320 break;
321 }
266 322
267 backlight->props.brightness = err; 323 if (wmi_has_guid(MSIWMI_BIOS_GUID) && !acpi_video_backlight_support()) {
324 err = msi_wmi_backlight_setup();
325 if (err) {
326 pr_err("Unable to setup backlight device\n");
327 goto err_uninstall_handler;
328 }
329 pr_debug("Backlight device created\n");
330 }
331
332 if (!event_wmi && !backlight) {
333 pr_err("This machine doesn't have neither MSI-hotkeys nor backlight through WMI\n");
334 return -ENODEV;
268 } 335 }
269 pr_debug("Event handler installed\n");
270 336
271 return 0; 337 return 0;
272 338
273err_free_backlight: 339err_uninstall_handler:
274 backlight_device_unregister(backlight); 340 if (event_wmi)
341 wmi_remove_notify_handler(event_wmi->guid);
275err_free_input: 342err_free_input:
276 sparse_keymap_free(msi_wmi_input_dev); 343 if (event_wmi) {
277 input_unregister_device(msi_wmi_input_dev); 344 sparse_keymap_free(msi_wmi_input_dev);
278err_uninstall_notifier: 345 input_unregister_device(msi_wmi_input_dev);
279 wmi_remove_notify_handler(MSIWMI_EVENT_GUID); 346 }
280 return err; 347 return err;
281} 348}
282 349
283static void __exit msi_wmi_exit(void) 350static void __exit msi_wmi_exit(void)
284{ 351{
285 if (wmi_has_guid(MSIWMI_EVENT_GUID)) { 352 if (event_wmi) {
286 wmi_remove_notify_handler(MSIWMI_EVENT_GUID); 353 wmi_remove_notify_handler(event_wmi->guid);
287 sparse_keymap_free(msi_wmi_input_dev); 354 sparse_keymap_free(msi_wmi_input_dev);
288 input_unregister_device(msi_wmi_input_dev); 355 input_unregister_device(msi_wmi_input_dev);
289 backlight_device_unregister(backlight);
290 } 356 }
357 if (backlight)
358 backlight_device_unregister(backlight);
291} 359}
292 360
293module_init(msi_wmi_init); 361module_init(msi_wmi_init);
diff --git a/drivers/platform/x86/sony-laptop.c b/drivers/platform/x86/sony-laptop.c
index 8da21876a794..14d4dced1def 100644
--- a/drivers/platform/x86/sony-laptop.c
+++ b/drivers/platform/x86/sony-laptop.c
@@ -158,6 +158,11 @@ static void sony_nc_thermal_cleanup(struct platform_device *pd);
158static int sony_nc_lid_resume_setup(struct platform_device *pd); 158static int sony_nc_lid_resume_setup(struct platform_device *pd);
159static void sony_nc_lid_resume_cleanup(struct platform_device *pd); 159static void sony_nc_lid_resume_cleanup(struct platform_device *pd);
160 160
161static int sony_nc_gfx_switch_setup(struct platform_device *pd,
162 unsigned int handle);
163static void sony_nc_gfx_switch_cleanup(struct platform_device *pd);
164static int __sony_nc_gfx_switch_status_get(void);
165
161static int sony_nc_highspeed_charging_setup(struct platform_device *pd); 166static int sony_nc_highspeed_charging_setup(struct platform_device *pd);
162static void sony_nc_highspeed_charging_cleanup(struct platform_device *pd); 167static void sony_nc_highspeed_charging_cleanup(struct platform_device *pd);
163 168
@@ -1241,17 +1246,13 @@ static void sony_nc_notify(struct acpi_device *device, u32 event)
1241 /* Hybrid GFX switching */ 1246 /* Hybrid GFX switching */
1242 sony_call_snc_handle(handle, 0x0000, &result); 1247 sony_call_snc_handle(handle, 0x0000, &result);
1243 dprintk("GFX switch event received (reason: %s)\n", 1248 dprintk("GFX switch event received (reason: %s)\n",
1244 (result & 0x01) ? 1249 (result == 0x1) ? "switch change" :
1245 "switch change" : "unknown"); 1250 (result == 0x2) ? "output switch" :
1246 1251 (result == 0x3) ? "output switch" :
1247 /* verify the switch state 1252 "");
1248 * 1: discrete GFX
1249 * 0: integrated GFX
1250 */
1251 sony_call_snc_handle(handle, 0x0100, &result);
1252 1253
1253 ev_type = GFX_SWITCH; 1254 ev_type = GFX_SWITCH;
1254 real_ev = result & 0xff; 1255 real_ev = __sony_nc_gfx_switch_status_get();
1255 break; 1256 break;
1256 1257
1257 default: 1258 default:
@@ -1350,6 +1351,13 @@ static void sony_nc_function_setup(struct acpi_device *device,
1350 pr_err("couldn't set up thermal profile function (%d)\n", 1351 pr_err("couldn't set up thermal profile function (%d)\n",
1351 result); 1352 result);
1352 break; 1353 break;
1354 case 0x0128:
1355 case 0x0146:
1356 result = sony_nc_gfx_switch_setup(pf_device, handle);
1357 if (result)
1358 pr_err("couldn't set up GFX Switch status (%d)\n",
1359 result);
1360 break;
1353 case 0x0131: 1361 case 0x0131:
1354 result = sony_nc_highspeed_charging_setup(pf_device); 1362 result = sony_nc_highspeed_charging_setup(pf_device);
1355 if (result) 1363 if (result)
@@ -1365,6 +1373,8 @@ static void sony_nc_function_setup(struct acpi_device *device,
1365 break; 1373 break;
1366 case 0x0137: 1374 case 0x0137:
1367 case 0x0143: 1375 case 0x0143:
1376 case 0x014b:
1377 case 0x014c:
1368 result = sony_nc_kbd_backlight_setup(pf_device, handle); 1378 result = sony_nc_kbd_backlight_setup(pf_device, handle);
1369 if (result) 1379 if (result)
1370 pr_err("couldn't set up keyboard backlight function (%d)\n", 1380 pr_err("couldn't set up keyboard backlight function (%d)\n",
@@ -1414,6 +1424,10 @@ static void sony_nc_function_cleanup(struct platform_device *pd)
1414 case 0x0122: 1424 case 0x0122:
1415 sony_nc_thermal_cleanup(pd); 1425 sony_nc_thermal_cleanup(pd);
1416 break; 1426 break;
1427 case 0x0128:
1428 case 0x0146:
1429 sony_nc_gfx_switch_cleanup(pd);
1430 break;
1417 case 0x0131: 1431 case 0x0131:
1418 sony_nc_highspeed_charging_cleanup(pd); 1432 sony_nc_highspeed_charging_cleanup(pd);
1419 break; 1433 break;
@@ -1423,6 +1437,8 @@ static void sony_nc_function_cleanup(struct platform_device *pd)
1423 break; 1437 break;
1424 case 0x0137: 1438 case 0x0137:
1425 case 0x0143: 1439 case 0x0143:
1440 case 0x014b:
1441 case 0x014c:
1426 sony_nc_kbd_backlight_cleanup(pd); 1442 sony_nc_kbd_backlight_cleanup(pd);
1427 break; 1443 break;
1428 default: 1444 default:
@@ -1467,6 +1483,8 @@ static void sony_nc_function_resume(void)
1467 break; 1483 break;
1468 case 0x0137: 1484 case 0x0137:
1469 case 0x0143: 1485 case 0x0143:
1486 case 0x014b:
1487 case 0x014c:
1470 sony_nc_kbd_backlight_resume(); 1488 sony_nc_kbd_backlight_resume();
1471 break; 1489 break;
1472 default: 1490 default:
@@ -1534,7 +1552,7 @@ static int sony_nc_rfkill_set(void *data, bool blocked)
1534 int argument = sony_rfkill_address[(long) data] + 0x100; 1552 int argument = sony_rfkill_address[(long) data] + 0x100;
1535 1553
1536 if (!blocked) 1554 if (!blocked)
1537 argument |= 0x030000; 1555 argument |= 0x070000;
1538 1556
1539 return sony_call_snc_handle(sony_rfkill_handle, argument, &result); 1557 return sony_call_snc_handle(sony_rfkill_handle, argument, &result);
1540} 1558}
@@ -2333,7 +2351,7 @@ static int sony_nc_lid_resume_setup(struct platform_device *pd)
2333 return 0; 2351 return 0;
2334 2352
2335liderror: 2353liderror:
2336 for (; i > 0; i--) 2354 for (i--; i >= 0; i--)
2337 device_remove_file(&pd->dev, &lid_ctl->attrs[i]); 2355 device_remove_file(&pd->dev, &lid_ctl->attrs[i]);
2338 2356
2339 kfree(lid_ctl); 2357 kfree(lid_ctl);
@@ -2355,6 +2373,97 @@ static void sony_nc_lid_resume_cleanup(struct platform_device *pd)
2355 } 2373 }
2356} 2374}
2357 2375
2376/* GFX Switch position */
2377enum gfx_switch {
2378 SPEED,
2379 STAMINA,
2380 AUTO
2381};
2382struct snc_gfx_switch_control {
2383 struct device_attribute attr;
2384 unsigned int handle;
2385};
2386static struct snc_gfx_switch_control *gfxs_ctl;
2387
2388/* returns 0 for speed, 1 for stamina */
2389static int __sony_nc_gfx_switch_status_get(void)
2390{
2391 unsigned int result;
2392
2393 if (sony_call_snc_handle(gfxs_ctl->handle, 0x0100, &result))
2394 return -EIO;
2395
2396 switch (gfxs_ctl->handle) {
2397 case 0x0146:
2398 /* 1: discrete GFX (speed)
2399 * 0: integrated GFX (stamina)
2400 */
2401 return result & 0x1 ? SPEED : STAMINA;
2402 break;
2403 case 0x0128:
2404 /* it's a more elaborated bitmask, for now:
2405 * 2: integrated GFX (stamina)
2406 * 0: discrete GFX (speed)
2407 */
2408 dprintk("GFX Status: 0x%x\n", result);
2409 return result & 0x80 ? AUTO :
2410 result & 0x02 ? STAMINA : SPEED;
2411 break;
2412 }
2413 return -EINVAL;
2414}
2415
2416static ssize_t sony_nc_gfx_switch_status_show(struct device *dev,
2417 struct device_attribute *attr,
2418 char *buffer)
2419{
2420 int pos = __sony_nc_gfx_switch_status_get();
2421
2422 if (pos < 0)
2423 return pos;
2424
2425 return snprintf(buffer, PAGE_SIZE, "%s\n", pos ? "speed" : "stamina");
2426}
2427
2428static int sony_nc_gfx_switch_setup(struct platform_device *pd,
2429 unsigned int handle)
2430{
2431 unsigned int result;
2432
2433 gfxs_ctl = kzalloc(sizeof(struct snc_gfx_switch_control), GFP_KERNEL);
2434 if (!gfxs_ctl)
2435 return -ENOMEM;
2436
2437 gfxs_ctl->handle = handle;
2438
2439 sysfs_attr_init(&gfxs_ctl->attr.attr);
2440 gfxs_ctl->attr.attr.name = "gfx_switch_status";
2441 gfxs_ctl->attr.attr.mode = S_IRUGO;
2442 gfxs_ctl->attr.show = sony_nc_gfx_switch_status_show;
2443
2444 result = device_create_file(&pd->dev, &gfxs_ctl->attr);
2445 if (result)
2446 goto gfxerror;
2447
2448 return 0;
2449
2450gfxerror:
2451 kfree(gfxs_ctl);
2452 gfxs_ctl = NULL;
2453
2454 return result;
2455}
2456
2457static void sony_nc_gfx_switch_cleanup(struct platform_device *pd)
2458{
2459 if (gfxs_ctl) {
2460 device_remove_file(&pd->dev, &gfxs_ctl->attr);
2461
2462 kfree(gfxs_ctl);
2463 gfxs_ctl = NULL;
2464 }
2465}
2466
2358/* High speed charging function */ 2467/* High speed charging function */
2359static struct device_attribute *hsc_handle; 2468static struct device_attribute *hsc_handle;
2360 2469
@@ -2533,6 +2642,8 @@ static void sony_nc_backlight_ng_read_limits(int handle,
2533 lvl_table_len = 9; 2642 lvl_table_len = 9;
2534 break; 2643 break;
2535 case 0x143: 2644 case 0x143:
2645 case 0x14b:
2646 case 0x14c:
2536 lvl_table_len = 16; 2647 lvl_table_len = 16;
2537 break; 2648 break;
2538 } 2649 }
@@ -2584,6 +2695,18 @@ static void sony_nc_backlight_setup(void)
2584 sony_nc_backlight_ng_read_limits(0x143, &sony_bl_props); 2695 sony_nc_backlight_ng_read_limits(0x143, &sony_bl_props);
2585 max_brightness = sony_bl_props.maxlvl - sony_bl_props.offset; 2696 max_brightness = sony_bl_props.maxlvl - sony_bl_props.offset;
2586 2697
2698 } else if (sony_find_snc_handle(0x14b) >= 0) {
2699 ops = &sony_backlight_ng_ops;
2700 sony_bl_props.cmd_base = 0x3000;
2701 sony_nc_backlight_ng_read_limits(0x14b, &sony_bl_props);
2702 max_brightness = sony_bl_props.maxlvl - sony_bl_props.offset;
2703
2704 } else if (sony_find_snc_handle(0x14c) >= 0) {
2705 ops = &sony_backlight_ng_ops;
2706 sony_bl_props.cmd_base = 0x3000;
2707 sony_nc_backlight_ng_read_limits(0x14c, &sony_bl_props);
2708 max_brightness = sony_bl_props.maxlvl - sony_bl_props.offset;
2709
2587 } else if (ACPI_SUCCESS(acpi_get_handle(sony_nc_acpi_handle, "GBRT", 2710 } else if (ACPI_SUCCESS(acpi_get_handle(sony_nc_acpi_handle, "GBRT",
2588 &unused))) { 2711 &unused))) {
2589 ops = &sony_backlight_ops; 2712 ops = &sony_backlight_ops;
diff --git a/drivers/platform/x86/thinkpad_acpi.c b/drivers/platform/x86/thinkpad_acpi.c
index f4f8408f3b5b..9a907567f41e 100644
--- a/drivers/platform/x86/thinkpad_acpi.c
+++ b/drivers/platform/x86/thinkpad_acpi.c
@@ -209,9 +209,8 @@ enum tpacpi_hkey_event_t {
209 TP_HKEY_EV_ALARM_SENSOR_XHOT = 0x6022, /* sensor critically hot */ 209 TP_HKEY_EV_ALARM_SENSOR_XHOT = 0x6022, /* sensor critically hot */
210 TP_HKEY_EV_THM_TABLE_CHANGED = 0x6030, /* thermal table changed */ 210 TP_HKEY_EV_THM_TABLE_CHANGED = 0x6030, /* thermal table changed */
211 211
212 TP_HKEY_EV_UNK_6040 = 0x6040, /* Related to AC change? 212 /* AC-related events */
213 some sort of APM hint, 213 TP_HKEY_EV_AC_CHANGED = 0x6040, /* AC status changed */
214 W520 */
215 214
216 /* Misc */ 215 /* Misc */
217 TP_HKEY_EV_RFKILL_CHANGED = 0x7000, /* rfkill switch changed */ 216 TP_HKEY_EV_RFKILL_CHANGED = 0x7000, /* rfkill switch changed */
@@ -3629,6 +3628,12 @@ static bool hotkey_notify_6xxx(const u32 hkey,
3629 "a sensor reports something is extremely hot!\n"); 3628 "a sensor reports something is extremely hot!\n");
3630 /* recommended action: immediate sleep/hibernate */ 3629 /* recommended action: immediate sleep/hibernate */
3631 break; 3630 break;
3631 case TP_HKEY_EV_AC_CHANGED:
3632 /* X120e, X121e, X220, X220i, X220t, X230, T420, T420s, W520:
3633 * AC status changed; can be triggered by plugging or
3634 * unplugging AC adapter, docking or undocking. */
3635
3636 /* fallthrough */
3632 3637
3633 case TP_HKEY_EV_KEY_NUMLOCK: 3638 case TP_HKEY_EV_KEY_NUMLOCK:
3634 case TP_HKEY_EV_KEY_FN: 3639 case TP_HKEY_EV_KEY_FN:
@@ -8574,7 +8579,8 @@ static bool __pure __init tpacpi_is_valid_fw_id(const char* const s,
8574 return s && strlen(s) >= 8 && 8579 return s && strlen(s) >= 8 &&
8575 tpacpi_is_fw_digit(s[0]) && 8580 tpacpi_is_fw_digit(s[0]) &&
8576 tpacpi_is_fw_digit(s[1]) && 8581 tpacpi_is_fw_digit(s[1]) &&
8577 s[2] == t && s[3] == 'T' && 8582 s[2] == t &&
8583 (s[3] == 'T' || s[3] == 'N') &&
8578 tpacpi_is_fw_digit(s[4]) && 8584 tpacpi_is_fw_digit(s[4]) &&
8579 tpacpi_is_fw_digit(s[5]); 8585 tpacpi_is_fw_digit(s[5]);
8580} 8586}
@@ -8607,7 +8613,8 @@ static int __must_check __init get_thinkpad_model_data(
8607 return -ENOMEM; 8613 return -ENOMEM;
8608 8614
8609 /* Really ancient ThinkPad 240X will fail this, which is fine */ 8615 /* Really ancient ThinkPad 240X will fail this, which is fine */
8610 if (!tpacpi_is_valid_fw_id(tp->bios_version_str, 'E')) 8616 if (!(tpacpi_is_valid_fw_id(tp->bios_version_str, 'E') ||
8617 tpacpi_is_valid_fw_id(tp->bios_version_str, 'C')))
8611 return 0; 8618 return 0;
8612 8619
8613 tp->bios_model = tp->bios_version_str[0] 8620 tp->bios_model = tp->bios_version_str[0]