summaryrefslogtreecommitdiffstats
path: root/drivers/platform
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2016-07-26 20:23:08 -0400
committerLinus Torvalds <torvalds@linux-foundation.org>2016-07-26 20:23:08 -0400
commit27b79027bc112a63ad4004eb83c6acacae08a0de (patch)
treeabce98b7d4598c6c212954a84cb3b41b7c33ddf3 /drivers/platform
parentf7e68169941a26cb1ad764d53ef13721e6fe439a (diff)
parent332e081225fc2a657aa587c42943d5f5a7dae88b (diff)
Merge tag 'platform-drivers-x86-v4.8-1' of git://git.infradead.org/users/dvhart/linux-platform-drivers-x86
Pull x8 platform driver updates from Darren Hart: "Several new quirks and tweaks for new platforms to existing laptop drivers. A new ACPI virtual power button driver, similar to the intel-hid driver. A rework of the dell keymap, using a single sparse keymap for all machines. A few fixes and cleanups. Summary: intel-vbtn: - new driver for Intel Virtual Button intel_pmc_core: - Convert to DEFINE_DEBUGFS_ATTRIBUTE fujitsu-laptop: - Rework brightness of eco led asus-wmi: - Add quirk_no_rfkill_wapf4 for the Asus X456UA - Add quirk_no_rfkill_wapf4 for the Asus X456UF - Add quirk_no_rfkill for the Asus Z550MA - Add quirk_no_rfkill for the Asus U303LB - Add quirk_no_rfkill for the Asus N552VW - Create quirk for airplane_mode LED - Add ambient light sensor toggle key asus-wireless: - Toggle airplane mode LED intel_telemetry: - Remove Monitor MWAIT feature dependency intel-hid: - Remove duplicated acpi_remove_notify_handler fujitsu-laptop: - Add support for eco LED - Support touchpad toggle hotkey on Skylake-based models - Remove unused macros - Use module name in debug messages hp-wmi: - Fix wifi cannot be hard-unblocked toshiba_acpi: - Bump driver version and update copyright year - Remove the position sysfs entry - Add IIO interface for accelerometer axis data dell-wmi: - Add a WMI event code for display on/off - Generate one sparse keymap for all machines - Add information about other WMI event codes - Sort WMI event codes and update comments - Ignore WMI event code 0xe045" * tag 'platform-drivers-x86-v4.8-1' of git://git.infradead.org/users/dvhart/linux-platform-drivers-x86: (26 commits) intel-vbtn: new driver for Intel Virtual Button intel_pmc_core: Convert to DEFINE_DEBUGFS_ATTRIBUTE fujitsu-laptop: Rework brightness of eco led asus-wmi: Add quirk_no_rfkill_wapf4 for the Asus X456UA asus-wmi: Add quirk_no_rfkill_wapf4 for the Asus X456UF asus-wmi: Add quirk_no_rfkill for the Asus Z550MA asus-wmi: Add quirk_no_rfkill for the Asus U303LB asus-wmi: Add quirk_no_rfkill for the Asus N552VW asus-wmi: Create quirk for airplane_mode LED asus-wireless: Toggle airplane mode LED intel_telemetry: Remove Monitor MWAIT feature dependency intel-hid: Remove duplicated acpi_remove_notify_handler asus-wmi: Add ambient light sensor toggle key fujitsu-laptop: Add support for eco LED fujitsu-laptop: Support touchpad toggle hotkey on Skylake-based models fujitsu-laptop: Remove unused macros fujitsu-laptop: Use module name in debug messages hp-wmi: Fix wifi cannot be hard-unblocked toshiba_acpi: Bump driver version and update copyright year toshiba_acpi: Remove the position sysfs entry ...
Diffstat (limited to 'drivers/platform')
-rw-r--r--drivers/platform/x86/Kconfig15
-rw-r--r--drivers/platform/x86/Makefile1
-rw-r--r--drivers/platform/x86/asus-nb-wmi.c50
-rw-r--r--drivers/platform/x86/asus-wireless.c91
-rw-r--r--drivers/platform/x86/asus-wmi.c8
-rw-r--r--drivers/platform/x86/asus-wmi.h1
-rw-r--r--drivers/platform/x86/dell-wmi.c293
-rw-r--r--drivers/platform/x86/fujitsu-laptop.c81
-rw-r--r--drivers/platform/x86/hp-wmi.c7
-rw-r--r--drivers/platform/x86/intel-hid.c5
-rw-r--r--drivers/platform/x86/intel-vbtn.c188
-rw-r--r--drivers/platform/x86/intel_pmc_core.c45
-rw-r--r--drivers/platform/x86/intel_pmc_core.h3
-rw-r--r--drivers/platform/x86/intel_telemetry_debugfs.c2
-rw-r--r--drivers/platform/x86/intel_telemetry_pltdrv.c2
-rw-r--r--drivers/platform/x86/toshiba_acpi.c136
16 files changed, 717 insertions, 211 deletions
diff --git a/drivers/platform/x86/Kconfig b/drivers/platform/x86/Kconfig
index 3ec0025d19e7..81b8dcca8891 100644
--- a/drivers/platform/x86/Kconfig
+++ b/drivers/platform/x86/Kconfig
@@ -603,6 +603,8 @@ config ASUS_WIRELESS
603 tristate "Asus Wireless Radio Control Driver" 603 tristate "Asus Wireless Radio Control Driver"
604 depends on ACPI 604 depends on ACPI
605 depends on INPUT 605 depends on INPUT
606 select NEW_LEDS
607 select LEDS_CLASS
606 ---help--- 608 ---help---
607 The Asus Wireless Radio Control handles the airplane mode hotkey 609 The Asus Wireless Radio Control handles the airplane mode hotkey
608 present on some Asus laptops. 610 present on some Asus laptops.
@@ -668,6 +670,7 @@ config ACPI_TOSHIBA
668 depends on SERIO_I8042 || SERIO_I8042 = n 670 depends on SERIO_I8042 || SERIO_I8042 = n
669 depends on ACPI_VIDEO || ACPI_VIDEO = n 671 depends on ACPI_VIDEO || ACPI_VIDEO = n
670 depends on RFKILL || RFKILL = n 672 depends on RFKILL || RFKILL = n
673 depends on IIO
671 select INPUT_POLLDEV 674 select INPUT_POLLDEV
672 select INPUT_SPARSEKMAP 675 select INPUT_SPARSEKMAP
673 ---help--- 676 ---help---
@@ -770,6 +773,18 @@ config INTEL_HID_EVENT
770 To compile this driver as a module, choose M here: the module will 773 To compile this driver as a module, choose M here: the module will
771 be called intel_hid. 774 be called intel_hid.
772 775
776config INTEL_VBTN
777 tristate "INTEL VIRTUAL BUTTON"
778 depends on ACPI
779 depends on INPUT
780 select INPUT_SPARSEKMAP
781 help
782 This driver provides support for the Intel Virtual Button interface.
783 Some laptops require this driver for power button support.
784
785 To compile this driver as a module, choose M here: the module will
786 be called intel_vbtn.
787
773config INTEL_SCU_IPC 788config INTEL_SCU_IPC
774 bool "Intel SCU IPC Support" 789 bool "Intel SCU IPC Support"
775 depends on X86_INTEL_MID 790 depends on X86_INTEL_MID
diff --git a/drivers/platform/x86/Makefile b/drivers/platform/x86/Makefile
index 9b11b4073e03..2efa86d2a1a7 100644
--- a/drivers/platform/x86/Makefile
+++ b/drivers/platform/x86/Makefile
@@ -44,6 +44,7 @@ obj-$(CONFIG_TOSHIBA_BT_RFKILL) += toshiba_bluetooth.o
44obj-$(CONFIG_TOSHIBA_HAPS) += toshiba_haps.o 44obj-$(CONFIG_TOSHIBA_HAPS) += toshiba_haps.o
45obj-$(CONFIG_TOSHIBA_WMI) += toshiba-wmi.o 45obj-$(CONFIG_TOSHIBA_WMI) += toshiba-wmi.o
46obj-$(CONFIG_INTEL_HID_EVENT) += intel-hid.o 46obj-$(CONFIG_INTEL_HID_EVENT) += intel-hid.o
47obj-$(CONFIG_INTEL_VBTN) += intel-vbtn.o
47obj-$(CONFIG_INTEL_SCU_IPC) += intel_scu_ipc.o 48obj-$(CONFIG_INTEL_SCU_IPC) += intel_scu_ipc.o
48obj-$(CONFIG_INTEL_SCU_IPC_UTIL) += intel_scu_ipcutil.o 49obj-$(CONFIG_INTEL_SCU_IPC_UTIL) += intel_scu_ipcutil.o
49obj-$(CONFIG_INTEL_MFLD_THERMAL) += intel_mid_thermal.o 50obj-$(CONFIG_INTEL_MFLD_THERMAL) += intel_mid_thermal.o
diff --git a/drivers/platform/x86/asus-nb-wmi.c b/drivers/platform/x86/asus-nb-wmi.c
index 091ca7ada8fc..adecc1c555f0 100644
--- a/drivers/platform/x86/asus-nb-wmi.c
+++ b/drivers/platform/x86/asus-nb-wmi.c
@@ -78,6 +78,15 @@ static struct quirk_entry quirk_asus_x200ca = {
78 .wapf = 2, 78 .wapf = 2,
79}; 79};
80 80
81static struct quirk_entry quirk_no_rfkill = {
82 .no_rfkill = true,
83};
84
85static struct quirk_entry quirk_no_rfkill_wapf4 = {
86 .wapf = 4,
87 .no_rfkill = true,
88};
89
81static int dmi_matched(const struct dmi_system_id *dmi) 90static int dmi_matched(const struct dmi_system_id *dmi)
82{ 91{
83 quirks = dmi->driver_data; 92 quirks = dmi->driver_data;
@@ -133,7 +142,7 @@ static const struct dmi_system_id asus_quirks[] = {
133 DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."), 142 DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."),
134 DMI_MATCH(DMI_PRODUCT_NAME, "X456UA"), 143 DMI_MATCH(DMI_PRODUCT_NAME, "X456UA"),
135 }, 144 },
136 .driver_data = &quirk_asus_wapf4, 145 .driver_data = &quirk_no_rfkill_wapf4,
137 }, 146 },
138 { 147 {
139 .callback = dmi_matched, 148 .callback = dmi_matched,
@@ -142,7 +151,7 @@ static const struct dmi_system_id asus_quirks[] = {
142 DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."), 151 DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."),
143 DMI_MATCH(DMI_PRODUCT_NAME, "X456UF"), 152 DMI_MATCH(DMI_PRODUCT_NAME, "X456UF"),
144 }, 153 },
145 .driver_data = &quirk_asus_wapf4, 154 .driver_data = &quirk_no_rfkill_wapf4,
146 }, 155 },
147 { 156 {
148 .callback = dmi_matched, 157 .callback = dmi_matched,
@@ -306,6 +315,42 @@ static const struct dmi_system_id asus_quirks[] = {
306 }, 315 },
307 .driver_data = &quirk_asus_x200ca, 316 .driver_data = &quirk_asus_x200ca,
308 }, 317 },
318 {
319 .callback = dmi_matched,
320 .ident = "ASUSTeK COMPUTER INC. X555UB",
321 .matches = {
322 DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."),
323 DMI_MATCH(DMI_PRODUCT_NAME, "X555UB"),
324 },
325 .driver_data = &quirk_no_rfkill,
326 },
327 {
328 .callback = dmi_matched,
329 .ident = "ASUSTeK COMPUTER INC. N552VW",
330 .matches = {
331 DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."),
332 DMI_MATCH(DMI_PRODUCT_NAME, "N552VW"),
333 },
334 .driver_data = &quirk_no_rfkill,
335 },
336 {
337 .callback = dmi_matched,
338 .ident = "ASUSTeK COMPUTER INC. U303LB",
339 .matches = {
340 DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."),
341 DMI_MATCH(DMI_PRODUCT_NAME, "U303LB"),
342 },
343 .driver_data = &quirk_no_rfkill,
344 },
345 {
346 .callback = dmi_matched,
347 .ident = "ASUSTeK COMPUTER INC. Z550MA",
348 .matches = {
349 DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."),
350 DMI_MATCH(DMI_PRODUCT_NAME, "Z550MA"),
351 },
352 .driver_data = &quirk_no_rfkill,
353 },
309 {}, 354 {},
310}; 355};
311 356
@@ -356,6 +401,7 @@ static const struct key_entry asus_nb_wmi_keymap[] = {
356 { KE_KEY, 0x67, { KEY_SWITCHVIDEOMODE } }, /* SDSP LCD + CRT + TV */ 401 { KE_KEY, 0x67, { KEY_SWITCHVIDEOMODE } }, /* SDSP LCD + CRT + TV */
357 { KE_KEY, 0x6B, { KEY_TOUCHPAD_TOGGLE } }, 402 { KE_KEY, 0x6B, { KEY_TOUCHPAD_TOGGLE } },
358 { KE_IGNORE, 0x6E, }, /* Low Battery notification */ 403 { KE_IGNORE, 0x6E, }, /* Low Battery notification */
404 { KE_KEY, 0x7a, { KEY_ALS_TOGGLE } }, /* Ambient Light Sensor Toggle */
359 { KE_KEY, 0x7D, { KEY_BLUETOOTH } }, /* Bluetooth Enable */ 405 { KE_KEY, 0x7D, { KEY_BLUETOOTH } }, /* Bluetooth Enable */
360 { KE_KEY, 0x7E, { KEY_BLUETOOTH } }, /* Bluetooth Disable */ 406 { KE_KEY, 0x7E, { KEY_BLUETOOTH } }, /* Bluetooth Disable */
361 { KE_KEY, 0x82, { KEY_CAMERA } }, 407 { KE_KEY, 0x82, { KEY_CAMERA } },
diff --git a/drivers/platform/x86/asus-wireless.c b/drivers/platform/x86/asus-wireless.c
index 9ec721e26532..9f31bc1a47d0 100644
--- a/drivers/platform/x86/asus-wireless.c
+++ b/drivers/platform/x86/asus-wireless.c
@@ -15,11 +15,78 @@
15#include <linux/acpi.h> 15#include <linux/acpi.h>
16#include <linux/input.h> 16#include <linux/input.h>
17#include <linux/pci_ids.h> 17#include <linux/pci_ids.h>
18#include <linux/leds.h>
19
20#define ASUS_WIRELESS_LED_STATUS 0x2
21#define ASUS_WIRELESS_LED_OFF 0x4
22#define ASUS_WIRELESS_LED_ON 0x5
18 23
19struct asus_wireless_data { 24struct asus_wireless_data {
20 struct input_dev *idev; 25 struct input_dev *idev;
26 struct acpi_device *adev;
27 struct workqueue_struct *wq;
28 struct work_struct led_work;
29 struct led_classdev led;
30 int led_state;
21}; 31};
22 32
33static u64 asus_wireless_method(acpi_handle handle, const char *method,
34 int param)
35{
36 struct acpi_object_list p;
37 union acpi_object obj;
38 acpi_status s;
39 u64 ret;
40
41 acpi_handle_debug(handle, "Evaluating method %s, parameter %#x\n",
42 method, param);
43 obj.type = ACPI_TYPE_INTEGER;
44 obj.integer.value = param;
45 p.count = 1;
46 p.pointer = &obj;
47
48 s = acpi_evaluate_integer(handle, (acpi_string) method, &p, &ret);
49 if (ACPI_FAILURE(s))
50 acpi_handle_err(handle,
51 "Failed to eval method %s, param %#x (%d)\n",
52 method, param, s);
53 acpi_handle_debug(handle, "%s returned %#x\n", method, (uint) ret);
54 return ret;
55}
56
57static enum led_brightness led_state_get(struct led_classdev *led)
58{
59 struct asus_wireless_data *data;
60 int s;
61
62 data = container_of(led, struct asus_wireless_data, led);
63 s = asus_wireless_method(acpi_device_handle(data->adev), "HSWC",
64 ASUS_WIRELESS_LED_STATUS);
65 if (s == ASUS_WIRELESS_LED_ON)
66 return LED_FULL;
67 return LED_OFF;
68}
69
70static void led_state_update(struct work_struct *work)
71{
72 struct asus_wireless_data *data;
73
74 data = container_of(work, struct asus_wireless_data, led_work);
75 asus_wireless_method(acpi_device_handle(data->adev), "HSWC",
76 data->led_state);
77}
78
79static void led_state_set(struct led_classdev *led,
80 enum led_brightness value)
81{
82 struct asus_wireless_data *data;
83
84 data = container_of(led, struct asus_wireless_data, led);
85 data->led_state = value == LED_OFF ? ASUS_WIRELESS_LED_OFF :
86 ASUS_WIRELESS_LED_ON;
87 queue_work(data->wq, &data->led_work);
88}
89
23static void asus_wireless_notify(struct acpi_device *adev, u32 event) 90static void asus_wireless_notify(struct acpi_device *adev, u32 event)
24{ 91{
25 struct asus_wireless_data *data = acpi_driver_data(adev); 92 struct asus_wireless_data *data = acpi_driver_data(adev);
@@ -37,6 +104,7 @@ static void asus_wireless_notify(struct acpi_device *adev, u32 event)
37static int asus_wireless_add(struct acpi_device *adev) 104static int asus_wireless_add(struct acpi_device *adev)
38{ 105{
39 struct asus_wireless_data *data; 106 struct asus_wireless_data *data;
107 int err;
40 108
41 data = devm_kzalloc(&adev->dev, sizeof(*data), GFP_KERNEL); 109 data = devm_kzalloc(&adev->dev, sizeof(*data), GFP_KERNEL);
42 if (!data) 110 if (!data)
@@ -52,11 +120,32 @@ static int asus_wireless_add(struct acpi_device *adev)
52 data->idev->id.vendor = PCI_VENDOR_ID_ASUSTEK; 120 data->idev->id.vendor = PCI_VENDOR_ID_ASUSTEK;
53 set_bit(EV_KEY, data->idev->evbit); 121 set_bit(EV_KEY, data->idev->evbit);
54 set_bit(KEY_RFKILL, data->idev->keybit); 122 set_bit(KEY_RFKILL, data->idev->keybit);
55 return input_register_device(data->idev); 123 err = input_register_device(data->idev);
124 if (err)
125 return err;
126
127 data->adev = adev;
128 data->wq = create_singlethread_workqueue("asus_wireless_workqueue");
129 if (!data->wq)
130 return -ENOMEM;
131 INIT_WORK(&data->led_work, led_state_update);
132 data->led.name = "asus-wireless::airplane";
133 data->led.brightness_set = led_state_set;
134 data->led.brightness_get = led_state_get;
135 data->led.flags = LED_CORE_SUSPENDRESUME;
136 data->led.max_brightness = 1;
137 err = devm_led_classdev_register(&adev->dev, &data->led);
138 if (err)
139 destroy_workqueue(data->wq);
140 return err;
56} 141}
57 142
58static int asus_wireless_remove(struct acpi_device *adev) 143static int asus_wireless_remove(struct acpi_device *adev)
59{ 144{
145 struct asus_wireless_data *data = acpi_driver_data(adev);
146
147 if (data->wq)
148 destroy_workqueue(data->wq);
60 return 0; 149 return 0;
61} 150}
62 151
diff --git a/drivers/platform/x86/asus-wmi.c b/drivers/platform/x86/asus-wmi.c
index a26dca3640ea..7c093a0b78bb 100644
--- a/drivers/platform/x86/asus-wmi.c
+++ b/drivers/platform/x86/asus-wmi.c
@@ -2069,9 +2069,11 @@ static int asus_wmi_add(struct platform_device *pdev)
2069 if (err) 2069 if (err)
2070 goto fail_leds; 2070 goto fail_leds;
2071 2071
2072 err = asus_wmi_rfkill_init(asus); 2072 if (!asus->driver->quirks->no_rfkill) {
2073 if (err) 2073 err = asus_wmi_rfkill_init(asus);
2074 goto fail_rfkill; 2074 if (err)
2075 goto fail_rfkill;
2076 }
2075 2077
2076 /* Some Asus desktop boards export an acpi-video backlight interface, 2078 /* Some Asus desktop boards export an acpi-video backlight interface,
2077 stop this from showing up */ 2079 stop this from showing up */
diff --git a/drivers/platform/x86/asus-wmi.h b/drivers/platform/x86/asus-wmi.h
index 4da4c8bafe70..5de1df510ebd 100644
--- a/drivers/platform/x86/asus-wmi.h
+++ b/drivers/platform/x86/asus-wmi.h
@@ -38,6 +38,7 @@ struct key_entry;
38struct asus_wmi; 38struct asus_wmi;
39 39
40struct quirk_entry { 40struct quirk_entry {
41 bool no_rfkill;
41 bool hotplug_wireless; 42 bool hotplug_wireless;
42 bool scalar_panel_brightness; 43 bool scalar_panel_brightness;
43 bool store_backlight_power; 44 bool store_backlight_power;
diff --git a/drivers/platform/x86/dell-wmi.c b/drivers/platform/x86/dell-wmi.c
index 15c6f1191aec..d2bc092defd7 100644
--- a/drivers/platform/x86/dell-wmi.c
+++ b/drivers/platform/x86/dell-wmi.c
@@ -80,66 +80,115 @@ static const struct dmi_system_id dell_wmi_smbios_list[] __initconst = {
80}; 80};
81 81
82/* 82/*
83 * Keymap for WMI events of type 0x0000
84 *
83 * Certain keys are flagged as KE_IGNORE. All of these are either 85 * Certain keys are flagged as KE_IGNORE. All of these are either
84 * notifications (rather than requests for change) or are also sent 86 * notifications (rather than requests for change) or are also sent
85 * via the keyboard controller so should not be sent again. 87 * via the keyboard controller so should not be sent again.
86 */ 88 */
87 89static const struct key_entry dell_wmi_keymap_type_0000[] __initconst = {
88static const struct key_entry dell_wmi_legacy_keymap[] __initconst = {
89 { KE_IGNORE, 0x003a, { KEY_CAPSLOCK } }, 90 { KE_IGNORE, 0x003a, { KEY_CAPSLOCK } },
90 91
91 { KE_KEY, 0xe045, { KEY_PROG1 } }, 92 /* Key code is followed by brightness level */
92 { KE_KEY, 0xe009, { KEY_EJECTCD } }, 93 { KE_KEY, 0xe005, { KEY_BRIGHTNESSDOWN } },
93 94 { KE_KEY, 0xe006, { KEY_BRIGHTNESSUP } },
94 /* These also contain the brightness level at offset 6 */
95 { KE_KEY, 0xe006, { KEY_BRIGHTNESSUP } },
96 { KE_KEY, 0xe005, { KEY_BRIGHTNESSDOWN } },
97 95
98 /* Battery health status button */ 96 /* Battery health status button */
99 { KE_KEY, 0xe007, { KEY_BATTERY } }, 97 { KE_KEY, 0xe007, { KEY_BATTERY } },
100 98
101 /* Radio devices state change */ 99 /* Radio devices state change, key code is followed by other values */
102 { KE_IGNORE, 0xe008, { KEY_RFKILL } }, 100 { KE_IGNORE, 0xe008, { KEY_RFKILL } },
103 101
104 /* The next device is at offset 6, the active devices are at 102 { KE_KEY, 0xe009, { KEY_EJECTCD } },
105 offset 8 and the attached devices at offset 10 */
106 { KE_KEY, 0xe00b, { KEY_SWITCHVIDEOMODE } },
107 103
104 /* Key code is followed by: next, active and attached devices */
105 { KE_KEY, 0xe00b, { KEY_SWITCHVIDEOMODE } },
106
107 /* Key code is followed by keyboard illumination level */
108 { KE_IGNORE, 0xe00c, { KEY_KBDILLUMTOGGLE } }, 108 { KE_IGNORE, 0xe00c, { KEY_KBDILLUMTOGGLE } },
109 109
110 /* BIOS error detected */ 110 /* BIOS error detected */
111 { KE_IGNORE, 0xe00d, { KEY_RESERVED } }, 111 { KE_IGNORE, 0xe00d, { KEY_RESERVED } },
112 112
113 /* Unknown, defined in ACPI DSDT */
114 /* { KE_IGNORE, 0xe00e, { KEY_RESERVED } }, */
115
113 /* Wifi Catcher */ 116 /* Wifi Catcher */
114 { KE_KEY, 0xe011, {KEY_PROG2 } }, 117 { KE_KEY, 0xe011, { KEY_PROG2 } },
115 118
116 /* Ambient light sensor toggle */ 119 /* Ambient light sensor toggle */
117 { KE_IGNORE, 0xe013, { KEY_RESERVED } }, 120 { KE_IGNORE, 0xe013, { KEY_RESERVED } },
118 121
119 { KE_IGNORE, 0xe020, { KEY_MUTE } }, 122 { KE_IGNORE, 0xe020, { KEY_MUTE } },
120 123
124 /* Unknown, defined in ACPI DSDT */
125 /* { KE_IGNORE, 0xe023, { KEY_RESERVED } }, */
126
127 /* Untested, Dell Instant Launch key on Inspiron 7520 */
128 /* { KE_IGNORE, 0xe024, { KEY_RESERVED } }, */
129
121 /* Dell Instant Launch key */ 130 /* Dell Instant Launch key */
122 { KE_KEY, 0xe025, { KEY_PROG4 } }, 131 { KE_KEY, 0xe025, { KEY_PROG4 } },
123 { KE_KEY, 0xe029, { KEY_PROG4 } },
124 132
125 /* Audio panel key */ 133 /* Audio panel key */
126 { KE_IGNORE, 0xe026, { KEY_RESERVED } }, 134 { KE_IGNORE, 0xe026, { KEY_RESERVED } },
127 135
136 /* LCD Display On/Off Control key */
137 { KE_KEY, 0xe027, { KEY_DISPLAYTOGGLE } },
138
139 /* Untested, Multimedia key on Dell Vostro 3560 */
140 /* { KE_IGNORE, 0xe028, { KEY_RESERVED } }, */
141
142 /* Dell Instant Launch key */
143 { KE_KEY, 0xe029, { KEY_PROG4 } },
144
145 /* Untested, Windows Mobility Center button on Inspiron 7520 */
146 /* { KE_IGNORE, 0xe02a, { KEY_RESERVED } }, */
147
148 /* Unknown, defined in ACPI DSDT */
149 /* { KE_IGNORE, 0xe02b, { KEY_RESERVED } }, */
150
151 /* Untested, Dell Audio With Preset Switch button on Inspiron 7520 */
152 /* { KE_IGNORE, 0xe02c, { KEY_RESERVED } }, */
153
128 { KE_IGNORE, 0xe02e, { KEY_VOLUMEDOWN } }, 154 { KE_IGNORE, 0xe02e, { KEY_VOLUMEDOWN } },
129 { KE_IGNORE, 0xe030, { KEY_VOLUMEUP } }, 155 { KE_IGNORE, 0xe030, { KEY_VOLUMEUP } },
130 { KE_IGNORE, 0xe033, { KEY_KBDILLUMUP } }, 156 { KE_IGNORE, 0xe033, { KEY_KBDILLUMUP } },
131 { KE_IGNORE, 0xe034, { KEY_KBDILLUMDOWN } }, 157 { KE_IGNORE, 0xe034, { KEY_KBDILLUMDOWN } },
132 { KE_IGNORE, 0xe03a, { KEY_CAPSLOCK } }, 158 { KE_IGNORE, 0xe03a, { KEY_CAPSLOCK } },
159
160 /* NIC Link is Up */
161 { KE_IGNORE, 0xe043, { KEY_RESERVED } },
162
163 /* NIC Link is Down */
164 { KE_IGNORE, 0xe044, { KEY_RESERVED } },
165
166 /*
167 * This entry is very suspicious!
168 * Originally Matthew Garrett created this dell-wmi driver specially for
169 * "button with a picture of a battery" which has event code 0xe045.
170 * Later Mario Limonciello from Dell told us that event code 0xe045 is
171 * reported by Num Lock and should be ignored because key is send also
172 * by keyboard controller.
173 * So for now we will ignore this event to prevent potential double
174 * Num Lock key press.
175 */
133 { KE_IGNORE, 0xe045, { KEY_NUMLOCK } }, 176 { KE_IGNORE, 0xe045, { KEY_NUMLOCK } },
177
178 /* Scroll lock and also going to tablet mode on portable devices */
134 { KE_IGNORE, 0xe046, { KEY_SCROLLLOCK } }, 179 { KE_IGNORE, 0xe046, { KEY_SCROLLLOCK } },
180
181 /* Untested, going from tablet mode on portable devices */
182 /* { KE_IGNORE, 0xe047, { KEY_RESERVED } }, */
183
184 /* Dell Support Center key */
185 { KE_IGNORE, 0xe06e, { KEY_RESERVED } },
186
135 { KE_IGNORE, 0xe0f7, { KEY_MUTE } }, 187 { KE_IGNORE, 0xe0f7, { KEY_MUTE } },
136 { KE_IGNORE, 0xe0f8, { KEY_VOLUMEDOWN } }, 188 { KE_IGNORE, 0xe0f8, { KEY_VOLUMEDOWN } },
137 { KE_IGNORE, 0xe0f9, { KEY_VOLUMEUP } }, 189 { KE_IGNORE, 0xe0f9, { KEY_VOLUMEUP } },
138 { KE_END, 0 }
139}; 190};
140 191
141static bool dell_new_hk_type;
142
143struct dell_bios_keymap_entry { 192struct dell_bios_keymap_entry {
144 u16 scancode; 193 u16 scancode;
145 u16 keycode; 194 u16 keycode;
@@ -153,6 +202,7 @@ struct dell_bios_hotkey_table {
153 202
154struct dell_dmi_results { 203struct dell_dmi_results {
155 int err; 204 int err;
205 int keymap_size;
156 struct key_entry *keymap; 206 struct key_entry *keymap;
157}; 207};
158 208
@@ -201,10 +251,12 @@ static const u16 bios_to_linux_keycode[256] __initconst = {
201}; 251};
202 252
203/* 253/*
254 * Keymap for WMI events of type 0x0010
255 *
204 * These are applied if the 0xB2 DMI hotkey table is present and doesn't 256 * These are applied if the 0xB2 DMI hotkey table is present and doesn't
205 * override them. 257 * override them.
206 */ 258 */
207static const struct key_entry dell_wmi_extra_keymap[] __initconst = { 259static const struct key_entry dell_wmi_keymap_type_0010[] __initconst = {
208 /* Fn-lock */ 260 /* Fn-lock */
209 { KE_IGNORE, 0x151, { KEY_RESERVED } }, 261 { KE_IGNORE, 0x151, { KEY_RESERVED } },
210 262
@@ -224,21 +276,39 @@ static const struct key_entry dell_wmi_extra_keymap[] __initconst = {
224 { KE_IGNORE, 0x155, { KEY_RESERVED } }, 276 { KE_IGNORE, 0x155, { KEY_RESERVED } },
225}; 277};
226 278
279/*
280 * Keymap for WMI events of type 0x0011
281 */
282static const struct key_entry dell_wmi_keymap_type_0011[] __initconst = {
283 /* Battery unplugged */
284 { KE_IGNORE, 0xfff0, { KEY_RESERVED } },
285
286 /* Battery inserted */
287 { KE_IGNORE, 0xfff1, { KEY_RESERVED } },
288
289 /* Keyboard backlight level changed */
290 { KE_IGNORE, 0x01e1, { KEY_RESERVED } },
291 { KE_IGNORE, 0x02ea, { KEY_RESERVED } },
292 { KE_IGNORE, 0x02eb, { KEY_RESERVED } },
293 { KE_IGNORE, 0x02ec, { KEY_RESERVED } },
294 { KE_IGNORE, 0x02f6, { KEY_RESERVED } },
295};
296
227static struct input_dev *dell_wmi_input_dev; 297static struct input_dev *dell_wmi_input_dev;
228 298
229static void dell_wmi_process_key(int reported_key) 299static void dell_wmi_process_key(int type, int code)
230{ 300{
231 const struct key_entry *key; 301 const struct key_entry *key;
232 302
233 key = sparse_keymap_entry_from_scancode(dell_wmi_input_dev, 303 key = sparse_keymap_entry_from_scancode(dell_wmi_input_dev,
234 reported_key); 304 (type << 16) | code);
235 if (!key) { 305 if (!key) {
236 pr_info("Unknown key with scancode 0x%x pressed\n", 306 pr_info("Unknown key with type 0x%04x and code 0x%04x pressed\n",
237 reported_key); 307 type, code);
238 return; 308 return;
239 } 309 }
240 310
241 pr_debug("Key %x pressed\n", reported_key); 311 pr_debug("Key with type 0x%04x and code 0x%04x pressed\n", type, code);
242 312
243 /* Don't report brightness notifications that will also come via ACPI */ 313 /* Don't report brightness notifications that will also come via ACPI */
244 if ((key->keycode == KEY_BRIGHTNESSUP || 314 if ((key->keycode == KEY_BRIGHTNESSUP ||
@@ -246,7 +316,7 @@ static void dell_wmi_process_key(int reported_key)
246 acpi_video_handles_brightness_key_presses()) 316 acpi_video_handles_brightness_key_presses())
247 return; 317 return;
248 318
249 if (reported_key == 0xe025 && !wmi_requires_smbios_request) 319 if (type == 0x0000 && code == 0xe025 && !wmi_requires_smbios_request)
250 return; 320 return;
251 321
252 sparse_keymap_report_entry(dell_wmi_input_dev, key, 1, true); 322 sparse_keymap_report_entry(dell_wmi_input_dev, key, 1, true);
@@ -284,18 +354,6 @@ static void dell_wmi_notify(u32 value, void *context)
284 354
285 buffer_entry = (u16 *)obj->buffer.pointer; 355 buffer_entry = (u16 *)obj->buffer.pointer;
286 buffer_size = obj->buffer.length/2; 356 buffer_size = obj->buffer.length/2;
287
288 if (!dell_new_hk_type) {
289 if (buffer_size >= 3 && buffer_entry[1] == 0x0)
290 dell_wmi_process_key(buffer_entry[2]);
291 else if (buffer_size >= 2)
292 dell_wmi_process_key(buffer_entry[1]);
293 else
294 pr_info("Received unknown WMI event\n");
295 kfree(obj);
296 return;
297 }
298
299 buffer_end = buffer_entry + buffer_size; 357 buffer_end = buffer_entry + buffer_size;
300 358
301 /* 359 /*
@@ -330,62 +388,18 @@ static void dell_wmi_notify(u32 value, void *context)
330 pr_debug("Process buffer (%*ph)\n", len*2, buffer_entry); 388 pr_debug("Process buffer (%*ph)\n", len*2, buffer_entry);
331 389
332 switch (buffer_entry[1]) { 390 switch (buffer_entry[1]) {
333 case 0x00: 391 case 0x0000: /* One key pressed or event occurred */
334 for (i = 2; i < len; ++i) { 392 if (len > 2)
335 switch (buffer_entry[i]) { 393 dell_wmi_process_key(0x0000, buffer_entry[2]);
336 case 0xe043: 394 /* Other entries could contain additional information */
337 /* NIC Link is Up */
338 pr_debug("NIC Link is Up\n");
339 break;
340 case 0xe044:
341 /* NIC Link is Down */
342 pr_debug("NIC Link is Down\n");
343 break;
344 case 0xe045:
345 /* Unknown event but defined in DSDT */
346 default:
347 /* Unknown event */
348 pr_info("Unknown WMI event type 0x00: "
349 "0x%x\n", (int)buffer_entry[i]);
350 break;
351 }
352 }
353 break; 395 break;
354 case 0x10: 396 case 0x0010: /* Sequence of keys pressed */
355 /* Keys pressed */ 397 case 0x0011: /* Sequence of events occurred */
356 for (i = 2; i < len; ++i) 398 for (i = 2; i < len; ++i)
357 dell_wmi_process_key(buffer_entry[i]); 399 dell_wmi_process_key(buffer_entry[1],
358 break; 400 buffer_entry[i]);
359 case 0x11:
360 for (i = 2; i < len; ++i) {
361 switch (buffer_entry[i]) {
362 case 0xfff0:
363 /* Battery unplugged */
364 pr_debug("Battery unplugged\n");
365 break;
366 case 0xfff1:
367 /* Battery inserted */
368 pr_debug("Battery inserted\n");
369 break;
370 case 0x01e1:
371 case 0x02ea:
372 case 0x02eb:
373 case 0x02ec:
374 case 0x02f6:
375 /* Keyboard backlight level changed */
376 pr_debug("Keyboard backlight level "
377 "changed\n");
378 break;
379 default:
380 /* Unknown event */
381 pr_info("Unknown WMI event type 0x11: "
382 "0x%x\n", (int)buffer_entry[i]);
383 break;
384 }
385 }
386 break; 401 break;
387 default: 402 default: /* Unknown event */
388 /* Unknown event */
389 pr_info("Unknown WMI event type 0x%x\n", 403 pr_info("Unknown WMI event type 0x%x\n",
390 (int)buffer_entry[1]); 404 (int)buffer_entry[1]);
391 break; 405 break;
@@ -410,7 +424,6 @@ static bool have_scancode(u32 scancode, const struct key_entry *keymap, int len)
410} 424}
411 425
412static void __init handle_dmi_entry(const struct dmi_header *dm, 426static void __init handle_dmi_entry(const struct dmi_header *dm,
413
414 void *opaque) 427 void *opaque)
415 428
416{ 429{
@@ -418,7 +431,6 @@ static void __init handle_dmi_entry(const struct dmi_header *dm,
418 struct dell_bios_hotkey_table *table; 431 struct dell_bios_hotkey_table *table;
419 int hotkey_num, i, pos = 0; 432 int hotkey_num, i, pos = 0;
420 struct key_entry *keymap; 433 struct key_entry *keymap;
421 int num_bios_keys;
422 434
423 if (results->err || results->keymap) 435 if (results->err || results->keymap)
424 return; /* We already found the hotkey table. */ 436 return; /* We already found the hotkey table. */
@@ -442,8 +454,7 @@ static void __init handle_dmi_entry(const struct dmi_header *dm,
442 return; 454 return;
443 } 455 }
444 456
445 keymap = kcalloc(hotkey_num + ARRAY_SIZE(dell_wmi_extra_keymap) + 1, 457 keymap = kcalloc(hotkey_num, sizeof(struct key_entry), GFP_KERNEL);
446 sizeof(struct key_entry), GFP_KERNEL);
447 if (!keymap) { 458 if (!keymap) {
448 results->err = -ENOMEM; 459 results->err = -ENOMEM;
449 return; 460 return;
@@ -480,31 +491,15 @@ static void __init handle_dmi_entry(const struct dmi_header *dm,
480 pos++; 491 pos++;
481 } 492 }
482 493
483 num_bios_keys = pos;
484
485 for (i = 0; i < ARRAY_SIZE(dell_wmi_extra_keymap); i++) {
486 const struct key_entry *entry = &dell_wmi_extra_keymap[i];
487
488 /*
489 * Check if we've already found this scancode. This takes
490 * quadratic time, but it doesn't matter unless the list
491 * of extra keys gets very long.
492 */
493 if (!have_scancode(entry->code, keymap, num_bios_keys)) {
494 keymap[pos] = *entry;
495 pos++;
496 }
497 }
498
499 keymap[pos].type = KE_END;
500
501 results->keymap = keymap; 494 results->keymap = keymap;
495 results->keymap_size = pos;
502} 496}
503 497
504static int __init dell_wmi_input_setup(void) 498static int __init dell_wmi_input_setup(void)
505{ 499{
506 struct dell_dmi_results dmi_results = {}; 500 struct dell_dmi_results dmi_results = {};
507 int err; 501 struct key_entry *keymap;
502 int err, i, pos = 0;
508 503
509 dell_wmi_input_dev = input_allocate_device(); 504 dell_wmi_input_dev = input_allocate_device();
510 if (!dell_wmi_input_dev) 505 if (!dell_wmi_input_dev)
@@ -528,21 +523,71 @@ static int __init dell_wmi_input_setup(void)
528 goto err_free_dev; 523 goto err_free_dev;
529 } 524 }
530 525
531 if (dmi_results.keymap) { 526 keymap = kcalloc(dmi_results.keymap_size +
532 dell_new_hk_type = true; 527 ARRAY_SIZE(dell_wmi_keymap_type_0000) +
528 ARRAY_SIZE(dell_wmi_keymap_type_0010) +
529 ARRAY_SIZE(dell_wmi_keymap_type_0011) +
530 1,
531 sizeof(struct key_entry), GFP_KERNEL);
532 if (!keymap) {
533 kfree(dmi_results.keymap);
534 err = -ENOMEM;
535 goto err_free_dev;
536 }
537
538 /* Append table with events of type 0x0010 which comes from DMI */
539 for (i = 0; i < dmi_results.keymap_size; i++) {
540 keymap[pos] = dmi_results.keymap[i];
541 keymap[pos].code |= (0x0010 << 16);
542 pos++;
543 }
544
545 kfree(dmi_results.keymap);
533 546
534 err = sparse_keymap_setup(dell_wmi_input_dev, 547 /* Append table with extra events of type 0x0010 which are not in DMI */
535 dmi_results.keymap, NULL); 548 for (i = 0; i < ARRAY_SIZE(dell_wmi_keymap_type_0010); i++) {
549 const struct key_entry *entry = &dell_wmi_keymap_type_0010[i];
536 550
537 /* 551 /*
538 * Sparse keymap library makes a copy of keymap so we 552 * Check if we've already found this scancode. This takes
539 * don't need the original one that was allocated. 553 * quadratic time, but it doesn't matter unless the list
554 * of extra keys gets very long.
540 */ 555 */
541 kfree(dmi_results.keymap); 556 if (dmi_results.keymap_size &&
542 } else { 557 have_scancode(entry->code | (0x0010 << 16),
543 err = sparse_keymap_setup(dell_wmi_input_dev, 558 keymap, dmi_results.keymap_size)
544 dell_wmi_legacy_keymap, NULL); 559 )
560 continue;
561
562 keymap[pos] = *entry;
563 keymap[pos].code |= (0x0010 << 16);
564 pos++;
565 }
566
567 /* Append table with events of type 0x0011 */
568 for (i = 0; i < ARRAY_SIZE(dell_wmi_keymap_type_0011); i++) {
569 keymap[pos] = dell_wmi_keymap_type_0011[i];
570 keymap[pos].code |= (0x0011 << 16);
571 pos++;
545 } 572 }
573
574 /*
575 * Now append also table with "legacy" events of type 0x0000. Some of
576 * them are reported also on laptops which have scancodes in DMI.
577 */
578 for (i = 0; i < ARRAY_SIZE(dell_wmi_keymap_type_0000); i++) {
579 keymap[pos] = dell_wmi_keymap_type_0000[i];
580 pos++;
581 }
582
583 keymap[pos].type = KE_END;
584
585 err = sparse_keymap_setup(dell_wmi_input_dev, keymap, NULL);
586 /*
587 * Sparse keymap library makes a copy of keymap so we don't need the
588 * original one that was allocated.
589 */
590 kfree(keymap);
546 if (err) 591 if (err)
547 goto err_free_dev; 592 goto err_free_dev;
548 593
diff --git a/drivers/platform/x86/fujitsu-laptop.c b/drivers/platform/x86/fujitsu-laptop.c
index ce41bc34288d..61f39abf5dc8 100644
--- a/drivers/platform/x86/fujitsu-laptop.c
+++ b/drivers/platform/x86/fujitsu-laptop.c
@@ -88,9 +88,6 @@
88 88
89#define ACPI_FUJITSU_NOTIFY_CODE1 0x80 89#define ACPI_FUJITSU_NOTIFY_CODE1 0x80
90 90
91#define ACPI_VIDEO_NOTIFY_INC_BRIGHTNESS 0x86
92#define ACPI_VIDEO_NOTIFY_DEC_BRIGHTNESS 0x87
93
94/* FUNC interface - command values */ 91/* FUNC interface - command values */
95#define FUNC_RFKILL 0x1000 92#define FUNC_RFKILL 0x1000
96#define FUNC_LEDS 0x1001 93#define FUNC_LEDS 0x1001
@@ -108,6 +105,8 @@
108#define LOGOLAMP_POWERON 0x2000 105#define LOGOLAMP_POWERON 0x2000
109#define LOGOLAMP_ALWAYS 0x4000 106#define LOGOLAMP_ALWAYS 0x4000
110#define RADIO_LED_ON 0x20 107#define RADIO_LED_ON 0x20
108#define ECO_LED 0x10000
109#define ECO_LED_ON 0x80000
111#endif 110#endif
112 111
113/* Hotkey details */ 112/* Hotkey details */
@@ -121,13 +120,6 @@
121#define RINGBUFFERSIZE 40 120#define RINGBUFFERSIZE 40
122 121
123/* Debugging */ 122/* Debugging */
124#define FUJLAPTOP_LOG ACPI_FUJITSU_HID ": "
125#define FUJLAPTOP_ERR KERN_ERR FUJLAPTOP_LOG
126#define FUJLAPTOP_NOTICE KERN_NOTICE FUJLAPTOP_LOG
127#define FUJLAPTOP_INFO KERN_INFO FUJLAPTOP_LOG
128#define FUJLAPTOP_DEBUG KERN_DEBUG FUJLAPTOP_LOG
129
130#define FUJLAPTOP_DBG_ALL 0xffff
131#define FUJLAPTOP_DBG_ERROR 0x0001 123#define FUJLAPTOP_DBG_ERROR 0x0001
132#define FUJLAPTOP_DBG_WARN 0x0002 124#define FUJLAPTOP_DBG_WARN 0x0002
133#define FUJLAPTOP_DBG_INFO 0x0004 125#define FUJLAPTOP_DBG_INFO 0x0004
@@ -136,7 +128,7 @@
136#ifdef CONFIG_FUJITSU_LAPTOP_DEBUG 128#ifdef CONFIG_FUJITSU_LAPTOP_DEBUG
137#define vdbg_printk(a_dbg_level, format, arg...) \ 129#define vdbg_printk(a_dbg_level, format, arg...) \
138 do { if (dbg_level & a_dbg_level) \ 130 do { if (dbg_level & a_dbg_level) \
139 printk(FUJLAPTOP_DEBUG "%s: " format, __func__ , ## arg); \ 131 printk(KERN_DEBUG pr_fmt("%s: " format), __func__, ## arg); \
140 } while (0) 132 } while (0)
141#else 133#else
142#define vdbg_printk(a_dbg_level, format, arg...) \ 134#define vdbg_printk(a_dbg_level, format, arg...) \
@@ -176,6 +168,7 @@ struct fujitsu_hotkey_t {
176 int logolamp_registered; 168 int logolamp_registered;
177 int kblamps_registered; 169 int kblamps_registered;
178 int radio_led_registered; 170 int radio_led_registered;
171 int eco_led_registered;
179}; 172};
180 173
181static struct fujitsu_hotkey_t *fujitsu_hotkey; 174static struct fujitsu_hotkey_t *fujitsu_hotkey;
@@ -212,6 +205,16 @@ static struct led_classdev radio_led = {
212 .brightness_get = radio_led_get, 205 .brightness_get = radio_led_get,
213 .brightness_set = radio_led_set 206 .brightness_set = radio_led_set
214}; 207};
208
209static enum led_brightness eco_led_get(struct led_classdev *cdev);
210static void eco_led_set(struct led_classdev *cdev,
211 enum led_brightness brightness);
212
213static struct led_classdev eco_led = {
214 .name = "fujitsu::eco_led",
215 .brightness_get = eco_led_get,
216 .brightness_set = eco_led_set
217};
215#endif 218#endif
216 219
217#ifdef CONFIG_FUJITSU_LAPTOP_DEBUG 220#ifdef CONFIG_FUJITSU_LAPTOP_DEBUG
@@ -296,6 +299,18 @@ static void radio_led_set(struct led_classdev *cdev,
296 call_fext_func(FUNC_RFKILL, 0x5, RADIO_LED_ON, 0x0); 299 call_fext_func(FUNC_RFKILL, 0x5, RADIO_LED_ON, 0x0);
297} 300}
298 301
302static void eco_led_set(struct led_classdev *cdev,
303 enum led_brightness brightness)
304{
305 int curr;
306
307 curr = call_fext_func(FUNC_LEDS, 0x2, ECO_LED, 0x0);
308 if (brightness >= LED_FULL)
309 call_fext_func(FUNC_LEDS, 0x1, ECO_LED, curr | ECO_LED_ON);
310 else
311 call_fext_func(FUNC_LEDS, 0x1, ECO_LED, curr & ~ECO_LED_ON);
312}
313
299static enum led_brightness logolamp_get(struct led_classdev *cdev) 314static enum led_brightness logolamp_get(struct led_classdev *cdev)
300{ 315{
301 enum led_brightness brightness = LED_OFF; 316 enum led_brightness brightness = LED_OFF;
@@ -330,6 +345,16 @@ static enum led_brightness radio_led_get(struct led_classdev *cdev)
330 345
331 return brightness; 346 return brightness;
332} 347}
348
349static enum led_brightness eco_led_get(struct led_classdev *cdev)
350{
351 enum led_brightness brightness = LED_OFF;
352
353 if (call_fext_func(FUNC_LEDS, 0x2, ECO_LED, 0x0) & ECO_LED_ON)
354 brightness = LED_FULL;
355
356 return brightness;
357}
333#endif 358#endif
334 359
335/* Hardware access for LCD brightness control */ 360/* Hardware access for LCD brightness control */
@@ -856,6 +881,7 @@ static int acpi_fujitsu_hotkey_add(struct acpi_device *device)
856 set_bit(fujitsu->keycode3, input->keybit); 881 set_bit(fujitsu->keycode3, input->keybit);
857 set_bit(fujitsu->keycode4, input->keybit); 882 set_bit(fujitsu->keycode4, input->keybit);
858 set_bit(fujitsu->keycode5, input->keybit); 883 set_bit(fujitsu->keycode5, input->keybit);
884 set_bit(KEY_TOUCHPAD_TOGGLE, input->keybit);
859 set_bit(KEY_UNKNOWN, input->keybit); 885 set_bit(KEY_UNKNOWN, input->keybit);
860 886
861 error = input_register_device(input); 887 error = input_register_device(input);
@@ -943,6 +969,23 @@ static int acpi_fujitsu_hotkey_add(struct acpi_device *device)
943 result); 969 result);
944 } 970 }
945 } 971 }
972
973 /* Support for eco led is not always signaled in bit corresponding
974 * to the bit used to control the led. According to the DSDT table,
975 * bit 14 seems to indicate presence of said led as well.
976 * Confirm by testing the status.
977 */
978 if ((call_fext_func(FUNC_LEDS, 0x0, 0x0, 0x0) & BIT(14)) &&
979 (call_fext_func(FUNC_LEDS, 0x2, ECO_LED, 0x0) != UNSUPPORTED_CMD)) {
980 result = led_classdev_register(&fujitsu->pf_device->dev,
981 &eco_led);
982 if (result == 0) {
983 fujitsu_hotkey->eco_led_registered = 1;
984 } else {
985 pr_err("Could not register LED handler for eco LED, error %i\n",
986 result);
987 }
988 }
946#endif 989#endif
947 990
948 return result; 991 return result;
@@ -972,6 +1015,9 @@ static int acpi_fujitsu_hotkey_remove(struct acpi_device *device)
972 1015
973 if (fujitsu_hotkey->radio_led_registered) 1016 if (fujitsu_hotkey->radio_led_registered)
974 led_classdev_unregister(&radio_led); 1017 led_classdev_unregister(&radio_led);
1018
1019 if (fujitsu_hotkey->eco_led_registered)
1020 led_classdev_unregister(&eco_led);
975#endif 1021#endif
976 1022
977 input_unregister_device(input); 1023 input_unregister_device(input);
@@ -1060,6 +1106,19 @@ static void acpi_fujitsu_hotkey_notify(struct acpi_device *device, u32 event)
1060 } 1106 }
1061 } 1107 }
1062 1108
1109 /* On some models (first seen on the Skylake-based Lifebook
1110 * E736/E746/E756), the touchpad toggle hotkey (Fn+F4) is
1111 * handled in software; its state is queried using FUNC_RFKILL
1112 */
1113 if ((fujitsu_hotkey->rfkill_supported & BIT(26)) &&
1114 (call_fext_func(FUNC_RFKILL, 0x1, 0x0, 0x0) & BIT(26))) {
1115 keycode = KEY_TOUCHPAD_TOGGLE;
1116 input_report_key(input, keycode, 1);
1117 input_sync(input);
1118 input_report_key(input, keycode, 0);
1119 input_sync(input);
1120 }
1121
1063 break; 1122 break;
1064 default: 1123 default:
1065 keycode = KEY_UNKNOWN; 1124 keycode = KEY_UNKNOWN;
diff --git a/drivers/platform/x86/hp-wmi.c b/drivers/platform/x86/hp-wmi.c
index 6f145f2d004d..96ffda493266 100644
--- a/drivers/platform/x86/hp-wmi.c
+++ b/drivers/platform/x86/hp-wmi.c
@@ -718,6 +718,11 @@ static int __init hp_wmi_rfkill_setup(struct platform_device *device)
718 if (err) 718 if (err)
719 return err; 719 return err;
720 720
721 err = hp_wmi_perform_query(HPWMI_WIRELESS_QUERY, 1, &wireless,
722 sizeof(wireless), 0);
723 if (err)
724 return err;
725
721 if (wireless & 0x1) { 726 if (wireless & 0x1) {
722 wifi_rfkill = rfkill_alloc("hp-wifi", &device->dev, 727 wifi_rfkill = rfkill_alloc("hp-wifi", &device->dev,
723 RFKILL_TYPE_WLAN, 728 RFKILL_TYPE_WLAN,
@@ -882,7 +887,7 @@ static int __init hp_wmi_bios_setup(struct platform_device *device)
882 wwan_rfkill = NULL; 887 wwan_rfkill = NULL;
883 rfkill2_count = 0; 888 rfkill2_count = 0;
884 889
885 if (hp_wmi_bios_2009_later() || hp_wmi_rfkill_setup(device)) 890 if (hp_wmi_rfkill_setup(device))
886 hp_wmi_rfkill2_setup(device); 891 hp_wmi_rfkill2_setup(device);
887 892
888 err = device_create_file(&device->dev, &dev_attr_display); 893 err = device_create_file(&device->dev, &dev_attr_display);
diff --git a/drivers/platform/x86/intel-hid.c b/drivers/platform/x86/intel-hid.c
index a818db6aa08f..ed5874217ee7 100644
--- a/drivers/platform/x86/intel-hid.c
+++ b/drivers/platform/x86/intel-hid.c
@@ -122,8 +122,8 @@ static int intel_hid_input_setup(struct platform_device *device)
122 return 0; 122 return 0;
123 123
124err_free_device: 124err_free_device:
125 input_free_device(priv->input_dev); 125 input_free_device(priv->input_dev);
126 return ret; 126 return ret;
127} 127}
128 128
129static void intel_hid_input_destroy(struct platform_device *device) 129static void intel_hid_input_destroy(struct platform_device *device)
@@ -224,7 +224,6 @@ static int intel_hid_remove(struct platform_device *device)
224 acpi_remove_notify_handler(handle, ACPI_DEVICE_NOTIFY, notify_handler); 224 acpi_remove_notify_handler(handle, ACPI_DEVICE_NOTIFY, notify_handler);
225 intel_hid_input_destroy(device); 225 intel_hid_input_destroy(device);
226 intel_hid_set_enable(&device->dev, 0); 226 intel_hid_set_enable(&device->dev, 0);
227 acpi_remove_notify_handler(handle, ACPI_DEVICE_NOTIFY, notify_handler);
228 227
229 /* 228 /*
230 * Even if we failed to shut off the event stream, we can still 229 * Even if we failed to shut off the event stream, we can still
diff --git a/drivers/platform/x86/intel-vbtn.c b/drivers/platform/x86/intel-vbtn.c
new file mode 100644
index 000000000000..146d02f8c9bc
--- /dev/null
+++ b/drivers/platform/x86/intel-vbtn.c
@@ -0,0 +1,188 @@
1/*
2 * Intel Virtual Button driver for Windows 8.1+
3 *
4 * Copyright (C) 2016 AceLan Kao <acelan.kao@canonical.com>
5 * Copyright (C) 2016 Alex Hung <alex.hung@canonical.com>
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 */
18
19#include <linux/kernel.h>
20#include <linux/module.h>
21#include <linux/init.h>
22#include <linux/input.h>
23#include <linux/platform_device.h>
24#include <linux/input/sparse-keymap.h>
25#include <linux/acpi.h>
26#include <acpi/acpi_bus.h>
27
28MODULE_LICENSE("GPL");
29MODULE_AUTHOR("AceLan Kao");
30
31static const struct acpi_device_id intel_vbtn_ids[] = {
32 {"INT33D6", 0},
33 {"", 0},
34};
35
36/* In theory, these are HID usages. */
37static const struct key_entry intel_vbtn_keymap[] = {
38 { KE_IGNORE, 0xC0, { KEY_POWER } }, /* power key press */
39 { KE_KEY, 0xC1, { KEY_POWER } }, /* power key release */
40 { KE_END },
41};
42
43struct intel_vbtn_priv {
44 struct input_dev *input_dev;
45};
46
47static int intel_vbtn_input_setup(struct platform_device *device)
48{
49 struct intel_vbtn_priv *priv = dev_get_drvdata(&device->dev);
50 int ret;
51
52 priv->input_dev = input_allocate_device();
53 if (!priv->input_dev)
54 return -ENOMEM;
55
56 ret = sparse_keymap_setup(priv->input_dev, intel_vbtn_keymap, NULL);
57 if (ret)
58 goto err_free_device;
59
60 priv->input_dev->dev.parent = &device->dev;
61 priv->input_dev->name = "Intel Virtual Button driver";
62 priv->input_dev->id.bustype = BUS_HOST;
63
64 ret = input_register_device(priv->input_dev);
65 if (ret)
66 goto err_free_device;
67
68 return 0;
69
70err_free_device:
71 input_free_device(priv->input_dev);
72 return ret;
73}
74
75static void intel_vbtn_input_destroy(struct platform_device *device)
76{
77 struct intel_vbtn_priv *priv = dev_get_drvdata(&device->dev);
78
79 input_unregister_device(priv->input_dev);
80}
81
82static void notify_handler(acpi_handle handle, u32 event, void *context)
83{
84 struct platform_device *device = context;
85 struct intel_vbtn_priv *priv = dev_get_drvdata(&device->dev);
86
87 if (!sparse_keymap_report_event(priv->input_dev, event, 1, true))
88 dev_info(&device->dev, "unknown event index 0x%x\n",
89 event);
90}
91
92static int intel_vbtn_probe(struct platform_device *device)
93{
94 acpi_handle handle = ACPI_HANDLE(&device->dev);
95 struct intel_vbtn_priv *priv;
96 acpi_status status;
97 int err;
98
99 status = acpi_evaluate_object(handle, "VBDL", NULL, NULL);
100 if (!ACPI_SUCCESS(status)) {
101 dev_warn(&device->dev, "failed to read Intel Virtual Button driver\n");
102 return -ENODEV;
103 }
104
105 priv = devm_kzalloc(&device->dev, sizeof(*priv), GFP_KERNEL);
106 if (!priv)
107 return -ENOMEM;
108 dev_set_drvdata(&device->dev, priv);
109
110 err = intel_vbtn_input_setup(device);
111 if (err) {
112 pr_err("Failed to setup Intel Virtual Button\n");
113 return err;
114 }
115
116 status = acpi_install_notify_handler(handle,
117 ACPI_DEVICE_NOTIFY,
118 notify_handler,
119 device);
120 if (ACPI_FAILURE(status)) {
121 err = -EBUSY;
122 goto err_remove_input;
123 }
124
125 return 0;
126
127err_remove_input:
128 intel_vbtn_input_destroy(device);
129
130 return err;
131}
132
133static int intel_vbtn_remove(struct platform_device *device)
134{
135 acpi_handle handle = ACPI_HANDLE(&device->dev);
136
137 intel_vbtn_input_destroy(device);
138 acpi_remove_notify_handler(handle, ACPI_DEVICE_NOTIFY, notify_handler);
139
140 /*
141 * Even if we failed to shut off the event stream, we can still
142 * safely detach from the device.
143 */
144 return 0;
145}
146
147static struct platform_driver intel_vbtn_pl_driver = {
148 .driver = {
149 .name = "intel-vbtn",
150 .acpi_match_table = intel_vbtn_ids,
151 },
152 .probe = intel_vbtn_probe,
153 .remove = intel_vbtn_remove,
154};
155MODULE_DEVICE_TABLE(acpi, intel_vbtn_ids);
156
157static acpi_status __init
158check_acpi_dev(acpi_handle handle, u32 lvl, void *context, void **rv)
159{
160 const struct acpi_device_id *ids = context;
161 struct acpi_device *dev;
162
163 if (acpi_bus_get_device(handle, &dev) != 0)
164 return AE_OK;
165
166 if (acpi_match_device_ids(dev, ids) == 0)
167 if (acpi_create_platform_device(dev))
168 dev_info(&dev->dev,
169 "intel-vbtn: created platform device\n");
170
171 return AE_OK;
172}
173
174static int __init intel_vbtn_init(void)
175{
176 acpi_walk_namespace(ACPI_TYPE_DEVICE, ACPI_ROOT_OBJECT,
177 ACPI_UINT32_MAX, check_acpi_dev, NULL,
178 (void *)intel_vbtn_ids, NULL);
179
180 return platform_driver_register(&intel_vbtn_pl_driver);
181}
182module_init(intel_vbtn_init);
183
184static void __exit intel_vbtn_exit(void)
185{
186 platform_driver_unregister(&intel_vbtn_pl_driver);
187}
188module_exit(intel_vbtn_exit);
diff --git a/drivers/platform/x86/intel_pmc_core.c b/drivers/platform/x86/intel_pmc_core.c
index e57f923eea0b..520b58a04daa 100644
--- a/drivers/platform/x86/intel_pmc_core.c
+++ b/drivers/platform/x86/intel_pmc_core.c
@@ -23,7 +23,6 @@
23#include <linux/init.h> 23#include <linux/init.h>
24#include <linux/io.h> 24#include <linux/io.h>
25#include <linux/pci.h> 25#include <linux/pci.h>
26#include <linux/seq_file.h>
27 26
28#include <asm/cpu_device_id.h> 27#include <asm/cpu_device_id.h>
29#include <asm/intel-family.h> 28#include <asm/intel-family.h>
@@ -78,30 +77,18 @@ int intel_pmc_slp_s0_counter_read(u32 *data)
78} 77}
79EXPORT_SYMBOL_GPL(intel_pmc_slp_s0_counter_read); 78EXPORT_SYMBOL_GPL(intel_pmc_slp_s0_counter_read);
80 79
81#if IS_ENABLED(CONFIG_DEBUG_FS) 80static int pmc_core_dev_state_get(void *data, u64 *val)
82static int pmc_core_dev_state_show(struct seq_file *s, void *unused)
83{ 81{
84 struct pmc_dev *pmcdev = s->private; 82 struct pmc_dev *pmcdev = data;
85 u32 counter_val; 83 u32 value;
86 84
87 counter_val = pmc_core_reg_read(pmcdev, 85 value = pmc_core_reg_read(pmcdev, SPT_PMC_SLP_S0_RES_COUNTER_OFFSET);
88 SPT_PMC_SLP_S0_RES_COUNTER_OFFSET); 86 *val = pmc_core_adjust_slp_s0_step(value);
89 seq_printf(s, "%u\n", pmc_core_adjust_slp_s0_step(counter_val));
90 87
91 return 0; 88 return 0;
92} 89}
93 90
94static int pmc_core_dev_state_open(struct inode *inode, struct file *file) 91DEFINE_DEBUGFS_ATTRIBUTE(pmc_core_dev_state, pmc_core_dev_state_get, NULL, "%llu\n");
95{
96 return single_open(file, pmc_core_dev_state_show, inode->i_private);
97}
98
99static const struct file_operations pmc_core_dev_state_ops = {
100 .open = pmc_core_dev_state_open,
101 .read = seq_read,
102 .llseek = seq_lseek,
103 .release = single_release,
104};
105 92
106static void pmc_core_dbgfs_unregister(struct pmc_dev *pmcdev) 93static void pmc_core_dbgfs_unregister(struct pmc_dev *pmcdev)
107{ 94{
@@ -113,12 +100,12 @@ static int pmc_core_dbgfs_register(struct pmc_dev *pmcdev)
113 struct dentry *dir, *file; 100 struct dentry *dir, *file;
114 101
115 dir = debugfs_create_dir("pmc_core", NULL); 102 dir = debugfs_create_dir("pmc_core", NULL);
116 if (!dir) 103 if (IS_ERR_OR_NULL(dir))
117 return -ENOMEM; 104 return -ENOMEM;
118 105
119 pmcdev->dbgfs_dir = dir; 106 pmcdev->dbgfs_dir = dir;
120 file = debugfs_create_file("slp_s0_residency_usec", S_IFREG | S_IRUGO, 107 file = debugfs_create_file("slp_s0_residency_usec", S_IFREG | S_IRUGO,
121 dir, pmcdev, &pmc_core_dev_state_ops); 108 dir, pmcdev, &pmc_core_dev_state);
122 109
123 if (!file) { 110 if (!file) {
124 pmc_core_dbgfs_unregister(pmcdev); 111 pmc_core_dbgfs_unregister(pmcdev);
@@ -127,16 +114,6 @@ static int pmc_core_dbgfs_register(struct pmc_dev *pmcdev)
127 114
128 return 0; 115 return 0;
129} 116}
130#else
131static inline int pmc_core_dbgfs_register(struct pmc_dev *pmcdev)
132{
133 return 0;
134}
135
136static inline void pmc_core_dbgfs_unregister(struct pmc_dev *pmcdev)
137{
138}
139#endif /* CONFIG_DEBUG_FS */
140 117
141static const struct x86_cpu_id intel_pmc_core_ids[] = { 118static const struct x86_cpu_id intel_pmc_core_ids[] = {
142 { X86_VENDOR_INTEL, 6, INTEL_FAM6_SKYLAKE_MOBILE, X86_FEATURE_MWAIT, 119 { X86_VENDOR_INTEL, 6, INTEL_FAM6_SKYLAKE_MOBILE, X86_FEATURE_MWAIT,
@@ -183,10 +160,8 @@ static int pmc_core_probe(struct pci_dev *dev, const struct pci_device_id *id)
183 } 160 }
184 161
185 err = pmc_core_dbgfs_register(pmcdev); 162 err = pmc_core_dbgfs_register(pmcdev);
186 if (err < 0) { 163 if (err < 0)
187 dev_err(&dev->dev, "PMC Core: debugfs register failed.\n"); 164 dev_warn(&dev->dev, "PMC Core: debugfs register failed.\n");
188 return err;
189 }
190 165
191 pmc.has_slp_s0_res = true; 166 pmc.has_slp_s0_res = true;
192 return 0; 167 return 0;
diff --git a/drivers/platform/x86/intel_pmc_core.h b/drivers/platform/x86/intel_pmc_core.h
index a9dadaf787c1..e3f671f4d122 100644
--- a/drivers/platform/x86/intel_pmc_core.h
+++ b/drivers/platform/x86/intel_pmc_core.h
@@ -23,6 +23,7 @@
23 23
24/* Sunrise Point Power Management Controller PCI Device ID */ 24/* Sunrise Point Power Management Controller PCI Device ID */
25#define SPT_PMC_PCI_DEVICE_ID 0x9d21 25#define SPT_PMC_PCI_DEVICE_ID 0x9d21
26
26#define SPT_PMC_BASE_ADDR_OFFSET 0x48 27#define SPT_PMC_BASE_ADDR_OFFSET 0x48
27#define SPT_PMC_SLP_S0_RES_COUNTER_OFFSET 0x13c 28#define SPT_PMC_SLP_S0_RES_COUNTER_OFFSET 0x13c
28#define SPT_PMC_MMIO_REG_LEN 0x100 29#define SPT_PMC_MMIO_REG_LEN 0x100
@@ -42,9 +43,7 @@
42struct pmc_dev { 43struct pmc_dev {
43 u32 base_addr; 44 u32 base_addr;
44 void __iomem *regbase; 45 void __iomem *regbase;
45#if IS_ENABLED(CONFIG_DEBUG_FS)
46 struct dentry *dbgfs_dir; 46 struct dentry *dbgfs_dir;
47#endif /* CONFIG_DEBUG_FS */
48 bool has_slp_s0_res; 47 bool has_slp_s0_res;
49}; 48};
50 49
diff --git a/drivers/platform/x86/intel_telemetry_debugfs.c b/drivers/platform/x86/intel_telemetry_debugfs.c
index 815a7c5e9566..ef29f18b1951 100644
--- a/drivers/platform/x86/intel_telemetry_debugfs.c
+++ b/drivers/platform/x86/intel_telemetry_debugfs.c
@@ -79,7 +79,7 @@
79#define TELEM_EVT_LEN(x) (sizeof(x)/sizeof((x)[0])) 79#define TELEM_EVT_LEN(x) (sizeof(x)/sizeof((x)[0]))
80 80
81#define TELEM_DEBUGFS_CPU(model, data) \ 81#define TELEM_DEBUGFS_CPU(model, data) \
82 { X86_VENDOR_INTEL, 6, model, X86_FEATURE_MWAIT, (unsigned long)&data} 82 { X86_VENDOR_INTEL, 6, model, X86_FEATURE_ANY, (unsigned long)&data}
83 83
84#define TELEM_CHECK_AND_PARSE_EVTS(EVTID, EVTNUM, BUF, EVTLOG, EVTDAT, MASK) { \ 84#define TELEM_CHECK_AND_PARSE_EVTS(EVTID, EVTNUM, BUF, EVTLOG, EVTDAT, MASK) { \
85 if (evtlog[index].telem_evtid == (EVTID)) { \ 85 if (evtlog[index].telem_evtid == (EVTID)) { \
diff --git a/drivers/platform/x86/intel_telemetry_pltdrv.c b/drivers/platform/x86/intel_telemetry_pltdrv.c
index 6d884f7d1b9f..6ebdbd2b04fc 100644
--- a/drivers/platform/x86/intel_telemetry_pltdrv.c
+++ b/drivers/platform/x86/intel_telemetry_pltdrv.c
@@ -83,7 +83,7 @@
83#define TELEM_SET_VERBOSITY_BITS(x, y) ((x) |= ((y) << 27)) 83#define TELEM_SET_VERBOSITY_BITS(x, y) ((x) |= ((y) << 27))
84 84
85#define TELEM_CPU(model, data) \ 85#define TELEM_CPU(model, data) \
86 { X86_VENDOR_INTEL, 6, model, X86_FEATURE_MWAIT, (unsigned long)&data } 86 { X86_VENDOR_INTEL, 6, model, X86_FEATURE_ANY, (unsigned long)&data }
87 87
88enum telemetry_action { 88enum telemetry_action {
89 TELEM_UPDATE = 0, 89 TELEM_UPDATE = 0,
diff --git a/drivers/platform/x86/toshiba_acpi.c b/drivers/platform/x86/toshiba_acpi.c
index 01e12d221a8b..9d60a40d8b3f 100644
--- a/drivers/platform/x86/toshiba_acpi.c
+++ b/drivers/platform/x86/toshiba_acpi.c
@@ -4,7 +4,7 @@
4 * Copyright (C) 2002-2004 John Belmonte 4 * Copyright (C) 2002-2004 John Belmonte
5 * Copyright (C) 2008 Philip Langdale 5 * Copyright (C) 2008 Philip Langdale
6 * Copyright (C) 2010 Pierre Ducroquet 6 * Copyright (C) 2010 Pierre Ducroquet
7 * Copyright (C) 2014-2015 Azael Avalos 7 * Copyright (C) 2014-2016 Azael Avalos
8 * 8 *
9 * This program is free software; you can redistribute it and/or modify 9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by 10 * it under the terms of the GNU General Public License as published by
@@ -31,7 +31,7 @@
31 31
32#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt 32#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
33 33
34#define TOSHIBA_ACPI_VERSION "0.23" 34#define TOSHIBA_ACPI_VERSION "0.24"
35#define PROC_INTERFACE_VERSION 1 35#define PROC_INTERFACE_VERSION 1
36 36
37#include <linux/kernel.h> 37#include <linux/kernel.h>
@@ -53,6 +53,7 @@
53#include <linux/uaccess.h> 53#include <linux/uaccess.h>
54#include <linux/miscdevice.h> 54#include <linux/miscdevice.h>
55#include <linux/rfkill.h> 55#include <linux/rfkill.h>
56#include <linux/iio/iio.h>
56#include <linux/toshiba.h> 57#include <linux/toshiba.h>
57#include <acpi/video.h> 58#include <acpi/video.h>
58 59
@@ -134,6 +135,7 @@ MODULE_LICENSE("GPL");
134 135
135/* Field definitions */ 136/* Field definitions */
136#define HCI_ACCEL_MASK 0x7fff 137#define HCI_ACCEL_MASK 0x7fff
138#define HCI_ACCEL_DIRECTION_MASK 0x8000
137#define HCI_HOTKEY_DISABLE 0x0b 139#define HCI_HOTKEY_DISABLE 0x0b
138#define HCI_HOTKEY_ENABLE 0x09 140#define HCI_HOTKEY_ENABLE 0x09
139#define HCI_HOTKEY_SPECIAL_FUNCTIONS 0x10 141#define HCI_HOTKEY_SPECIAL_FUNCTIONS 0x10
@@ -178,6 +180,7 @@ struct toshiba_acpi_dev {
178 struct led_classdev eco_led; 180 struct led_classdev eco_led;
179 struct miscdevice miscdev; 181 struct miscdevice miscdev;
180 struct rfkill *wwan_rfk; 182 struct rfkill *wwan_rfk;
183 struct iio_dev *indio_dev;
181 184
182 int force_fan; 185 int force_fan;
183 int last_key_event; 186 int last_key_event;
@@ -1958,28 +1961,6 @@ static ssize_t touchpad_show(struct device *dev,
1958} 1961}
1959static DEVICE_ATTR_RW(touchpad); 1962static DEVICE_ATTR_RW(touchpad);
1960 1963
1961static ssize_t position_show(struct device *dev,
1962 struct device_attribute *attr, char *buf)
1963{
1964 struct toshiba_acpi_dev *toshiba = dev_get_drvdata(dev);
1965 u32 xyval, zval, tmp;
1966 u16 x, y, z;
1967 int ret;
1968
1969 xyval = zval = 0;
1970 ret = toshiba_accelerometer_get(toshiba, &xyval, &zval);
1971 if (ret < 0)
1972 return ret;
1973
1974 x = xyval & HCI_ACCEL_MASK;
1975 tmp = xyval >> HCI_MISC_SHIFT;
1976 y = tmp & HCI_ACCEL_MASK;
1977 z = zval & HCI_ACCEL_MASK;
1978
1979 return sprintf(buf, "%d %d %d\n", x, y, z);
1980}
1981static DEVICE_ATTR_RO(position);
1982
1983static ssize_t usb_sleep_charge_show(struct device *dev, 1964static ssize_t usb_sleep_charge_show(struct device *dev,
1984 struct device_attribute *attr, char *buf) 1965 struct device_attribute *attr, char *buf)
1985{ 1966{
@@ -2350,7 +2331,6 @@ static struct attribute *toshiba_attributes[] = {
2350 &dev_attr_available_kbd_modes.attr, 2331 &dev_attr_available_kbd_modes.attr,
2351 &dev_attr_kbd_backlight_timeout.attr, 2332 &dev_attr_kbd_backlight_timeout.attr,
2352 &dev_attr_touchpad.attr, 2333 &dev_attr_touchpad.attr,
2353 &dev_attr_position.attr,
2354 &dev_attr_usb_sleep_charge.attr, 2334 &dev_attr_usb_sleep_charge.attr,
2355 &dev_attr_sleep_functions_on_battery.attr, 2335 &dev_attr_sleep_functions_on_battery.attr,
2356 &dev_attr_usb_rapid_charge.attr, 2336 &dev_attr_usb_rapid_charge.attr,
@@ -2377,8 +2357,6 @@ static umode_t toshiba_sysfs_is_visible(struct kobject *kobj,
2377 exists = (drv->kbd_mode == SCI_KBD_MODE_AUTO) ? true : false; 2357 exists = (drv->kbd_mode == SCI_KBD_MODE_AUTO) ? true : false;
2378 else if (attr == &dev_attr_touchpad.attr) 2358 else if (attr == &dev_attr_touchpad.attr)
2379 exists = (drv->touchpad_supported) ? true : false; 2359 exists = (drv->touchpad_supported) ? true : false;
2380 else if (attr == &dev_attr_position.attr)
2381 exists = (drv->accelerometer_supported) ? true : false;
2382 else if (attr == &dev_attr_usb_sleep_charge.attr) 2360 else if (attr == &dev_attr_usb_sleep_charge.attr)
2383 exists = (drv->usb_sleep_charge_supported) ? true : false; 2361 exists = (drv->usb_sleep_charge_supported) ? true : false;
2384 else if (attr == &dev_attr_sleep_functions_on_battery.attr) 2362 else if (attr == &dev_attr_sleep_functions_on_battery.attr)
@@ -2420,6 +2398,81 @@ static void toshiba_acpi_kbd_bl_work(struct work_struct *work)
2420} 2398}
2421 2399
2422/* 2400/*
2401 * IIO device
2402 */
2403
2404enum toshiba_iio_accel_chan {
2405 AXIS_X,
2406 AXIS_Y,
2407 AXIS_Z
2408};
2409
2410static int toshiba_iio_accel_get_axis(enum toshiba_iio_accel_chan chan)
2411{
2412 u32 xyval, zval;
2413 int ret;
2414
2415 ret = toshiba_accelerometer_get(toshiba_acpi, &xyval, &zval);
2416 if (ret < 0)
2417 return ret;
2418
2419 switch (chan) {
2420 case AXIS_X:
2421 return xyval & HCI_ACCEL_DIRECTION_MASK ?
2422 -(xyval & HCI_ACCEL_MASK) : xyval & HCI_ACCEL_MASK;
2423 case AXIS_Y:
2424 return (xyval >> HCI_MISC_SHIFT) & HCI_ACCEL_DIRECTION_MASK ?
2425 -((xyval >> HCI_MISC_SHIFT) & HCI_ACCEL_MASK) :
2426 (xyval >> HCI_MISC_SHIFT) & HCI_ACCEL_MASK;
2427 case AXIS_Z:
2428 return zval & HCI_ACCEL_DIRECTION_MASK ?
2429 -(zval & HCI_ACCEL_MASK) : zval & HCI_ACCEL_MASK;
2430 }
2431
2432 return ret;
2433}
2434
2435static int toshiba_iio_accel_read_raw(struct iio_dev *indio_dev,
2436 struct iio_chan_spec const *chan,
2437 int *val, int *val2, long mask)
2438{
2439 int ret;
2440
2441 switch (mask) {
2442 case IIO_CHAN_INFO_RAW:
2443 ret = toshiba_iio_accel_get_axis(chan->channel);
2444 if (ret == -EIO || ret == -ENODEV)
2445 return ret;
2446
2447 *val = ret;
2448
2449 return IIO_VAL_INT;
2450 }
2451
2452 return -EINVAL;
2453}
2454
2455#define TOSHIBA_IIO_ACCEL_CHANNEL(axis, chan) { \
2456 .type = IIO_ACCEL, \
2457 .modified = 1, \
2458 .channel = chan, \
2459 .channel2 = IIO_MOD_##axis, \
2460 .output = 1, \
2461 .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \
2462}
2463
2464static const struct iio_chan_spec toshiba_iio_accel_channels[] = {
2465 TOSHIBA_IIO_ACCEL_CHANNEL(X, AXIS_X),
2466 TOSHIBA_IIO_ACCEL_CHANNEL(Y, AXIS_Y),
2467 TOSHIBA_IIO_ACCEL_CHANNEL(Z, AXIS_Z),
2468};
2469
2470static const struct iio_info toshiba_iio_accel_info = {
2471 .driver_module = THIS_MODULE,
2472 .read_raw = &toshiba_iio_accel_read_raw,
2473};
2474
2475/*
2423 * Misc device 2476 * Misc device
2424 */ 2477 */
2425static int toshiba_acpi_smm_bridge(SMMRegisters *regs) 2478static int toshiba_acpi_smm_bridge(SMMRegisters *regs)
@@ -2904,6 +2957,11 @@ static int toshiba_acpi_remove(struct acpi_device *acpi_dev)
2904 2957
2905 remove_toshiba_proc_entries(dev); 2958 remove_toshiba_proc_entries(dev);
2906 2959
2960 if (dev->accelerometer_supported && dev->indio_dev) {
2961 iio_device_unregister(dev->indio_dev);
2962 iio_device_free(dev->indio_dev);
2963 }
2964
2907 if (dev->sysfs_created) 2965 if (dev->sysfs_created)
2908 sysfs_remove_group(&dev->acpi_dev->dev.kobj, 2966 sysfs_remove_group(&dev->acpi_dev->dev.kobj,
2909 &toshiba_attr_group); 2967 &toshiba_attr_group);
@@ -3051,6 +3109,30 @@ static int toshiba_acpi_add(struct acpi_device *acpi_dev)
3051 dev->touchpad_supported = !ret; 3109 dev->touchpad_supported = !ret;
3052 3110
3053 toshiba_accelerometer_available(dev); 3111 toshiba_accelerometer_available(dev);
3112 if (dev->accelerometer_supported) {
3113 dev->indio_dev = iio_device_alloc(sizeof(*dev));
3114 if (!dev->indio_dev) {
3115 pr_err("Unable to allocate iio device\n");
3116 goto iio_error;
3117 }
3118
3119 pr_info("Registering Toshiba accelerometer iio device\n");
3120
3121 dev->indio_dev->info = &toshiba_iio_accel_info;
3122 dev->indio_dev->name = "Toshiba accelerometer";
3123 dev->indio_dev->dev.parent = &acpi_dev->dev;
3124 dev->indio_dev->modes = INDIO_DIRECT_MODE;
3125 dev->indio_dev->channels = toshiba_iio_accel_channels;
3126 dev->indio_dev->num_channels =
3127 ARRAY_SIZE(toshiba_iio_accel_channels);
3128
3129 ret = iio_device_register(dev->indio_dev);
3130 if (ret < 0) {
3131 pr_err("Unable to register iio device\n");
3132 iio_device_free(dev->indio_dev);
3133 }
3134 }
3135iio_error:
3054 3136
3055 toshiba_usb_sleep_charge_available(dev); 3137 toshiba_usb_sleep_charge_available(dev);
3056 3138