diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2016-07-26 20:23:08 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2016-07-26 20:23:08 -0400 |
commit | 27b79027bc112a63ad4004eb83c6acacae08a0de (patch) | |
tree | abce98b7d4598c6c212954a84cb3b41b7c33ddf3 /drivers/platform | |
parent | f7e68169941a26cb1ad764d53ef13721e6fe439a (diff) | |
parent | 332e081225fc2a657aa587c42943d5f5a7dae88b (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/Kconfig | 15 | ||||
-rw-r--r-- | drivers/platform/x86/Makefile | 1 | ||||
-rw-r--r-- | drivers/platform/x86/asus-nb-wmi.c | 50 | ||||
-rw-r--r-- | drivers/platform/x86/asus-wireless.c | 91 | ||||
-rw-r--r-- | drivers/platform/x86/asus-wmi.c | 8 | ||||
-rw-r--r-- | drivers/platform/x86/asus-wmi.h | 1 | ||||
-rw-r--r-- | drivers/platform/x86/dell-wmi.c | 293 | ||||
-rw-r--r-- | drivers/platform/x86/fujitsu-laptop.c | 81 | ||||
-rw-r--r-- | drivers/platform/x86/hp-wmi.c | 7 | ||||
-rw-r--r-- | drivers/platform/x86/intel-hid.c | 5 | ||||
-rw-r--r-- | drivers/platform/x86/intel-vbtn.c | 188 | ||||
-rw-r--r-- | drivers/platform/x86/intel_pmc_core.c | 45 | ||||
-rw-r--r-- | drivers/platform/x86/intel_pmc_core.h | 3 | ||||
-rw-r--r-- | drivers/platform/x86/intel_telemetry_debugfs.c | 2 | ||||
-rw-r--r-- | drivers/platform/x86/intel_telemetry_pltdrv.c | 2 | ||||
-rw-r--r-- | drivers/platform/x86/toshiba_acpi.c | 136 |
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 | ||
776 | config 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 | |||
773 | config INTEL_SCU_IPC | 788 | config 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 | |||
44 | obj-$(CONFIG_TOSHIBA_HAPS) += toshiba_haps.o | 44 | obj-$(CONFIG_TOSHIBA_HAPS) += toshiba_haps.o |
45 | obj-$(CONFIG_TOSHIBA_WMI) += toshiba-wmi.o | 45 | obj-$(CONFIG_TOSHIBA_WMI) += toshiba-wmi.o |
46 | obj-$(CONFIG_INTEL_HID_EVENT) += intel-hid.o | 46 | obj-$(CONFIG_INTEL_HID_EVENT) += intel-hid.o |
47 | obj-$(CONFIG_INTEL_VBTN) += intel-vbtn.o | ||
47 | obj-$(CONFIG_INTEL_SCU_IPC) += intel_scu_ipc.o | 48 | obj-$(CONFIG_INTEL_SCU_IPC) += intel_scu_ipc.o |
48 | obj-$(CONFIG_INTEL_SCU_IPC_UTIL) += intel_scu_ipcutil.o | 49 | obj-$(CONFIG_INTEL_SCU_IPC_UTIL) += intel_scu_ipcutil.o |
49 | obj-$(CONFIG_INTEL_MFLD_THERMAL) += intel_mid_thermal.o | 50 | obj-$(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 | ||
81 | static struct quirk_entry quirk_no_rfkill = { | ||
82 | .no_rfkill = true, | ||
83 | }; | ||
84 | |||
85 | static struct quirk_entry quirk_no_rfkill_wapf4 = { | ||
86 | .wapf = 4, | ||
87 | .no_rfkill = true, | ||
88 | }; | ||
89 | |||
81 | static int dmi_matched(const struct dmi_system_id *dmi) | 90 | static 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 | ||
19 | struct asus_wireless_data { | 24 | struct 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 | ||
33 | static 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 | |||
57 | static 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 | |||
70 | static 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 | |||
79 | static 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 | |||
23 | static void asus_wireless_notify(struct acpi_device *adev, u32 event) | 90 | static 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) | |||
37 | static int asus_wireless_add(struct acpi_device *adev) | 104 | static 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 | ||
58 | static int asus_wireless_remove(struct acpi_device *adev) | 143 | static 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; | |||
38 | struct asus_wmi; | 38 | struct asus_wmi; |
39 | 39 | ||
40 | struct quirk_entry { | 40 | struct 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 | 89 | static const struct key_entry dell_wmi_keymap_type_0000[] __initconst = { | |
88 | static 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 | ||
141 | static bool dell_new_hk_type; | ||
142 | |||
143 | struct dell_bios_keymap_entry { | 192 | struct 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 | ||
154 | struct dell_dmi_results { | 203 | struct 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 | */ |
207 | static const struct key_entry dell_wmi_extra_keymap[] __initconst = { | 259 | static 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 | */ | ||
282 | static 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 | |||
227 | static struct input_dev *dell_wmi_input_dev; | 297 | static struct input_dev *dell_wmi_input_dev; |
228 | 298 | ||
229 | static void dell_wmi_process_key(int reported_key) | 299 | static 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 | ||
412 | static void __init handle_dmi_entry(const struct dmi_header *dm, | 426 | static 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 | ||
504 | static int __init dell_wmi_input_setup(void) | 498 | static 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 | ||
181 | static struct fujitsu_hotkey_t *fujitsu_hotkey; | 174 | static 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 | |||
209 | static enum led_brightness eco_led_get(struct led_classdev *cdev); | ||
210 | static void eco_led_set(struct led_classdev *cdev, | ||
211 | enum led_brightness brightness); | ||
212 | |||
213 | static 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 | ||
302 | static 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 | |||
299 | static enum led_brightness logolamp_get(struct led_classdev *cdev) | 314 | static 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 | |||
349 | static 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 | ||
124 | err_free_device: | 124 | err_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 | ||
129 | static void intel_hid_input_destroy(struct platform_device *device) | 129 | static 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 | |||
28 | MODULE_LICENSE("GPL"); | ||
29 | MODULE_AUTHOR("AceLan Kao"); | ||
30 | |||
31 | static const struct acpi_device_id intel_vbtn_ids[] = { | ||
32 | {"INT33D6", 0}, | ||
33 | {"", 0}, | ||
34 | }; | ||
35 | |||
36 | /* In theory, these are HID usages. */ | ||
37 | static 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 | |||
43 | struct intel_vbtn_priv { | ||
44 | struct input_dev *input_dev; | ||
45 | }; | ||
46 | |||
47 | static 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 | |||
70 | err_free_device: | ||
71 | input_free_device(priv->input_dev); | ||
72 | return ret; | ||
73 | } | ||
74 | |||
75 | static 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 | |||
82 | static 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 | |||
92 | static 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 | |||
127 | err_remove_input: | ||
128 | intel_vbtn_input_destroy(device); | ||
129 | |||
130 | return err; | ||
131 | } | ||
132 | |||
133 | static 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 | |||
147 | static 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 | }; | ||
155 | MODULE_DEVICE_TABLE(acpi, intel_vbtn_ids); | ||
156 | |||
157 | static acpi_status __init | ||
158 | check_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 | |||
174 | static 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 | } | ||
182 | module_init(intel_vbtn_init); | ||
183 | |||
184 | static void __exit intel_vbtn_exit(void) | ||
185 | { | ||
186 | platform_driver_unregister(&intel_vbtn_pl_driver); | ||
187 | } | ||
188 | module_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 | } |
79 | EXPORT_SYMBOL_GPL(intel_pmc_slp_s0_counter_read); | 78 | EXPORT_SYMBOL_GPL(intel_pmc_slp_s0_counter_read); |
80 | 79 | ||
81 | #if IS_ENABLED(CONFIG_DEBUG_FS) | 80 | static int pmc_core_dev_state_get(void *data, u64 *val) |
82 | static 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 | ||
94 | static int pmc_core_dev_state_open(struct inode *inode, struct file *file) | 91 | DEFINE_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 | |||
99 | static 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 | ||
106 | static void pmc_core_dbgfs_unregister(struct pmc_dev *pmcdev) | 93 | static 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 | ||
131 | static inline int pmc_core_dbgfs_register(struct pmc_dev *pmcdev) | ||
132 | { | ||
133 | return 0; | ||
134 | } | ||
135 | |||
136 | static inline void pmc_core_dbgfs_unregister(struct pmc_dev *pmcdev) | ||
137 | { | ||
138 | } | ||
139 | #endif /* CONFIG_DEBUG_FS */ | ||
140 | 117 | ||
141 | static const struct x86_cpu_id intel_pmc_core_ids[] = { | 118 | static 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 @@ | |||
42 | struct pmc_dev { | 43 | struct 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 | ||
88 | enum telemetry_action { | 88 | enum 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 | } |
1959 | static DEVICE_ATTR_RW(touchpad); | 1962 | static DEVICE_ATTR_RW(touchpad); |
1960 | 1963 | ||
1961 | static 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 | } | ||
1981 | static DEVICE_ATTR_RO(position); | ||
1982 | |||
1983 | static ssize_t usb_sleep_charge_show(struct device *dev, | 1964 | static 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 | |||
2404 | enum toshiba_iio_accel_chan { | ||
2405 | AXIS_X, | ||
2406 | AXIS_Y, | ||
2407 | AXIS_Z | ||
2408 | }; | ||
2409 | |||
2410 | static 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 | |||
2435 | static 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 | |||
2464 | static 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 | |||
2470 | static 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 | */ |
2425 | static int toshiba_acpi_smm_bridge(SMMRegisters *regs) | 2478 | static 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 | } | ||
3135 | iio_error: | ||
3054 | 3136 | ||
3055 | toshiba_usb_sleep_charge_available(dev); | 3137 | toshiba_usb_sleep_charge_available(dev); |
3056 | 3138 | ||