diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2015-11-06 02:45:53 -0500 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2015-11-06 02:45:53 -0500 |
commit | d1e41ff11941784f469f17795a4d9425c2eb4b7a (patch) | |
tree | 9cf7a381919282de65744329f61807ba49a83ad7 | |
parent | 2f4bf528eca5b2d9eef12b6d323c040254f8f67c (diff) | |
parent | d2f20619942fe4618160a7fa3dbdcbac335cff59 (diff) |
Merge tag 'platform-drivers-x86-v4.4-1' of git://git.infradead.org/users/dvhart/linux-platform-drivers-x86
Pull x86 platform driver update from Darren Hart:
"Various toshiba hotkey and keyboard related fixes and a new WMI
driver. Several intel_scu_ipc cleanups and a locking fix. A
spattering of small single fixes across various platforms.
I was asked to pick up an OLPC cleanup as the driver appeared
unmaintained and it seemed similar to what is maintained in
platform/drivers/x86. I have included the patch and an update to the
MAINTAINERS file.
toshiba_acpi:
- Initialize hotkey_event_type variable
- Remove unneeded u32 variables from *setup_keyboard
- Add 0x prefix to available_kbd_modes_show function
- Change default Hotkey enabling value
- Unify hotkey enabling functions
toshiba-wmi:
- Toshiba WMI Hotkey Driver
intel_scu_ipc:
- Protect dev member assignment on ->remove()
- Switch to use module_pci_driver() macro
- Convert to use struct device *
- Propagate pointer to struct intel_scu_ipc_dev
- Fix error path by turning to devm_* / pcim_*
acer-wmi:
- remove threeg and interface sysfs interfaces
OLPC:
- Use %*ph specifier instead of passing direct values
MAINTAINERS:
- Add drivers/platform/olpc to drivers/platform/x86
sony-laptop:
- Fix handling sony_nc_hotkeys_decode result
intel_mid_powerbtn:
- Remove misuse of IRQF_NO_SUSPEND flag
compal-laptop:
- Add charge control limit
asus-wmi:
- restore kbd led level after resume"
* tag 'platform-drivers-x86-v4.4-1' of git://git.infradead.org/users/dvhart/linux-platform-drivers-x86:
toshiba_acpi: Initialize hotkey_event_type variable
intel_scu_ipc: Protect dev member assignment on ->remove()
intel_scu_ipc: Switch to use module_pci_driver() macro
intel_scu_ipc: Convert to use struct device *
intel_scu_ipc: Propagate pointer to struct intel_scu_ipc_dev
intel_scu_ipc: Fix error path by turning to devm_* / pcim_*
acer-wmi: remove threeg and interface sysfs interfaces
OLPC: Use %*ph specifier instead of passing direct values
MAINTAINERS: Add drivers/platform/olpc to drivers/platform/x86
platform/x86: Toshiba WMI Hotkey Driver
sony-laptop: Fix handling sony_nc_hotkeys_decode result
intel_mid_powerbtn: Remove misuse of IRQF_NO_SUSPEND flag
compal-laptop: Add charge control limit
asus-wmi: restore kbd led level after resume
toshiba_acpi: Remove unneeded u32 variables from *setup_keyboard
toshiba_acpi: Add 0x prefix to available_kbd_modes_show function
toshiba_acpi: Change default Hotkey enabling value
toshiba_acpi: Unify hotkey enabling functions
-rw-r--r-- | MAINTAINERS | 7 | ||||
-rw-r--r-- | drivers/platform/olpc/olpc-ec.c | 13 | ||||
-rw-r--r-- | drivers/platform/x86/Kconfig | 22 | ||||
-rw-r--r-- | drivers/platform/x86/Makefile | 1 | ||||
-rw-r--r-- | drivers/platform/x86/acer-wmi.c | 92 | ||||
-rw-r--r-- | drivers/platform/x86/asus-wmi.c | 19 | ||||
-rw-r--r-- | drivers/platform/x86/compal-laptop.c | 43 | ||||
-rw-r--r-- | drivers/platform/x86/intel_mid_powerbtn.c | 10 | ||||
-rw-r--r-- | drivers/platform/x86/intel_scu_ipc.c | 189 | ||||
-rw-r--r-- | drivers/platform/x86/sony-laptop.c | 13 | ||||
-rw-r--r-- | drivers/platform/x86/toshiba-wmi.c | 138 | ||||
-rw-r--r-- | drivers/platform/x86/toshiba_acpi.c | 63 |
12 files changed, 358 insertions, 252 deletions
diff --git a/MAINTAINERS b/MAINTAINERS index 7301ae17ec63..15c38961d6ff 100644 --- a/MAINTAINERS +++ b/MAINTAINERS | |||
@@ -10699,6 +10699,12 @@ L: platform-driver-x86@vger.kernel.org | |||
10699 | S: Maintained | 10699 | S: Maintained |
10700 | F: drivers/platform/x86/toshiba_haps.c | 10700 | F: drivers/platform/x86/toshiba_haps.c |
10701 | 10701 | ||
10702 | TOSHIBA WMI HOTKEYS DRIVER | ||
10703 | M: Azael Avalos <coproscefalo@gmail.com> | ||
10704 | L: platform-driver-x86@vger.kernel.org | ||
10705 | S: Maintained | ||
10706 | F: drivers/platform/x86/toshiba-wmi.c | ||
10707 | |||
10702 | TOSHIBA SMM DRIVER | 10708 | TOSHIBA SMM DRIVER |
10703 | M: Jonathan Buzzard <jonathan@buzzard.org.uk> | 10709 | M: Jonathan Buzzard <jonathan@buzzard.org.uk> |
10704 | W: http://www.buzzard.org.uk/toshiba/ | 10710 | W: http://www.buzzard.org.uk/toshiba/ |
@@ -11621,6 +11627,7 @@ L: platform-driver-x86@vger.kernel.org | |||
11621 | T: git git://git.infradead.org/users/dvhart/linux-platform-drivers-x86.git | 11627 | T: git git://git.infradead.org/users/dvhart/linux-platform-drivers-x86.git |
11622 | S: Maintained | 11628 | S: Maintained |
11623 | F: drivers/platform/x86/ | 11629 | F: drivers/platform/x86/ |
11630 | F: drivers/platform/olpc/ | ||
11624 | 11631 | ||
11625 | X86 MCE INFRASTRUCTURE | 11632 | X86 MCE INFRASTRUCTURE |
11626 | M: Tony Luck <tony.luck@intel.com> | 11633 | M: Tony Luck <tony.luck@intel.com> |
diff --git a/drivers/platform/olpc/olpc-ec.c b/drivers/platform/olpc/olpc-ec.c index f9119525f557..f99b183d5296 100644 --- a/drivers/platform/olpc/olpc-ec.c +++ b/drivers/platform/olpc/olpc-ec.c | |||
@@ -192,18 +192,15 @@ static ssize_t ec_dbgfs_cmd_write(struct file *file, const char __user *buf, | |||
192 | for (i = 0; i <= ec_cmd_bytes; i++) | 192 | for (i = 0; i <= ec_cmd_bytes; i++) |
193 | ec_cmd[i] = ec_cmd_int[i]; | 193 | ec_cmd[i] = ec_cmd_int[i]; |
194 | 194 | ||
195 | pr_debug("olpc-ec: debugfs cmd 0x%02x with %d args %02x %02x %02x %02x %02x, want %d returns\n", | 195 | pr_debug("olpc-ec: debugfs cmd 0x%02x with %d args %5ph, want %d returns\n", |
196 | ec_cmd[0], ec_cmd_bytes, ec_cmd[1], ec_cmd[2], | 196 | ec_cmd[0], ec_cmd_bytes, ec_cmd + 1, |
197 | ec_cmd[3], ec_cmd[4], ec_cmd[5], ec_dbgfs_resp_bytes); | 197 | ec_dbgfs_resp_bytes); |
198 | 198 | ||
199 | olpc_ec_cmd(ec_cmd[0], (ec_cmd_bytes == 0) ? NULL : &ec_cmd[1], | 199 | olpc_ec_cmd(ec_cmd[0], (ec_cmd_bytes == 0) ? NULL : &ec_cmd[1], |
200 | ec_cmd_bytes, ec_dbgfs_resp, ec_dbgfs_resp_bytes); | 200 | ec_cmd_bytes, ec_dbgfs_resp, ec_dbgfs_resp_bytes); |
201 | 201 | ||
202 | pr_debug("olpc-ec: response %02x %02x %02x %02x %02x %02x %02x %02x (%d bytes expected)\n", | 202 | pr_debug("olpc-ec: response %8ph (%d bytes expected)\n", |
203 | ec_dbgfs_resp[0], ec_dbgfs_resp[1], ec_dbgfs_resp[2], | 203 | ec_dbgfs_resp, ec_dbgfs_resp_bytes); |
204 | ec_dbgfs_resp[3], ec_dbgfs_resp[4], ec_dbgfs_resp[5], | ||
205 | ec_dbgfs_resp[6], ec_dbgfs_resp[7], | ||
206 | ec_dbgfs_resp_bytes); | ||
207 | 204 | ||
208 | out: | 205 | out: |
209 | mutex_unlock(&ec_dbgfs_lock); | 206 | mutex_unlock(&ec_dbgfs_lock); |
diff --git a/drivers/platform/x86/Kconfig b/drivers/platform/x86/Kconfig index c69bb703f483..7b492d9b3ec4 100644 --- a/drivers/platform/x86/Kconfig +++ b/drivers/platform/x86/Kconfig | |||
@@ -309,8 +309,8 @@ config COMPAL_LAPTOP | |||
309 | This is a driver for laptops built by Compal, and some models by | 309 | This is a driver for laptops built by Compal, and some models by |
310 | other brands (e.g. Dell, Toshiba). | 310 | other brands (e.g. Dell, Toshiba). |
311 | 311 | ||
312 | It adds support for rfkill, Bluetooth, WLAN and LCD brightness | 312 | It adds support for rfkill, Bluetooth, WLAN, LCD brightness, hwmon |
313 | control. | 313 | and battery charging level control. |
314 | 314 | ||
315 | For a (possibly incomplete) list of supported laptops, please refer | 315 | For a (possibly incomplete) list of supported laptops, please refer |
316 | to: Documentation/platform/x86-laptop-drivers.txt | 316 | to: Documentation/platform/x86-laptop-drivers.txt |
@@ -700,6 +700,24 @@ config TOSHIBA_HAPS | |||
700 | If you have a recent Toshiba laptop with a built-in accelerometer | 700 | If you have a recent Toshiba laptop with a built-in accelerometer |
701 | device, say Y. | 701 | device, say Y. |
702 | 702 | ||
703 | config TOSHIBA_WMI | ||
704 | tristate "Toshiba WMI Hotkeys Driver (EXPERIMENTAL)" | ||
705 | default n | ||
706 | depends on ACPI_WMI | ||
707 | depends on INPUT | ||
708 | select INPUT_SPARSEKMAP | ||
709 | ---help--- | ||
710 | This driver adds hotkey monitoring support to some Toshiba models | ||
711 | that manage the hotkeys via WMI events. | ||
712 | |||
713 | WARNING: This driver is incomplete as it lacks a proper keymap and the | ||
714 | *notify function only prints the ACPI event type value. Be warned that | ||
715 | you will need to provide some information if you have a Toshiba model | ||
716 | with WMI event hotkeys and want to help with the develpment of this | ||
717 | driver. | ||
718 | |||
719 | If you have a WMI-based hotkeys Toshiba laptop, say Y or M here. | ||
720 | |||
703 | config ACPI_CMPC | 721 | config ACPI_CMPC |
704 | tristate "CMPC Laptop Extras" | 722 | tristate "CMPC Laptop Extras" |
705 | depends on X86 && ACPI | 723 | depends on X86 && ACPI |
diff --git a/drivers/platform/x86/Makefile b/drivers/platform/x86/Makefile index ada512819028..3ca78a3eb6f8 100644 --- a/drivers/platform/x86/Makefile +++ b/drivers/platform/x86/Makefile | |||
@@ -40,6 +40,7 @@ obj-$(CONFIG_ACPI_TOSHIBA) += toshiba_acpi.o | |||
40 | 40 | ||
41 | obj-$(CONFIG_TOSHIBA_BT_RFKILL) += toshiba_bluetooth.o | 41 | obj-$(CONFIG_TOSHIBA_BT_RFKILL) += toshiba_bluetooth.o |
42 | obj-$(CONFIG_TOSHIBA_HAPS) += toshiba_haps.o | 42 | obj-$(CONFIG_TOSHIBA_HAPS) += toshiba_haps.o |
43 | obj-$(CONFIG_TOSHIBA_WMI) += toshiba-wmi.o | ||
43 | obj-$(CONFIG_INTEL_SCU_IPC) += intel_scu_ipc.o | 44 | obj-$(CONFIG_INTEL_SCU_IPC) += intel_scu_ipc.o |
44 | obj-$(CONFIG_INTEL_SCU_IPC_UTIL) += intel_scu_ipcutil.o | 45 | obj-$(CONFIG_INTEL_SCU_IPC_UTIL) += intel_scu_ipcutil.o |
45 | obj-$(CONFIG_INTEL_MFLD_THERMAL) += intel_mid_thermal.o | 46 | obj-$(CONFIG_INTEL_MFLD_THERMAL) += intel_mid_thermal.o |
diff --git a/drivers/platform/x86/acer-wmi.c b/drivers/platform/x86/acer-wmi.c index d773b9dc48a0..1062fa42ff26 100644 --- a/drivers/platform/x86/acer-wmi.c +++ b/drivers/platform/x86/acer-wmi.c | |||
@@ -1662,58 +1662,6 @@ static void acer_rfkill_exit(void) | |||
1662 | return; | 1662 | return; |
1663 | } | 1663 | } |
1664 | 1664 | ||
1665 | /* | ||
1666 | * sysfs interface | ||
1667 | */ | ||
1668 | static ssize_t show_bool_threeg(struct device *dev, | ||
1669 | struct device_attribute *attr, char *buf) | ||
1670 | { | ||
1671 | u32 result; \ | ||
1672 | acpi_status status; | ||
1673 | |||
1674 | pr_info("This threeg sysfs will be removed in 2014 - used by: %s\n", | ||
1675 | current->comm); | ||
1676 | status = get_u32(&result, ACER_CAP_THREEG); | ||
1677 | if (ACPI_SUCCESS(status)) | ||
1678 | return sprintf(buf, "%u\n", result); | ||
1679 | return sprintf(buf, "Read error\n"); | ||
1680 | } | ||
1681 | |||
1682 | static ssize_t set_bool_threeg(struct device *dev, | ||
1683 | struct device_attribute *attr, const char *buf, size_t count) | ||
1684 | { | ||
1685 | u32 tmp = simple_strtoul(buf, NULL, 10); | ||
1686 | acpi_status status = set_u32(tmp, ACER_CAP_THREEG); | ||
1687 | pr_info("This threeg sysfs will be removed in 2014 - used by: %s\n", | ||
1688 | current->comm); | ||
1689 | if (ACPI_FAILURE(status)) | ||
1690 | return -EINVAL; | ||
1691 | return count; | ||
1692 | } | ||
1693 | static DEVICE_ATTR(threeg, S_IRUGO | S_IWUSR, show_bool_threeg, | ||
1694 | set_bool_threeg); | ||
1695 | |||
1696 | static ssize_t show_interface(struct device *dev, struct device_attribute *attr, | ||
1697 | char *buf) | ||
1698 | { | ||
1699 | pr_info("This interface sysfs will be removed in 2014 - used by: %s\n", | ||
1700 | current->comm); | ||
1701 | switch (interface->type) { | ||
1702 | case ACER_AMW0: | ||
1703 | return sprintf(buf, "AMW0\n"); | ||
1704 | case ACER_AMW0_V2: | ||
1705 | return sprintf(buf, "AMW0 v2\n"); | ||
1706 | case ACER_WMID: | ||
1707 | return sprintf(buf, "WMID\n"); | ||
1708 | case ACER_WMID_v2: | ||
1709 | return sprintf(buf, "WMID v2\n"); | ||
1710 | default: | ||
1711 | return sprintf(buf, "Error!\n"); | ||
1712 | } | ||
1713 | } | ||
1714 | |||
1715 | static DEVICE_ATTR(interface, S_IRUGO, show_interface, NULL); | ||
1716 | |||
1717 | static void acer_wmi_notify(u32 value, void *context) | 1665 | static void acer_wmi_notify(u32 value, void *context) |
1718 | { | 1666 | { |
1719 | struct acpi_buffer response = { ACPI_ALLOCATE_BUFFER, NULL }; | 1667 | struct acpi_buffer response = { ACPI_ALLOCATE_BUFFER, NULL }; |
@@ -2127,39 +2075,6 @@ static struct platform_driver acer_platform_driver = { | |||
2127 | 2075 | ||
2128 | static struct platform_device *acer_platform_device; | 2076 | static struct platform_device *acer_platform_device; |
2129 | 2077 | ||
2130 | static int remove_sysfs(struct platform_device *device) | ||
2131 | { | ||
2132 | if (has_cap(ACER_CAP_THREEG)) | ||
2133 | device_remove_file(&device->dev, &dev_attr_threeg); | ||
2134 | |||
2135 | device_remove_file(&device->dev, &dev_attr_interface); | ||
2136 | |||
2137 | return 0; | ||
2138 | } | ||
2139 | |||
2140 | static int __init create_sysfs(void) | ||
2141 | { | ||
2142 | int retval = -ENOMEM; | ||
2143 | |||
2144 | if (has_cap(ACER_CAP_THREEG)) { | ||
2145 | retval = device_create_file(&acer_platform_device->dev, | ||
2146 | &dev_attr_threeg); | ||
2147 | if (retval) | ||
2148 | goto error_sysfs; | ||
2149 | } | ||
2150 | |||
2151 | retval = device_create_file(&acer_platform_device->dev, | ||
2152 | &dev_attr_interface); | ||
2153 | if (retval) | ||
2154 | goto error_sysfs; | ||
2155 | |||
2156 | return 0; | ||
2157 | |||
2158 | error_sysfs: | ||
2159 | remove_sysfs(acer_platform_device); | ||
2160 | return retval; | ||
2161 | } | ||
2162 | |||
2163 | static void remove_debugfs(void) | 2078 | static void remove_debugfs(void) |
2164 | { | 2079 | { |
2165 | debugfs_remove(interface->debug.devices); | 2080 | debugfs_remove(interface->debug.devices); |
@@ -2290,10 +2205,6 @@ static int __init acer_wmi_init(void) | |||
2290 | if (err) | 2205 | if (err) |
2291 | goto error_device_add; | 2206 | goto error_device_add; |
2292 | 2207 | ||
2293 | err = create_sysfs(); | ||
2294 | if (err) | ||
2295 | goto error_create_sys; | ||
2296 | |||
2297 | if (wmi_has_guid(WMID_GUID2)) { | 2208 | if (wmi_has_guid(WMID_GUID2)) { |
2298 | interface->debug.wmid_devices = get_wmid_devices(); | 2209 | interface->debug.wmid_devices = get_wmid_devices(); |
2299 | err = create_debugfs(); | 2210 | err = create_debugfs(); |
@@ -2307,8 +2218,6 @@ static int __init acer_wmi_init(void) | |||
2307 | return 0; | 2218 | return 0; |
2308 | 2219 | ||
2309 | error_create_debugfs: | 2220 | error_create_debugfs: |
2310 | remove_sysfs(acer_platform_device); | ||
2311 | error_create_sys: | ||
2312 | platform_device_del(acer_platform_device); | 2221 | platform_device_del(acer_platform_device); |
2313 | error_device_add: | 2222 | error_device_add: |
2314 | platform_device_put(acer_platform_device); | 2223 | platform_device_put(acer_platform_device); |
@@ -2331,7 +2240,6 @@ static void __exit acer_wmi_exit(void) | |||
2331 | if (has_cap(ACER_CAP_ACCEL)) | 2240 | if (has_cap(ACER_CAP_ACCEL)) |
2332 | acer_wmi_accel_destroy(); | 2241 | acer_wmi_accel_destroy(); |
2333 | 2242 | ||
2334 | remove_sysfs(acer_platform_device); | ||
2335 | remove_debugfs(); | 2243 | remove_debugfs(); |
2336 | platform_device_unregister(acer_platform_device); | 2244 | platform_device_unregister(acer_platform_device); |
2337 | platform_driver_unregister(&acer_platform_driver); | 2245 | platform_driver_unregister(&acer_platform_driver); |
diff --git a/drivers/platform/x86/asus-wmi.c b/drivers/platform/x86/asus-wmi.c index efbc3f0c592b..1f7d80ff8cb4 100644 --- a/drivers/platform/x86/asus-wmi.c +++ b/drivers/platform/x86/asus-wmi.c | |||
@@ -582,7 +582,7 @@ static void asus_wmi_led_exit(struct asus_wmi *asus) | |||
582 | 582 | ||
583 | static int asus_wmi_led_init(struct asus_wmi *asus) | 583 | static int asus_wmi_led_init(struct asus_wmi *asus) |
584 | { | 584 | { |
585 | int rv = 0; | 585 | int rv = 0, led_val; |
586 | 586 | ||
587 | asus->led_workqueue = create_singlethread_workqueue("led_workqueue"); | 587 | asus->led_workqueue = create_singlethread_workqueue("led_workqueue"); |
588 | if (!asus->led_workqueue) | 588 | if (!asus->led_workqueue) |
@@ -602,9 +602,11 @@ static int asus_wmi_led_init(struct asus_wmi *asus) | |||
602 | goto error; | 602 | goto error; |
603 | } | 603 | } |
604 | 604 | ||
605 | if (kbd_led_read(asus, NULL, NULL) >= 0) { | 605 | led_val = kbd_led_read(asus, NULL, NULL); |
606 | if (led_val >= 0) { | ||
606 | INIT_WORK(&asus->kbd_led_work, kbd_led_update); | 607 | INIT_WORK(&asus->kbd_led_work, kbd_led_update); |
607 | 608 | ||
609 | asus->kbd_led_wk = led_val; | ||
608 | asus->kbd_led.name = "asus::kbd_backlight"; | 610 | asus->kbd_led.name = "asus::kbd_backlight"; |
609 | asus->kbd_led.brightness_set = kbd_led_set; | 611 | asus->kbd_led.brightness_set = kbd_led_set; |
610 | asus->kbd_led.brightness_get = kbd_led_get; | 612 | asus->kbd_led.brightness_get = kbd_led_get; |
@@ -2160,6 +2162,16 @@ static int asus_hotk_thaw(struct device *device) | |||
2160 | return 0; | 2162 | return 0; |
2161 | } | 2163 | } |
2162 | 2164 | ||
2165 | static int asus_hotk_resume(struct device *device) | ||
2166 | { | ||
2167 | struct asus_wmi *asus = dev_get_drvdata(device); | ||
2168 | |||
2169 | if (!IS_ERR_OR_NULL(asus->kbd_led.dev)) | ||
2170 | queue_work(asus->led_workqueue, &asus->kbd_led_work); | ||
2171 | |||
2172 | return 0; | ||
2173 | } | ||
2174 | |||
2163 | static int asus_hotk_restore(struct device *device) | 2175 | static int asus_hotk_restore(struct device *device) |
2164 | { | 2176 | { |
2165 | struct asus_wmi *asus = dev_get_drvdata(device); | 2177 | struct asus_wmi *asus = dev_get_drvdata(device); |
@@ -2190,6 +2202,8 @@ static int asus_hotk_restore(struct device *device) | |||
2190 | bl = !asus_wmi_get_devstate_simple(asus, ASUS_WMI_DEVID_UWB); | 2202 | bl = !asus_wmi_get_devstate_simple(asus, ASUS_WMI_DEVID_UWB); |
2191 | rfkill_set_sw_state(asus->uwb.rfkill, bl); | 2203 | rfkill_set_sw_state(asus->uwb.rfkill, bl); |
2192 | } | 2204 | } |
2205 | if (!IS_ERR_OR_NULL(asus->kbd_led.dev)) | ||
2206 | queue_work(asus->led_workqueue, &asus->kbd_led_work); | ||
2193 | 2207 | ||
2194 | return 0; | 2208 | return 0; |
2195 | } | 2209 | } |
@@ -2197,6 +2211,7 @@ static int asus_hotk_restore(struct device *device) | |||
2197 | static const struct dev_pm_ops asus_pm_ops = { | 2211 | static const struct dev_pm_ops asus_pm_ops = { |
2198 | .thaw = asus_hotk_thaw, | 2212 | .thaw = asus_hotk_thaw, |
2199 | .restore = asus_hotk_restore, | 2213 | .restore = asus_hotk_restore, |
2214 | .resume = asus_hotk_resume, | ||
2200 | }; | 2215 | }; |
2201 | 2216 | ||
2202 | static int asus_wmi_probe(struct platform_device *pdev) | 2217 | static int asus_wmi_probe(struct platform_device *pdev) |
diff --git a/drivers/platform/x86/compal-laptop.c b/drivers/platform/x86/compal-laptop.c index f2706d27adff..e1c2b6d4b24a 100644 --- a/drivers/platform/x86/compal-laptop.c +++ b/drivers/platform/x86/compal-laptop.c | |||
@@ -151,6 +151,8 @@ | |||
151 | #define BAT_STATUS2 0xF1 | 151 | #define BAT_STATUS2 0xF1 |
152 | #define BAT_STOP_CHARGE1 0xF2 | 152 | #define BAT_STOP_CHARGE1 0xF2 |
153 | #define BAT_STOP_CHARGE2 0xF3 | 153 | #define BAT_STOP_CHARGE2 0xF3 |
154 | #define BAT_CHARGE_LIMIT 0x03 | ||
155 | #define BAT_CHARGE_LIMIT_MAX 100 | ||
154 | 156 | ||
155 | #define BAT_S0_DISCHARGE (1 << 0) | 157 | #define BAT_S0_DISCHARGE (1 << 0) |
156 | #define BAT_S0_DISCHRG_CRITICAL (1 << 2) | 158 | #define BAT_S0_DISCHRG_CRITICAL (1 << 2) |
@@ -601,6 +603,12 @@ static int bat_get_property(struct power_supply *psy, | |||
601 | case POWER_SUPPLY_PROP_CHARGE_NOW: | 603 | case POWER_SUPPLY_PROP_CHARGE_NOW: |
602 | val->intval = ec_read_u16(BAT_CHARGE_NOW) * 1000; | 604 | val->intval = ec_read_u16(BAT_CHARGE_NOW) * 1000; |
603 | break; | 605 | break; |
606 | case POWER_SUPPLY_PROP_CHARGE_CONTROL_LIMIT: | ||
607 | val->intval = ec_read_u8(BAT_CHARGE_LIMIT); | ||
608 | break; | ||
609 | case POWER_SUPPLY_PROP_CHARGE_CONTROL_LIMIT_MAX: | ||
610 | val->intval = BAT_CHARGE_LIMIT_MAX; | ||
611 | break; | ||
604 | case POWER_SUPPLY_PROP_CAPACITY: | 612 | case POWER_SUPPLY_PROP_CAPACITY: |
605 | val->intval = ec_read_u8(BAT_CAPACITY); | 613 | val->intval = ec_read_u8(BAT_CAPACITY); |
606 | break; | 614 | break; |
@@ -634,6 +642,36 @@ static int bat_get_property(struct power_supply *psy, | |||
634 | return 0; | 642 | return 0; |
635 | } | 643 | } |
636 | 644 | ||
645 | static int bat_set_property(struct power_supply *psy, | ||
646 | enum power_supply_property psp, | ||
647 | const union power_supply_propval *val) | ||
648 | { | ||
649 | int level; | ||
650 | |||
651 | switch (psp) { | ||
652 | case POWER_SUPPLY_PROP_CHARGE_CONTROL_LIMIT: | ||
653 | level = val->intval; | ||
654 | if (level < 0 || level > BAT_CHARGE_LIMIT_MAX) | ||
655 | return -EINVAL; | ||
656 | if (ec_write(BAT_CHARGE_LIMIT, level) < 0) | ||
657 | return -EIO; | ||
658 | break; | ||
659 | default: | ||
660 | break; | ||
661 | } | ||
662 | return 0; | ||
663 | } | ||
664 | |||
665 | static int bat_writeable_property(struct power_supply *psy, | ||
666 | enum power_supply_property psp) | ||
667 | { | ||
668 | switch (psp) { | ||
669 | case POWER_SUPPLY_PROP_CHARGE_CONTROL_LIMIT: | ||
670 | return 1; | ||
671 | default: | ||
672 | return 0; | ||
673 | } | ||
674 | } | ||
637 | 675 | ||
638 | 676 | ||
639 | 677 | ||
@@ -726,6 +764,8 @@ static enum power_supply_property compal_bat_properties[] = { | |||
726 | POWER_SUPPLY_PROP_POWER_NOW, | 764 | POWER_SUPPLY_PROP_POWER_NOW, |
727 | POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN, | 765 | POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN, |
728 | POWER_SUPPLY_PROP_CHARGE_NOW, | 766 | POWER_SUPPLY_PROP_CHARGE_NOW, |
767 | POWER_SUPPLY_PROP_CHARGE_CONTROL_LIMIT, | ||
768 | POWER_SUPPLY_PROP_CHARGE_CONTROL_LIMIT_MAX, | ||
729 | POWER_SUPPLY_PROP_CAPACITY, | 769 | POWER_SUPPLY_PROP_CAPACITY, |
730 | POWER_SUPPLY_PROP_CAPACITY_LEVEL, | 770 | POWER_SUPPLY_PROP_CAPACITY_LEVEL, |
731 | POWER_SUPPLY_PROP_TEMP, | 771 | POWER_SUPPLY_PROP_TEMP, |
@@ -880,11 +920,12 @@ static const struct power_supply_desc psy_bat_desc = { | |||
880 | .properties = compal_bat_properties, | 920 | .properties = compal_bat_properties, |
881 | .num_properties = ARRAY_SIZE(compal_bat_properties), | 921 | .num_properties = ARRAY_SIZE(compal_bat_properties), |
882 | .get_property = bat_get_property, | 922 | .get_property = bat_get_property, |
923 | .set_property = bat_set_property, | ||
924 | .property_is_writeable = bat_writeable_property, | ||
883 | }; | 925 | }; |
884 | 926 | ||
885 | static void initialize_power_supply_data(struct compal_data *data) | 927 | static void initialize_power_supply_data(struct compal_data *data) |
886 | { | 928 | { |
887 | |||
888 | ec_read_sequence(BAT_MANUFACTURER_NAME_ADDR, | 929 | ec_read_sequence(BAT_MANUFACTURER_NAME_ADDR, |
889 | data->bat_manufacturer_name, | 930 | data->bat_manufacturer_name, |
890 | BAT_MANUFACTURER_NAME_LEN); | 931 | BAT_MANUFACTURER_NAME_LEN); |
diff --git a/drivers/platform/x86/intel_mid_powerbtn.c b/drivers/platform/x86/intel_mid_powerbtn.c index 22606d6b2af3..1fc0de870ff8 100644 --- a/drivers/platform/x86/intel_mid_powerbtn.c +++ b/drivers/platform/x86/intel_mid_powerbtn.c | |||
@@ -24,6 +24,7 @@ | |||
24 | #include <linux/platform_device.h> | 24 | #include <linux/platform_device.h> |
25 | #include <linux/input.h> | 25 | #include <linux/input.h> |
26 | #include <linux/mfd/intel_msic.h> | 26 | #include <linux/mfd/intel_msic.h> |
27 | #include <linux/pm_wakeirq.h> | ||
27 | 28 | ||
28 | #define DRIVER_NAME "msic_power_btn" | 29 | #define DRIVER_NAME "msic_power_btn" |
29 | 30 | ||
@@ -76,14 +77,17 @@ static int mfld_pb_probe(struct platform_device *pdev) | |||
76 | 77 | ||
77 | input_set_capability(input, EV_KEY, KEY_POWER); | 78 | input_set_capability(input, EV_KEY, KEY_POWER); |
78 | 79 | ||
79 | error = request_threaded_irq(irq, NULL, mfld_pb_isr, IRQF_NO_SUSPEND, | 80 | error = request_threaded_irq(irq, NULL, mfld_pb_isr, 0, |
80 | DRIVER_NAME, input); | 81 | DRIVER_NAME, input); |
81 | if (error) { | 82 | if (error) { |
82 | dev_err(&pdev->dev, "Unable to request irq %d for mfld power" | 83 | dev_err(&pdev->dev, "Unable to request irq %d for mfld power" |
83 | "button\n", irq); | 84 | "button\n", irq); |
84 | goto err_free_input; | 85 | goto err_free_input; |
85 | } | 86 | } |
86 | 87 | ||
88 | device_init_wakeup(&pdev->dev, true); | ||
89 | dev_pm_set_wake_irq(&pdev->dev, irq); | ||
90 | |||
87 | error = input_register_device(input); | 91 | error = input_register_device(input); |
88 | if (error) { | 92 | if (error) { |
89 | dev_err(&pdev->dev, "Unable to register input dev, error " | 93 | dev_err(&pdev->dev, "Unable to register input dev, error " |
@@ -124,6 +128,8 @@ static int mfld_pb_remove(struct platform_device *pdev) | |||
124 | struct input_dev *input = platform_get_drvdata(pdev); | 128 | struct input_dev *input = platform_get_drvdata(pdev); |
125 | int irq = platform_get_irq(pdev, 0); | 129 | int irq = platform_get_irq(pdev, 0); |
126 | 130 | ||
131 | dev_pm_clear_wake_irq(&pdev->dev); | ||
132 | device_init_wakeup(&pdev->dev, false); | ||
127 | free_irq(irq, input); | 133 | free_irq(irq, input); |
128 | input_unregister_device(input); | 134 | input_unregister_device(input); |
129 | 135 | ||
diff --git a/drivers/platform/x86/intel_scu_ipc.c b/drivers/platform/x86/intel_scu_ipc.c index 187d1086d15c..f94b730540e2 100644 --- a/drivers/platform/x86/intel_scu_ipc.c +++ b/drivers/platform/x86/intel_scu_ipc.c | |||
@@ -92,11 +92,8 @@ static struct intel_scu_ipc_pdata_t intel_scu_ipc_tangier_pdata = { | |||
92 | .irq_mode = 0, | 92 | .irq_mode = 0, |
93 | }; | 93 | }; |
94 | 94 | ||
95 | static int ipc_probe(struct pci_dev *dev, const struct pci_device_id *id); | ||
96 | static void ipc_remove(struct pci_dev *pdev); | ||
97 | |||
98 | struct intel_scu_ipc_dev { | 95 | struct intel_scu_ipc_dev { |
99 | struct pci_dev *pdev; | 96 | struct device *dev; |
100 | void __iomem *ipc_base; | 97 | void __iomem *ipc_base; |
101 | void __iomem *i2c_base; | 98 | void __iomem *i2c_base; |
102 | struct completion cmd_complete; | 99 | struct completion cmd_complete; |
@@ -118,28 +115,30 @@ static struct intel_scu_ipc_dev ipcdev; /* Only one for now */ | |||
118 | static DEFINE_MUTEX(ipclock); /* lock used to prevent multiple call to SCU */ | 115 | static DEFINE_MUTEX(ipclock); /* lock used to prevent multiple call to SCU */ |
119 | 116 | ||
120 | /* | 117 | /* |
118 | * Send ipc command | ||
121 | * Command Register (Write Only): | 119 | * Command Register (Write Only): |
122 | * A write to this register results in an interrupt to the SCU core processor | 120 | * A write to this register results in an interrupt to the SCU core processor |
123 | * Format: | 121 | * Format: |
124 | * |rfu2(8) | size(8) | command id(4) | rfu1(3) | ioc(1) | command(8)| | 122 | * |rfu2(8) | size(8) | command id(4) | rfu1(3) | ioc(1) | command(8)| |
125 | */ | 123 | */ |
126 | static inline void ipc_command(u32 cmd) /* Send ipc command */ | 124 | static inline void ipc_command(struct intel_scu_ipc_dev *scu, u32 cmd) |
127 | { | 125 | { |
128 | if (ipcdev.irq_mode) { | 126 | if (scu->irq_mode) { |
129 | reinit_completion(&ipcdev.cmd_complete); | 127 | reinit_completion(&scu->cmd_complete); |
130 | writel(cmd | IPC_IOC, ipcdev.ipc_base); | 128 | writel(cmd | IPC_IOC, scu->ipc_base); |
131 | } | 129 | } |
132 | writel(cmd, ipcdev.ipc_base); | 130 | writel(cmd, scu->ipc_base); |
133 | } | 131 | } |
134 | 132 | ||
135 | /* | 133 | /* |
134 | * Write ipc data | ||
136 | * IPC Write Buffer (Write Only): | 135 | * IPC Write Buffer (Write Only): |
137 | * 16-byte buffer for sending data associated with IPC command to | 136 | * 16-byte buffer for sending data associated with IPC command to |
138 | * SCU. Size of the data is specified in the IPC_COMMAND_REG register | 137 | * SCU. Size of the data is specified in the IPC_COMMAND_REG register |
139 | */ | 138 | */ |
140 | static inline void ipc_data_writel(u32 data, u32 offset) /* Write ipc data */ | 139 | static inline void ipc_data_writel(struct intel_scu_ipc_dev *scu, u32 data, u32 offset) |
141 | { | 140 | { |
142 | writel(data, ipcdev.ipc_base + 0x80 + offset); | 141 | writel(data, scu->ipc_base + 0x80 + offset); |
143 | } | 142 | } |
144 | 143 | ||
145 | /* | 144 | /* |
@@ -149,35 +148,37 @@ static inline void ipc_data_writel(u32 data, u32 offset) /* Write ipc data */ | |||
149 | * Format: | 148 | * Format: |
150 | * |rfu3(8)|error code(8)|initiator id(8)|cmd id(4)|rfu1(2)|error(1)|busy(1)| | 149 | * |rfu3(8)|error code(8)|initiator id(8)|cmd id(4)|rfu1(2)|error(1)|busy(1)| |
151 | */ | 150 | */ |
152 | static inline u8 ipc_read_status(void) | 151 | static inline u8 ipc_read_status(struct intel_scu_ipc_dev *scu) |
153 | { | 152 | { |
154 | return __raw_readl(ipcdev.ipc_base + 0x04); | 153 | return __raw_readl(scu->ipc_base + 0x04); |
155 | } | 154 | } |
156 | 155 | ||
157 | static inline u8 ipc_data_readb(u32 offset) /* Read ipc byte data */ | 156 | /* Read ipc byte data */ |
157 | static inline u8 ipc_data_readb(struct intel_scu_ipc_dev *scu, u32 offset) | ||
158 | { | 158 | { |
159 | return readb(ipcdev.ipc_base + IPC_READ_BUFFER + offset); | 159 | return readb(scu->ipc_base + IPC_READ_BUFFER + offset); |
160 | } | 160 | } |
161 | 161 | ||
162 | static inline u32 ipc_data_readl(u32 offset) /* Read ipc u32 data */ | 162 | /* Read ipc u32 data */ |
163 | static inline u32 ipc_data_readl(struct intel_scu_ipc_dev *scu, u32 offset) | ||
163 | { | 164 | { |
164 | return readl(ipcdev.ipc_base + IPC_READ_BUFFER + offset); | 165 | return readl(scu->ipc_base + IPC_READ_BUFFER + offset); |
165 | } | 166 | } |
166 | 167 | ||
167 | /* Wait till scu status is busy */ | 168 | /* Wait till scu status is busy */ |
168 | static inline int busy_loop(void) | 169 | static inline int busy_loop(struct intel_scu_ipc_dev *scu) |
169 | { | 170 | { |
170 | u32 status = ipc_read_status(); | 171 | u32 status = ipc_read_status(scu); |
171 | u32 loop_count = 100000; | 172 | u32 loop_count = 100000; |
172 | 173 | ||
173 | /* break if scu doesn't reset busy bit after huge retry */ | 174 | /* break if scu doesn't reset busy bit after huge retry */ |
174 | while ((status & BIT(0)) && --loop_count) { | 175 | while ((status & BIT(0)) && --loop_count) { |
175 | udelay(1); /* scu processing time is in few u secods */ | 176 | udelay(1); /* scu processing time is in few u secods */ |
176 | status = ipc_read_status(); | 177 | status = ipc_read_status(scu); |
177 | } | 178 | } |
178 | 179 | ||
179 | if (status & BIT(0)) { | 180 | if (status & BIT(0)) { |
180 | dev_err(&ipcdev.pdev->dev, "IPC timed out"); | 181 | dev_err(scu->dev, "IPC timed out"); |
181 | return -ETIMEDOUT; | 182 | return -ETIMEDOUT; |
182 | } | 183 | } |
183 | 184 | ||
@@ -188,31 +189,31 @@ static inline int busy_loop(void) | |||
188 | } | 189 | } |
189 | 190 | ||
190 | /* Wait till ipc ioc interrupt is received or timeout in 3 HZ */ | 191 | /* Wait till ipc ioc interrupt is received or timeout in 3 HZ */ |
191 | static inline int ipc_wait_for_interrupt(void) | 192 | static inline int ipc_wait_for_interrupt(struct intel_scu_ipc_dev *scu) |
192 | { | 193 | { |
193 | int status; | 194 | int status; |
194 | 195 | ||
195 | if (!wait_for_completion_timeout(&ipcdev.cmd_complete, 3 * HZ)) { | 196 | if (!wait_for_completion_timeout(&scu->cmd_complete, 3 * HZ)) { |
196 | struct device *dev = &ipcdev.pdev->dev; | 197 | dev_err(scu->dev, "IPC timed out\n"); |
197 | dev_err(dev, "IPC timed out\n"); | ||
198 | return -ETIMEDOUT; | 198 | return -ETIMEDOUT; |
199 | } | 199 | } |
200 | 200 | ||
201 | status = ipc_read_status(); | 201 | status = ipc_read_status(scu); |
202 | if (status & BIT(1)) | 202 | if (status & BIT(1)) |
203 | return -EIO; | 203 | return -EIO; |
204 | 204 | ||
205 | return 0; | 205 | return 0; |
206 | } | 206 | } |
207 | 207 | ||
208 | static int intel_scu_ipc_check_status(void) | 208 | static int intel_scu_ipc_check_status(struct intel_scu_ipc_dev *scu) |
209 | { | 209 | { |
210 | return ipcdev.irq_mode ? ipc_wait_for_interrupt() : busy_loop(); | 210 | return scu->irq_mode ? ipc_wait_for_interrupt(scu) : busy_loop(scu); |
211 | } | 211 | } |
212 | 212 | ||
213 | /* Read/Write power control(PMIC in Langwell, MSIC in PenWell) registers */ | 213 | /* Read/Write power control(PMIC in Langwell, MSIC in PenWell) registers */ |
214 | static int pwr_reg_rdwr(u16 *addr, u8 *data, u32 count, u32 op, u32 id) | 214 | static int pwr_reg_rdwr(u16 *addr, u8 *data, u32 count, u32 op, u32 id) |
215 | { | 215 | { |
216 | struct intel_scu_ipc_dev *scu = &ipcdev; | ||
216 | int nc; | 217 | int nc; |
217 | u32 offset = 0; | 218 | u32 offset = 0; |
218 | int err; | 219 | int err; |
@@ -223,7 +224,7 @@ static int pwr_reg_rdwr(u16 *addr, u8 *data, u32 count, u32 op, u32 id) | |||
223 | 224 | ||
224 | mutex_lock(&ipclock); | 225 | mutex_lock(&ipclock); |
225 | 226 | ||
226 | if (ipcdev.pdev == NULL) { | 227 | if (scu->dev == NULL) { |
227 | mutex_unlock(&ipclock); | 228 | mutex_unlock(&ipclock); |
228 | return -ENODEV; | 229 | return -ENODEV; |
229 | } | 230 | } |
@@ -235,27 +236,27 @@ static int pwr_reg_rdwr(u16 *addr, u8 *data, u32 count, u32 op, u32 id) | |||
235 | 236 | ||
236 | if (id == IPC_CMD_PCNTRL_R) { | 237 | if (id == IPC_CMD_PCNTRL_R) { |
237 | for (nc = 0, offset = 0; nc < count; nc++, offset += 4) | 238 | for (nc = 0, offset = 0; nc < count; nc++, offset += 4) |
238 | ipc_data_writel(wbuf[nc], offset); | 239 | ipc_data_writel(scu, wbuf[nc], offset); |
239 | ipc_command((count * 2) << 16 | id << 12 | 0 << 8 | op); | 240 | ipc_command(scu, (count * 2) << 16 | id << 12 | 0 << 8 | op); |
240 | } else if (id == IPC_CMD_PCNTRL_W) { | 241 | } else if (id == IPC_CMD_PCNTRL_W) { |
241 | for (nc = 0; nc < count; nc++, offset += 1) | 242 | for (nc = 0; nc < count; nc++, offset += 1) |
242 | cbuf[offset] = data[nc]; | 243 | cbuf[offset] = data[nc]; |
243 | for (nc = 0, offset = 0; nc < count; nc++, offset += 4) | 244 | for (nc = 0, offset = 0; nc < count; nc++, offset += 4) |
244 | ipc_data_writel(wbuf[nc], offset); | 245 | ipc_data_writel(scu, wbuf[nc], offset); |
245 | ipc_command((count * 3) << 16 | id << 12 | 0 << 8 | op); | 246 | ipc_command(scu, (count * 3) << 16 | id << 12 | 0 << 8 | op); |
246 | } else if (id == IPC_CMD_PCNTRL_M) { | 247 | } else if (id == IPC_CMD_PCNTRL_M) { |
247 | cbuf[offset] = data[0]; | 248 | cbuf[offset] = data[0]; |
248 | cbuf[offset + 1] = data[1]; | 249 | cbuf[offset + 1] = data[1]; |
249 | ipc_data_writel(wbuf[0], 0); /* Write wbuff */ | 250 | ipc_data_writel(scu, wbuf[0], 0); /* Write wbuff */ |
250 | ipc_command(4 << 16 | id << 12 | 0 << 8 | op); | 251 | ipc_command(scu, 4 << 16 | id << 12 | 0 << 8 | op); |
251 | } | 252 | } |
252 | 253 | ||
253 | err = intel_scu_ipc_check_status(); | 254 | err = intel_scu_ipc_check_status(scu); |
254 | if (!err && id == IPC_CMD_PCNTRL_R) { /* Read rbuf */ | 255 | if (!err && id == IPC_CMD_PCNTRL_R) { /* Read rbuf */ |
255 | /* Workaround: values are read as 0 without memcpy_fromio */ | 256 | /* Workaround: values are read as 0 without memcpy_fromio */ |
256 | memcpy_fromio(cbuf, ipcdev.ipc_base + 0x90, 16); | 257 | memcpy_fromio(cbuf, scu->ipc_base + 0x90, 16); |
257 | for (nc = 0; nc < count; nc++) | 258 | for (nc = 0; nc < count; nc++) |
258 | data[nc] = ipc_data_readb(nc); | 259 | data[nc] = ipc_data_readb(scu, nc); |
259 | } | 260 | } |
260 | mutex_unlock(&ipclock); | 261 | mutex_unlock(&ipclock); |
261 | return err; | 262 | return err; |
@@ -436,15 +437,16 @@ EXPORT_SYMBOL(intel_scu_ipc_update_register); | |||
436 | */ | 437 | */ |
437 | int intel_scu_ipc_simple_command(int cmd, int sub) | 438 | int intel_scu_ipc_simple_command(int cmd, int sub) |
438 | { | 439 | { |
440 | struct intel_scu_ipc_dev *scu = &ipcdev; | ||
439 | int err; | 441 | int err; |
440 | 442 | ||
441 | mutex_lock(&ipclock); | 443 | mutex_lock(&ipclock); |
442 | if (ipcdev.pdev == NULL) { | 444 | if (scu->dev == NULL) { |
443 | mutex_unlock(&ipclock); | 445 | mutex_unlock(&ipclock); |
444 | return -ENODEV; | 446 | return -ENODEV; |
445 | } | 447 | } |
446 | ipc_command(sub << 12 | cmd); | 448 | ipc_command(scu, sub << 12 | cmd); |
447 | err = intel_scu_ipc_check_status(); | 449 | err = intel_scu_ipc_check_status(scu); |
448 | mutex_unlock(&ipclock); | 450 | mutex_unlock(&ipclock); |
449 | return err; | 451 | return err; |
450 | } | 452 | } |
@@ -465,23 +467,24 @@ EXPORT_SYMBOL(intel_scu_ipc_simple_command); | |||
465 | int intel_scu_ipc_command(int cmd, int sub, u32 *in, int inlen, | 467 | int intel_scu_ipc_command(int cmd, int sub, u32 *in, int inlen, |
466 | u32 *out, int outlen) | 468 | u32 *out, int outlen) |
467 | { | 469 | { |
470 | struct intel_scu_ipc_dev *scu = &ipcdev; | ||
468 | int i, err; | 471 | int i, err; |
469 | 472 | ||
470 | mutex_lock(&ipclock); | 473 | mutex_lock(&ipclock); |
471 | if (ipcdev.pdev == NULL) { | 474 | if (scu->dev == NULL) { |
472 | mutex_unlock(&ipclock); | 475 | mutex_unlock(&ipclock); |
473 | return -ENODEV; | 476 | return -ENODEV; |
474 | } | 477 | } |
475 | 478 | ||
476 | for (i = 0; i < inlen; i++) | 479 | for (i = 0; i < inlen; i++) |
477 | ipc_data_writel(*in++, 4 * i); | 480 | ipc_data_writel(scu, *in++, 4 * i); |
478 | 481 | ||
479 | ipc_command((inlen << 16) | (sub << 12) | cmd); | 482 | ipc_command(scu, (inlen << 16) | (sub << 12) | cmd); |
480 | err = intel_scu_ipc_check_status(); | 483 | err = intel_scu_ipc_check_status(scu); |
481 | 484 | ||
482 | if (!err) { | 485 | if (!err) { |
483 | for (i = 0; i < outlen; i++) | 486 | for (i = 0; i < outlen; i++) |
484 | *out++ = ipc_data_readl(4 * i); | 487 | *out++ = ipc_data_readl(scu, 4 * i); |
485 | } | 488 | } |
486 | 489 | ||
487 | mutex_unlock(&ipclock); | 490 | mutex_unlock(&ipclock); |
@@ -507,25 +510,26 @@ EXPORT_SYMBOL(intel_scu_ipc_command); | |||
507 | */ | 510 | */ |
508 | int intel_scu_ipc_i2c_cntrl(u32 addr, u32 *data) | 511 | int intel_scu_ipc_i2c_cntrl(u32 addr, u32 *data) |
509 | { | 512 | { |
513 | struct intel_scu_ipc_dev *scu = &ipcdev; | ||
510 | u32 cmd = 0; | 514 | u32 cmd = 0; |
511 | 515 | ||
512 | mutex_lock(&ipclock); | 516 | mutex_lock(&ipclock); |
513 | if (ipcdev.pdev == NULL) { | 517 | if (scu->dev == NULL) { |
514 | mutex_unlock(&ipclock); | 518 | mutex_unlock(&ipclock); |
515 | return -ENODEV; | 519 | return -ENODEV; |
516 | } | 520 | } |
517 | cmd = (addr >> 24) & 0xFF; | 521 | cmd = (addr >> 24) & 0xFF; |
518 | if (cmd == IPC_I2C_READ) { | 522 | if (cmd == IPC_I2C_READ) { |
519 | writel(addr, ipcdev.i2c_base + IPC_I2C_CNTRL_ADDR); | 523 | writel(addr, scu->i2c_base + IPC_I2C_CNTRL_ADDR); |
520 | /* Write not getting updated without delay */ | 524 | /* Write not getting updated without delay */ |
521 | mdelay(1); | 525 | mdelay(1); |
522 | *data = readl(ipcdev.i2c_base + I2C_DATA_ADDR); | 526 | *data = readl(scu->i2c_base + I2C_DATA_ADDR); |
523 | } else if (cmd == IPC_I2C_WRITE) { | 527 | } else if (cmd == IPC_I2C_WRITE) { |
524 | writel(*data, ipcdev.i2c_base + I2C_DATA_ADDR); | 528 | writel(*data, scu->i2c_base + I2C_DATA_ADDR); |
525 | mdelay(1); | 529 | mdelay(1); |
526 | writel(addr, ipcdev.i2c_base + IPC_I2C_CNTRL_ADDR); | 530 | writel(addr, scu->i2c_base + IPC_I2C_CNTRL_ADDR); |
527 | } else { | 531 | } else { |
528 | dev_err(&ipcdev.pdev->dev, | 532 | dev_err(scu->dev, |
529 | "intel_scu_ipc: I2C INVALID_CMD = 0x%x\n", cmd); | 533 | "intel_scu_ipc: I2C INVALID_CMD = 0x%x\n", cmd); |
530 | 534 | ||
531 | mutex_unlock(&ipclock); | 535 | mutex_unlock(&ipclock); |
@@ -545,63 +549,65 @@ EXPORT_SYMBOL(intel_scu_ipc_i2c_cntrl); | |||
545 | */ | 549 | */ |
546 | static irqreturn_t ioc(int irq, void *dev_id) | 550 | static irqreturn_t ioc(int irq, void *dev_id) |
547 | { | 551 | { |
548 | if (ipcdev.irq_mode) | 552 | struct intel_scu_ipc_dev *scu = dev_id; |
549 | complete(&ipcdev.cmd_complete); | 553 | |
554 | if (scu->irq_mode) | ||
555 | complete(&scu->cmd_complete); | ||
550 | 556 | ||
551 | return IRQ_HANDLED; | 557 | return IRQ_HANDLED; |
552 | } | 558 | } |
553 | 559 | ||
554 | /** | 560 | /** |
555 | * ipc_probe - probe an Intel SCU IPC | 561 | * ipc_probe - probe an Intel SCU IPC |
556 | * @dev: the PCI device matching | 562 | * @pdev: the PCI device matching |
557 | * @id: entry in the match table | 563 | * @id: entry in the match table |
558 | * | 564 | * |
559 | * Enable and install an intel SCU IPC. This appears in the PCI space | 565 | * Enable and install an intel SCU IPC. This appears in the PCI space |
560 | * but uses some hard coded addresses as well. | 566 | * but uses some hard coded addresses as well. |
561 | */ | 567 | */ |
562 | static int ipc_probe(struct pci_dev *dev, const struct pci_device_id *id) | 568 | static int ipc_probe(struct pci_dev *pdev, const struct pci_device_id *id) |
563 | { | 569 | { |
570 | int platform; /* Platform type */ | ||
564 | int err; | 571 | int err; |
572 | struct intel_scu_ipc_dev *scu = &ipcdev; | ||
565 | struct intel_scu_ipc_pdata_t *pdata; | 573 | struct intel_scu_ipc_pdata_t *pdata; |
566 | resource_size_t base; | ||
567 | 574 | ||
568 | if (ipcdev.pdev) /* We support only one SCU */ | 575 | platform = intel_mid_identify_cpu(); |
576 | if (platform == 0) | ||
577 | return -ENODEV; | ||
578 | |||
579 | if (scu->dev) /* We support only one SCU */ | ||
569 | return -EBUSY; | 580 | return -EBUSY; |
570 | 581 | ||
571 | pdata = (struct intel_scu_ipc_pdata_t *)id->driver_data; | 582 | pdata = (struct intel_scu_ipc_pdata_t *)id->driver_data; |
572 | 583 | ||
573 | ipcdev.pdev = pci_dev_get(dev); | 584 | scu->dev = &pdev->dev; |
574 | ipcdev.irq_mode = pdata->irq_mode; | 585 | scu->irq_mode = pdata->irq_mode; |
575 | 586 | ||
576 | err = pci_enable_device(dev); | 587 | err = pcim_enable_device(pdev); |
577 | if (err) | 588 | if (err) |
578 | return err; | 589 | return err; |
579 | 590 | ||
580 | err = pci_request_regions(dev, "intel_scu_ipc"); | 591 | err = pcim_iomap_regions(pdev, 1 << 0, pci_name(pdev)); |
581 | if (err) | 592 | if (err) |
582 | return err; | 593 | return err; |
583 | 594 | ||
584 | base = pci_resource_start(dev, 0); | 595 | init_completion(&scu->cmd_complete); |
585 | if (!base) | ||
586 | return -ENOMEM; | ||
587 | 596 | ||
588 | init_completion(&ipcdev.cmd_complete); | 597 | err = devm_request_irq(&pdev->dev, pdev->irq, ioc, 0, "intel_scu_ipc", |
598 | scu); | ||
599 | if (err) | ||
600 | return err; | ||
589 | 601 | ||
590 | if (request_irq(dev->irq, ioc, 0, "intel_scu_ipc", &ipcdev)) | 602 | scu->ipc_base = pcim_iomap_table(pdev)[0]; |
591 | return -EBUSY; | ||
592 | 603 | ||
593 | ipcdev.ipc_base = ioremap_nocache(base, pci_resource_len(dev, 0)); | 604 | scu->i2c_base = ioremap_nocache(pdata->i2c_base, pdata->i2c_len); |
594 | if (!ipcdev.ipc_base) | 605 | if (!scu->i2c_base) |
595 | return -ENOMEM; | 606 | return -ENOMEM; |
596 | 607 | ||
597 | ipcdev.i2c_base = ioremap_nocache(pdata->i2c_base, pdata->i2c_len); | ||
598 | if (!ipcdev.i2c_base) { | ||
599 | iounmap(ipcdev.ipc_base); | ||
600 | return -ENOMEM; | ||
601 | } | ||
602 | |||
603 | intel_scu_devices_create(); | 608 | intel_scu_devices_create(); |
604 | 609 | ||
610 | pci_set_drvdata(pdev, scu); | ||
605 | return 0; | 611 | return 0; |
606 | } | 612 | } |
607 | 613 | ||
@@ -617,12 +623,13 @@ static int ipc_probe(struct pci_dev *dev, const struct pci_device_id *id) | |||
617 | */ | 623 | */ |
618 | static void ipc_remove(struct pci_dev *pdev) | 624 | static void ipc_remove(struct pci_dev *pdev) |
619 | { | 625 | { |
620 | free_irq(pdev->irq, &ipcdev); | 626 | struct intel_scu_ipc_dev *scu = pci_get_drvdata(pdev); |
621 | pci_release_regions(pdev); | 627 | |
622 | pci_dev_put(ipcdev.pdev); | 628 | mutex_lock(&ipclock); |
623 | iounmap(ipcdev.ipc_base); | 629 | scu->dev = NULL; |
624 | iounmap(ipcdev.i2c_base); | 630 | mutex_unlock(&ipclock); |
625 | ipcdev.pdev = NULL; | 631 | |
632 | iounmap(scu->i2c_base); | ||
626 | intel_scu_devices_destroy(); | 633 | intel_scu_devices_destroy(); |
627 | } | 634 | } |
628 | 635 | ||
@@ -652,24 +659,8 @@ static struct pci_driver ipc_driver = { | |||
652 | .remove = ipc_remove, | 659 | .remove = ipc_remove, |
653 | }; | 660 | }; |
654 | 661 | ||
655 | static int __init intel_scu_ipc_init(void) | 662 | module_pci_driver(ipc_driver); |
656 | { | ||
657 | int platform; /* Platform type */ | ||
658 | |||
659 | platform = intel_mid_identify_cpu(); | ||
660 | if (platform == 0) | ||
661 | return -ENODEV; | ||
662 | return pci_register_driver(&ipc_driver); | ||
663 | } | ||
664 | |||
665 | static void __exit intel_scu_ipc_exit(void) | ||
666 | { | ||
667 | pci_unregister_driver(&ipc_driver); | ||
668 | } | ||
669 | 663 | ||
670 | MODULE_AUTHOR("Sreedhara DS <sreedhara.ds@intel.com>"); | 664 | MODULE_AUTHOR("Sreedhara DS <sreedhara.ds@intel.com>"); |
671 | MODULE_DESCRIPTION("Intel SCU IPC driver"); | 665 | MODULE_DESCRIPTION("Intel SCU IPC driver"); |
672 | MODULE_LICENSE("GPL"); | 666 | MODULE_LICENSE("GPL"); |
673 | |||
674 | module_init(intel_scu_ipc_init); | ||
675 | module_exit(intel_scu_ipc_exit); | ||
diff --git a/drivers/platform/x86/sony-laptop.c b/drivers/platform/x86/sony-laptop.c index aeb80d1c2b07..f73c29558cd3 100644 --- a/drivers/platform/x86/sony-laptop.c +++ b/drivers/platform/x86/sony-laptop.c | |||
@@ -1204,6 +1204,8 @@ static void sony_nc_notify(struct acpi_device *device, u32 event) | |||
1204 | { | 1204 | { |
1205 | u32 real_ev = event; | 1205 | u32 real_ev = event; |
1206 | u8 ev_type = 0; | 1206 | u8 ev_type = 0; |
1207 | int ret; | ||
1208 | |||
1207 | dprintk("sony_nc_notify, event: 0x%.2x\n", event); | 1209 | dprintk("sony_nc_notify, event: 0x%.2x\n", event); |
1208 | 1210 | ||
1209 | if (event >= 0x90) { | 1211 | if (event >= 0x90) { |
@@ -1225,13 +1227,12 @@ static void sony_nc_notify(struct acpi_device *device, u32 event) | |||
1225 | case 0x0100: | 1227 | case 0x0100: |
1226 | case 0x0127: | 1228 | case 0x0127: |
1227 | ev_type = HOTKEY; | 1229 | ev_type = HOTKEY; |
1228 | real_ev = sony_nc_hotkeys_decode(event, handle); | 1230 | ret = sony_nc_hotkeys_decode(event, handle); |
1229 | 1231 | ||
1230 | if (real_ev > 0) | 1232 | if (ret > 0) { |
1231 | sony_laptop_report_input_event(real_ev); | 1233 | sony_laptop_report_input_event(ret); |
1232 | else | 1234 | real_ev = ret; |
1233 | /* restore the original event for reporting */ | 1235 | } |
1234 | real_ev = event; | ||
1235 | 1236 | ||
1236 | break; | 1237 | break; |
1237 | 1238 | ||
diff --git a/drivers/platform/x86/toshiba-wmi.c b/drivers/platform/x86/toshiba-wmi.c new file mode 100644 index 000000000000..feac4576b837 --- /dev/null +++ b/drivers/platform/x86/toshiba-wmi.c | |||
@@ -0,0 +1,138 @@ | |||
1 | /* | ||
2 | * toshiba_wmi.c - Toshiba WMI Hotkey Driver | ||
3 | * | ||
4 | * Copyright (C) 2015 Azael Avalos <coproscefalo@gmail.com> | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or modify | ||
7 | * it under the terms of the GNU General Public License as published by | ||
8 | * the Free Software Foundation; either version 2 of the License, or | ||
9 | * (at your option) any later version. | ||
10 | * | ||
11 | * This program is distributed in the hope that it will be useful, | ||
12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
14 | * GNU General Public License for more details. | ||
15 | * | ||
16 | */ | ||
17 | |||
18 | #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt | ||
19 | |||
20 | #include <linux/kernel.h> | ||
21 | #include <linux/module.h> | ||
22 | #include <linux/init.h> | ||
23 | #include <linux/types.h> | ||
24 | #include <linux/acpi.h> | ||
25 | #include <linux/input.h> | ||
26 | #include <linux/input/sparse-keymap.h> | ||
27 | |||
28 | MODULE_AUTHOR("Azael Avalos"); | ||
29 | MODULE_DESCRIPTION("Toshiba WMI Hotkey Driver"); | ||
30 | MODULE_LICENSE("GPL"); | ||
31 | |||
32 | #define TOSHIBA_WMI_EVENT_GUID "59142400-C6A3-40FA-BADB-8A2652834100" | ||
33 | |||
34 | MODULE_ALIAS("wmi:"TOSHIBA_WMI_EVENT_GUID); | ||
35 | |||
36 | static struct input_dev *toshiba_wmi_input_dev; | ||
37 | |||
38 | static const struct key_entry toshiba_wmi_keymap[] __initconst = { | ||
39 | /* TODO: Add keymap values once found... */ | ||
40 | /*{ KE_KEY, 0x00, { KEY_ } },*/ | ||
41 | { KE_END, 0 } | ||
42 | }; | ||
43 | |||
44 | static void toshiba_wmi_notify(u32 value, void *context) | ||
45 | { | ||
46 | struct acpi_buffer response = { ACPI_ALLOCATE_BUFFER, NULL }; | ||
47 | union acpi_object *obj; | ||
48 | acpi_status status; | ||
49 | |||
50 | status = wmi_get_event_data(value, &response); | ||
51 | if (ACPI_FAILURE(status)) { | ||
52 | pr_err("Bad event status 0x%x\n", status); | ||
53 | return; | ||
54 | } | ||
55 | |||
56 | obj = (union acpi_object *)response.pointer; | ||
57 | if (!obj) | ||
58 | return; | ||
59 | |||
60 | /* TODO: Add proper checks once we have data */ | ||
61 | pr_debug("Unknown event received, obj type %x\n", obj->type); | ||
62 | |||
63 | kfree(response.pointer); | ||
64 | } | ||
65 | |||
66 | static int __init toshiba_wmi_input_setup(void) | ||
67 | { | ||
68 | acpi_status status; | ||
69 | int err; | ||
70 | |||
71 | toshiba_wmi_input_dev = input_allocate_device(); | ||
72 | if (!toshiba_wmi_input_dev) | ||
73 | return -ENOMEM; | ||
74 | |||
75 | toshiba_wmi_input_dev->name = "Toshiba WMI hotkeys"; | ||
76 | toshiba_wmi_input_dev->phys = "wmi/input0"; | ||
77 | toshiba_wmi_input_dev->id.bustype = BUS_HOST; | ||
78 | |||
79 | err = sparse_keymap_setup(toshiba_wmi_input_dev, | ||
80 | toshiba_wmi_keymap, NULL); | ||
81 | if (err) | ||
82 | goto err_free_dev; | ||
83 | |||
84 | status = wmi_install_notify_handler(TOSHIBA_WMI_EVENT_GUID, | ||
85 | toshiba_wmi_notify, NULL); | ||
86 | if (ACPI_FAILURE(status)) { | ||
87 | err = -EIO; | ||
88 | goto err_free_keymap; | ||
89 | } | ||
90 | |||
91 | err = input_register_device(toshiba_wmi_input_dev); | ||
92 | if (err) | ||
93 | goto err_remove_notifier; | ||
94 | |||
95 | return 0; | ||
96 | |||
97 | err_remove_notifier: | ||
98 | wmi_remove_notify_handler(TOSHIBA_WMI_EVENT_GUID); | ||
99 | err_free_keymap: | ||
100 | sparse_keymap_free(toshiba_wmi_input_dev); | ||
101 | err_free_dev: | ||
102 | input_free_device(toshiba_wmi_input_dev); | ||
103 | return err; | ||
104 | } | ||
105 | |||
106 | static void toshiba_wmi_input_destroy(void) | ||
107 | { | ||
108 | wmi_remove_notify_handler(TOSHIBA_WMI_EVENT_GUID); | ||
109 | sparse_keymap_free(toshiba_wmi_input_dev); | ||
110 | input_unregister_device(toshiba_wmi_input_dev); | ||
111 | } | ||
112 | |||
113 | static int __init toshiba_wmi_init(void) | ||
114 | { | ||
115 | int ret; | ||
116 | |||
117 | if (!wmi_has_guid(TOSHIBA_WMI_EVENT_GUID)) | ||
118 | return -ENODEV; | ||
119 | |||
120 | ret = toshiba_wmi_input_setup(); | ||
121 | if (ret) { | ||
122 | pr_err("Failed to setup input device\n"); | ||
123 | return ret; | ||
124 | } | ||
125 | |||
126 | pr_info("Toshiba WMI Hotkey Driver\n"); | ||
127 | |||
128 | return 0; | ||
129 | } | ||
130 | |||
131 | static void __exit toshiba_wmi_exit(void) | ||
132 | { | ||
133 | if (wmi_has_guid(TOSHIBA_WMI_EVENT_GUID)) | ||
134 | toshiba_wmi_input_destroy(); | ||
135 | } | ||
136 | |||
137 | module_init(toshiba_wmi_init); | ||
138 | module_exit(toshiba_wmi_exit); | ||
diff --git a/drivers/platform/x86/toshiba_acpi.c b/drivers/platform/x86/toshiba_acpi.c index f2372f400ddb..c01302989ee4 100644 --- a/drivers/platform/x86/toshiba_acpi.c +++ b/drivers/platform/x86/toshiba_acpi.c | |||
@@ -131,7 +131,7 @@ MODULE_LICENSE("GPL"); | |||
131 | /* Field definitions */ | 131 | /* Field definitions */ |
132 | #define HCI_ACCEL_MASK 0x7fff | 132 | #define HCI_ACCEL_MASK 0x7fff |
133 | #define HCI_HOTKEY_DISABLE 0x0b | 133 | #define HCI_HOTKEY_DISABLE 0x0b |
134 | #define HCI_HOTKEY_ENABLE 0x09 | 134 | #define HCI_HOTKEY_ENABLE 0x01 |
135 | #define HCI_HOTKEY_SPECIAL_FUNCTIONS 0x10 | 135 | #define HCI_HOTKEY_SPECIAL_FUNCTIONS 0x10 |
136 | #define HCI_LCD_BRIGHTNESS_BITS 3 | 136 | #define HCI_LCD_BRIGHTNESS_BITS 3 |
137 | #define HCI_LCD_BRIGHTNESS_SHIFT (16-HCI_LCD_BRIGHTNESS_BITS) | 137 | #define HCI_LCD_BRIGHTNESS_SHIFT (16-HCI_LCD_BRIGHTNESS_BITS) |
@@ -198,6 +198,7 @@ struct toshiba_acpi_dev { | |||
198 | unsigned int panel_power_on_supported:1; | 198 | unsigned int panel_power_on_supported:1; |
199 | unsigned int usb_three_supported:1; | 199 | unsigned int usb_three_supported:1; |
200 | unsigned int sysfs_created:1; | 200 | unsigned int sysfs_created:1; |
201 | unsigned int special_functions; | ||
201 | 202 | ||
202 | bool kbd_led_registered; | 203 | bool kbd_led_registered; |
203 | bool illumination_led_registered; | 204 | bool illumination_led_registered; |
@@ -1668,10 +1669,10 @@ static ssize_t available_kbd_modes_show(struct device *dev, | |||
1668 | struct toshiba_acpi_dev *toshiba = dev_get_drvdata(dev); | 1669 | struct toshiba_acpi_dev *toshiba = dev_get_drvdata(dev); |
1669 | 1670 | ||
1670 | if (toshiba->kbd_type == 1) | 1671 | if (toshiba->kbd_type == 1) |
1671 | return sprintf(buf, "%x %x\n", | 1672 | return sprintf(buf, "0x%x 0x%x\n", |
1672 | SCI_KBD_MODE_FNZ, SCI_KBD_MODE_AUTO); | 1673 | SCI_KBD_MODE_FNZ, SCI_KBD_MODE_AUTO); |
1673 | 1674 | ||
1674 | return sprintf(buf, "%x %x %x\n", | 1675 | return sprintf(buf, "0x%x 0x%x 0x%x\n", |
1675 | SCI_KBD_MODE_AUTO, SCI_KBD_MODE_ON, SCI_KBD_MODE_OFF); | 1676 | SCI_KBD_MODE_AUTO, SCI_KBD_MODE_ON, SCI_KBD_MODE_OFF); |
1676 | } | 1677 | } |
1677 | static DEVICE_ATTR_RO(available_kbd_modes); | 1678 | static DEVICE_ATTR_RO(available_kbd_modes); |
@@ -2253,7 +2254,16 @@ static int toshiba_acpi_enable_hotkeys(struct toshiba_acpi_dev *dev) | |||
2253 | if (ACPI_FAILURE(status)) | 2254 | if (ACPI_FAILURE(status)) |
2254 | return -ENODEV; | 2255 | return -ENODEV; |
2255 | 2256 | ||
2256 | result = hci_write(dev, HCI_HOTKEY_EVENT, HCI_HOTKEY_ENABLE); | 2257 | /* |
2258 | * Enable the "Special Functions" mode only if they are | ||
2259 | * supported and if they are activated. | ||
2260 | */ | ||
2261 | if (dev->kbd_function_keys_supported && dev->special_functions) | ||
2262 | result = hci_write(dev, HCI_HOTKEY_EVENT, | ||
2263 | HCI_HOTKEY_SPECIAL_FUNCTIONS); | ||
2264 | else | ||
2265 | result = hci_write(dev, HCI_HOTKEY_EVENT, HCI_HOTKEY_ENABLE); | ||
2266 | |||
2257 | if (result == TOS_FAILURE) | 2267 | if (result == TOS_FAILURE) |
2258 | return -EIO; | 2268 | return -EIO; |
2259 | else if (result == TOS_NOT_SUPPORTED) | 2269 | else if (result == TOS_NOT_SUPPORTED) |
@@ -2262,20 +2272,6 @@ static int toshiba_acpi_enable_hotkeys(struct toshiba_acpi_dev *dev) | |||
2262 | return 0; | 2272 | return 0; |
2263 | } | 2273 | } |
2264 | 2274 | ||
2265 | static void toshiba_acpi_enable_special_functions(struct toshiba_acpi_dev *dev) | ||
2266 | { | ||
2267 | u32 result; | ||
2268 | |||
2269 | /* | ||
2270 | * Re-activate the hotkeys, but this time, we are using the | ||
2271 | * "Special Functions" mode. | ||
2272 | */ | ||
2273 | result = hci_write(dev, HCI_HOTKEY_EVENT, | ||
2274 | HCI_HOTKEY_SPECIAL_FUNCTIONS); | ||
2275 | if (result != TOS_SUCCESS) | ||
2276 | pr_err("Could not enable the Special Function mode\n"); | ||
2277 | } | ||
2278 | |||
2279 | static bool toshiba_acpi_i8042_filter(unsigned char data, unsigned char str, | 2275 | static bool toshiba_acpi_i8042_filter(unsigned char data, unsigned char str, |
2280 | struct serio *port) | 2276 | struct serio *port) |
2281 | { | 2277 | { |
@@ -2385,8 +2381,6 @@ static int toshiba_acpi_setup_keyboard(struct toshiba_acpi_dev *dev) | |||
2385 | { | 2381 | { |
2386 | const struct key_entry *keymap = toshiba_acpi_keymap; | 2382 | const struct key_entry *keymap = toshiba_acpi_keymap; |
2387 | acpi_handle ec_handle; | 2383 | acpi_handle ec_handle; |
2388 | u32 events_type; | ||
2389 | u32 hci_result; | ||
2390 | int error; | 2384 | int error; |
2391 | 2385 | ||
2392 | if (wmi_has_guid(TOSHIBA_WMI_EVENT_GUID)) { | 2386 | if (wmi_has_guid(TOSHIBA_WMI_EVENT_GUID)) { |
@@ -2398,11 +2392,9 @@ static int toshiba_acpi_setup_keyboard(struct toshiba_acpi_dev *dev) | |||
2398 | if (error) | 2392 | if (error) |
2399 | return error; | 2393 | return error; |
2400 | 2394 | ||
2401 | if (toshiba_hotkey_event_type_get(dev, &events_type)) | 2395 | if (toshiba_hotkey_event_type_get(dev, &dev->hotkey_event_type)) |
2402 | pr_notice("Unable to query Hotkey Event Type\n"); | 2396 | pr_notice("Unable to query Hotkey Event Type\n"); |
2403 | 2397 | ||
2404 | dev->hotkey_event_type = events_type; | ||
2405 | |||
2406 | dev->hotkey_dev = input_allocate_device(); | 2398 | dev->hotkey_dev = input_allocate_device(); |
2407 | if (!dev->hotkey_dev) | 2399 | if (!dev->hotkey_dev) |
2408 | return -ENOMEM; | 2400 | return -ENOMEM; |
@@ -2411,14 +2403,15 @@ static int toshiba_acpi_setup_keyboard(struct toshiba_acpi_dev *dev) | |||
2411 | dev->hotkey_dev->phys = "toshiba_acpi/input0"; | 2403 | dev->hotkey_dev->phys = "toshiba_acpi/input0"; |
2412 | dev->hotkey_dev->id.bustype = BUS_HOST; | 2404 | dev->hotkey_dev->id.bustype = BUS_HOST; |
2413 | 2405 | ||
2414 | if (events_type == HCI_SYSTEM_TYPE1 || | 2406 | if (dev->hotkey_event_type == HCI_SYSTEM_TYPE1 || |
2415 | !dev->kbd_function_keys_supported) | 2407 | !dev->kbd_function_keys_supported) |
2416 | keymap = toshiba_acpi_keymap; | 2408 | keymap = toshiba_acpi_keymap; |
2417 | else if (events_type == HCI_SYSTEM_TYPE2 || | 2409 | else if (dev->hotkey_event_type == HCI_SYSTEM_TYPE2 || |
2418 | dev->kbd_function_keys_supported) | 2410 | dev->kbd_function_keys_supported) |
2419 | keymap = toshiba_acpi_alt_keymap; | 2411 | keymap = toshiba_acpi_alt_keymap; |
2420 | else | 2412 | else |
2421 | pr_info("Unknown event type received %x\n", events_type); | 2413 | pr_info("Unknown event type received %x\n", |
2414 | dev->hotkey_event_type); | ||
2422 | error = sparse_keymap_setup(dev->hotkey_dev, keymap, NULL); | 2415 | error = sparse_keymap_setup(dev->hotkey_dev, keymap, NULL); |
2423 | if (error) | 2416 | if (error) |
2424 | goto err_free_dev; | 2417 | goto err_free_dev; |
@@ -2449,11 +2442,8 @@ static int toshiba_acpi_setup_keyboard(struct toshiba_acpi_dev *dev) | |||
2449 | */ | 2442 | */ |
2450 | if (acpi_has_method(dev->acpi_dev->handle, "INFO")) | 2443 | if (acpi_has_method(dev->acpi_dev->handle, "INFO")) |
2451 | dev->info_supported = 1; | 2444 | dev->info_supported = 1; |
2452 | else { | 2445 | else if (hci_write(dev, HCI_SYSTEM_EVENT, 1) == TOS_SUCCESS) |
2453 | hci_result = hci_write(dev, HCI_SYSTEM_EVENT, 1); | 2446 | dev->system_event_supported = 1; |
2454 | if (hci_result == TOS_SUCCESS) | ||
2455 | dev->system_event_supported = 1; | ||
2456 | } | ||
2457 | 2447 | ||
2458 | if (!dev->info_supported && !dev->system_event_supported) { | 2448 | if (!dev->info_supported && !dev->system_event_supported) { |
2459 | pr_warn("No hotkey query interface found\n"); | 2449 | pr_warn("No hotkey query interface found\n"); |
@@ -2631,7 +2621,6 @@ static int toshiba_acpi_add(struct acpi_device *acpi_dev) | |||
2631 | { | 2621 | { |
2632 | struct toshiba_acpi_dev *dev; | 2622 | struct toshiba_acpi_dev *dev; |
2633 | const char *hci_method; | 2623 | const char *hci_method; |
2634 | u32 special_functions; | ||
2635 | u32 dummy; | 2624 | u32 dummy; |
2636 | int ret = 0; | 2625 | int ret = 0; |
2637 | 2626 | ||
@@ -2673,9 +2662,10 @@ static int toshiba_acpi_add(struct acpi_device *acpi_dev) | |||
2673 | * with the new keyboard layout, query for its presence to help | 2662 | * with the new keyboard layout, query for its presence to help |
2674 | * determine the keymap layout to use. | 2663 | * determine the keymap layout to use. |
2675 | */ | 2664 | */ |
2676 | ret = toshiba_function_keys_get(dev, &special_functions); | 2665 | ret = toshiba_function_keys_get(dev, &dev->special_functions); |
2677 | dev->kbd_function_keys_supported = !ret; | 2666 | dev->kbd_function_keys_supported = !ret; |
2678 | 2667 | ||
2668 | dev->hotkey_event_type = 0; | ||
2679 | if (toshiba_acpi_setup_keyboard(dev)) | 2669 | if (toshiba_acpi_setup_keyboard(dev)) |
2680 | pr_info("Unable to activate hotkeys\n"); | 2670 | pr_info("Unable to activate hotkeys\n"); |
2681 | 2671 | ||
@@ -2748,13 +2738,6 @@ static int toshiba_acpi_add(struct acpi_device *acpi_dev) | |||
2748 | 2738 | ||
2749 | print_supported_features(dev); | 2739 | print_supported_features(dev); |
2750 | 2740 | ||
2751 | /* | ||
2752 | * Enable the "Special Functions" mode only if they are | ||
2753 | * supported and if they are activated. | ||
2754 | */ | ||
2755 | if (dev->kbd_function_keys_supported && special_functions) | ||
2756 | toshiba_acpi_enable_special_functions(dev); | ||
2757 | |||
2758 | ret = sysfs_create_group(&dev->acpi_dev->dev.kobj, | 2741 | ret = sysfs_create_group(&dev->acpi_dev->dev.kobj, |
2759 | &toshiba_attr_group); | 2742 | &toshiba_attr_group); |
2760 | if (ret) { | 2743 | if (ret) { |