Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

Merge tag 'platform-drivers-x86-v4.11-1' of git://git.infradead.org/linux-platform-drivers-x86

Pull x86 platform driver updates from Darren Hart:
"Big picture:

- New intel_turbo_max_3 driver, providing max core frequency
information to the scheduler. Intel PMC APL support, s0ix read API,
and fixes.

- New Silead touchscreen platform touchscreen descriptions.
Additional hotkey support for the intel-hid driver.

- New model support for dell-laptop and hp_accel.

- Several cleanups, especially to the fujitsu-laptop and
intel_mid_powerbtn drivers.

Detail summary:

platorm/x86:
- silead depends on I2C being built-in
- add support for devices with Silead touchscreens
- Support Turbo Boost Max 3.0 for non HWP systems

intel_turbo_max_3:
- make it explicitly non-modular

dell-laptop:
- Add Latitude 7480 and others to the DMI whitelist

intel-hid:
- Support 5 button array

thinkpad_acpi:
- Call led_classdev_notify_brightness_hw_changed on kbd brightness change
- Use brightness_set_blocking callback for LEDs
- Stop setting led_classdev brightness directly

acer-wmi:
- add another KEY_WLAN keycode
- Inform firmware that RF Button Driver is active
- setup accelerometer when machine has appropriate notify event

asus-wireless:
- Fix indentation
- Use per-HID HSWC parameters

intel_pmc_ipc:
- Add APL PMC PCI Id
- read s0ix residency API
- Remove unused iTCO_version variable

alienware-wmi:
- Remove header duplicate

intel_pmc_core:
- fix out-of-bounds accesses on stack

intel_mid_powerbtn:
- Use SCU IPC directly
- Unify IRQ acknowledgment
- Move comment to where it belongs
- Unify PBSTATUS access
- Remove snail address
- Sort headers alphabetically
- Join string literals
- Enable driver for Merrifield
- Acknowledge interrupts
- Factor out mfld_ack()
- Introduce driver data
- Substitute mfld by mid
- Convert to use devm_*()

fujitsu-laptop:
- make hotkey handling functions more similar
- break up complex loop condition
- move keycode processing to separate functions
- decrease indentation in acpi_fujitsu_hotkey_notify()
- simplify logolamp_get()
- rework logolamp_set() to properly handle errors
- set default trigger for radio LED to rfkill-any

dell-smbios:
- Auto-select as needed

intel_mid_thermal:
- Fix module autoload
- Remove duplicated platform device ID

mlx-platform:
- mlxcpld-hotplug driver style fixes

hp_accel:
- Add support for HP ZBook 17"

* tag 'platform-drivers-x86-v4.11-1' of git://git.infradead.org/linux-platform-drivers-x86: (45 commits)
platform/x86: intel_turbo_max_3: make it explicitly non-modular
platform/x86: dell-laptop: Add Latitude 7480 and others to the DMI whitelist
platform/x86: intel-hid: Support 5 button array
platform/x86: thinkpad_acpi: Call led_classdev_notify_brightness_hw_changed on kbd brightness change
platform/x86: thinkpad_acpi: Use brightness_set_blocking callback for LEDs
platform/x86: thinkpad_acpi: Stop setting led_classdev brightness directly
leds: class: Add new optional brightness_hw_changed attribute
platform/x86: acer-wmi: add another KEY_WLAN keycode
platform/x86: acer-wmi: Inform firmware that RF Button Driver is active
platform/x86: asus-wireless: Fix indentation
platform/x86: asus-wireless: Use per-HID HSWC parameters
platform/x86: intel_pmc_ipc: Add APL PMC PCI Id
platform/x86: intel_pmc_ipc: read s0ix residency API
platform/x86: alienware-wmi: Remove header duplicate
platform/x86: intel_mid_powerbtn: Use SCU IPC directly
platform/x86: intel_mid_powerbtn: Unify IRQ acknowledgment
platform/x86: intel_mid_powerbtn: Move comment to where it belongs
platform/x86: intel_mid_powerbtn: Unify PBSTATUS access
platform/x86: intel_pmc_core: fix out-of-bounds accesses on stack
platform/x86: silead depends on I2C being built-in
...

+968 -323
+8
MAINTAINERS
··· 11456 11456 F: drivers/media/usb/siano/ 11457 11457 F: drivers/media/mmc/siano/ 11458 11458 11459 + SILEAD TOUCHSCREEN DRIVER 11460 + M: Hans de Goede <hdegoede@redhat.com> 11461 + L: linux-input@vger.kernel.org 11462 + L: platform-driver-x86@vger.kernel.org 11463 + S: Maintained 11464 + F: drivers/input/touchscreen/silead.c 11465 + F: drivers/platform/x86/silead_dmi.c 11466 + 11459 11467 SIMPLEFB FB DRIVER 11460 11468 M: Hans de Goede <hdegoede@redhat.com> 11461 11469 L: linux-fbdev@vger.kernel.org
+6
arch/x86/include/asm/intel_pmc_ipc.h
··· 30 30 u32 *out, u32 outlen, u32 dptr, u32 sptr); 31 31 int intel_pmc_ipc_command(u32 cmd, u32 sub, u8 *in, u32 inlen, 32 32 u32 *out, u32 outlen); 33 + int intel_pmc_s0ix_counter_read(u64 *data); 33 34 34 35 #else 35 36 ··· 47 46 48 47 static inline int intel_pmc_ipc_command(u32 cmd, u32 sub, u8 *in, u32 inlen, 49 48 u32 *out, u32 outlen) 49 + { 50 + return -EINVAL; 51 + } 52 + 53 + static inline int intel_pmc_s0ix_counter_read(u64 *data) 50 54 { 51 55 return -EINVAL; 52 56 }
+25 -6
drivers/platform/x86/Kconfig
··· 92 92 If you have an ACPI-compatible ASUS laptop, say Y or M here. 93 93 94 94 config DELL_SMBIOS 95 - tristate "Dell SMBIOS Support" 96 - depends on DCDBAS 97 - default n 95 + tristate 96 + select DCDBAS 98 97 ---help--- 99 98 This module provides common functions for kernel modules using 100 99 Dell SMBIOS. ··· 102 103 103 104 config DELL_LAPTOP 104 105 tristate "Dell Laptop Extras" 105 - depends on DELL_SMBIOS 106 106 depends on DMI 107 107 depends on BACKLIGHT_CLASS_DEVICE 108 108 depends on ACPI_VIDEO || ACPI_VIDEO = n 109 109 depends on RFKILL || RFKILL = n 110 110 depends on SERIO_I8042 111 + select DELL_SMBIOS 111 112 select POWER_SUPPLY 112 113 select LEDS_CLASS 113 114 select NEW_LEDS 114 - default n 115 115 ---help--- 116 116 This driver adds support for rfkill and backlight control to Dell 117 117 laptops (except for some models covered by the Compal driver). ··· 121 123 depends on DMI 122 124 depends on INPUT 123 125 depends on ACPI_VIDEO || ACPI_VIDEO = n 124 - depends on DELL_SMBIOS 126 + select DELL_SMBIOS 125 127 select INPUT_SPARSEKMAP 126 128 ---help--- 127 129 Say Y here if you want to support WMI-based hotkeys on Dell laptops. ··· 1066 1068 ---help--- 1067 1069 This driver handles hot-plug events for the power suppliers, power 1068 1070 cables and fans on the wide range Mellanox IB and Ethernet systems. 1071 + 1072 + config INTEL_TURBO_MAX_3 1073 + bool "Intel Turbo Boost Max Technology 3.0 enumeration driver" 1074 + depends on X86_64 && SCHED_MC_PRIO 1075 + ---help--- 1076 + This driver reads maximum performance ratio of each CPU and set up 1077 + the scheduler priority metrics. In this way scheduler can prefer 1078 + CPU with higher performance to schedule tasks. 1079 + This driver is only required when the system is not using Hardware 1080 + P-States (HWP). In HWP mode, priority can be read from ACPI tables. 1081 + 1082 + config SILEAD_DMI 1083 + bool "Tablets with Silead touchscreens" 1084 + depends on ACPI && DMI && I2C=y && INPUT 1085 + ---help--- 1086 + Certain ACPI based tablets with Silead touchscreens do not have 1087 + enough data in ACPI tables for the touchscreen driver to handle 1088 + the touchscreen properly, as OEMs expected the data to be baked 1089 + into the tablet model specific version of the driver shipped 1090 + with the OS-image for the device. This option supplies the missing 1091 + information. Enable this for x86 tablets with Silead touchscreens. 1069 1092 1070 1093 endif # X86_PLATFORM_DEVICES 1071 1094
+2
drivers/platform/x86/Makefile
··· 65 65 obj-$(CONFIG_PVPANIC) += pvpanic.o 66 66 obj-$(CONFIG_ALIENWARE_WMI) += alienware-wmi.o 67 67 obj-$(CONFIG_INTEL_PMC_IPC) += intel_pmc_ipc.o 68 + obj-$(CONFIG_SILEAD_DMI) += silead_dmi.o 68 69 obj-$(CONFIG_SURFACE_PRO3_BUTTON) += surfacepro3_button.o 69 70 obj-$(CONFIG_SURFACE_3_BUTTON) += surface3_button.o 70 71 obj-$(CONFIG_INTEL_PUNIT_IPC) += intel_punit_ipc.o ··· 77 76 obj-$(CONFIG_PMC_ATOM) += pmc_atom.o 78 77 obj-$(CONFIG_MLX_PLATFORM) += mlx-platform.o 79 78 obj-$(CONFIG_MLX_CPLD_PLATFORM) += mlxcpld-hotplug.o 79 + obj-$(CONFIG_INTEL_TURBO_MAX_3) += intel_turbo_max_3.o
+77 -20
drivers/platform/x86/acer-wmi.c
··· 128 128 {KE_KEY, KEY_TOUCHPAD_OFF, {KEY_TOUCHPAD_OFF} }, 129 129 {KE_IGNORE, 0x83, {KEY_TOUCHPAD_TOGGLE} }, 130 130 {KE_KEY, 0x85, {KEY_TOUCHPAD_TOGGLE} }, 131 + {KE_KEY, 0x86, {KEY_WLAN} }, 131 132 {KE_END, 0} 132 133 }; 133 134 ··· 151 150 #define ACER_WMID3_GDS_BLUETOOTH (1<<11) /* BT */ 152 151 #define ACER_WMID3_GDS_TOUCHPAD (1<<1) /* Touchpad */ 153 152 154 - struct lm_input_params { 153 + /* Hotkey Customized Setting and Acer Application Status. 154 + * Set Device Default Value and Report Acer Application Status. 155 + * When Acer Application starts, it will run this method to inform 156 + * BIOS/EC that Acer Application is on. 157 + * App Status 158 + * Bit[0]: Launch Manager Status 159 + * Bit[1]: ePM Status 160 + * Bit[2]: Device Control Status 161 + * Bit[3]: Acer Power Button Utility Status 162 + * Bit[4]: RF Button Status 163 + * Bit[5]: ODD PM Status 164 + * Bit[6]: Device Default Value Control 165 + * Bit[7]: Hall Sensor Application Status 166 + */ 167 + struct func_input_params { 155 168 u8 function_num; /* Function Number */ 156 169 u16 commun_devices; /* Communication type devices default status */ 157 170 u16 devices; /* Other type devices default status */ 158 - u8 lm_status; /* Launch Manager Status */ 159 - u16 reserved; 171 + u8 app_status; /* Acer Device Status. LM, ePM, RF Button... */ 172 + u8 app_mask; /* Bit mask to app_status */ 173 + u8 reserved; 160 174 } __attribute__((packed)); 161 175 162 - struct lm_return_value { 176 + struct func_return_value { 163 177 u8 error_code; /* Error Code */ 164 178 u8 ec_return_value; /* EC Return Value */ 165 179 u16 reserved; ··· 1785 1769 } 1786 1770 1787 1771 static acpi_status __init 1788 - wmid3_set_lm_mode(struct lm_input_params *params, 1789 - struct lm_return_value *return_value) 1772 + wmid3_set_function_mode(struct func_input_params *params, 1773 + struct func_return_value *return_value) 1790 1774 { 1791 1775 acpi_status status; 1792 1776 union acpi_object *obj; 1793 1777 1794 - struct acpi_buffer input = { sizeof(struct lm_input_params), params }; 1778 + struct acpi_buffer input = { sizeof(struct func_input_params), params }; 1795 1779 struct acpi_buffer output = { ACPI_ALLOCATE_BUFFER, NULL }; 1796 1780 1797 1781 status = wmi_evaluate_method(WMID_GUID3, 0, 0x1, &input, &output); ··· 1812 1796 return AE_ERROR; 1813 1797 } 1814 1798 1815 - *return_value = *((struct lm_return_value *)obj->buffer.pointer); 1799 + *return_value = *((struct func_return_value *)obj->buffer.pointer); 1816 1800 kfree(obj); 1817 1801 1818 1802 return status; ··· 1820 1804 1821 1805 static int __init acer_wmi_enable_ec_raw(void) 1822 1806 { 1823 - struct lm_return_value return_value; 1807 + struct func_return_value return_value; 1824 1808 acpi_status status; 1825 - struct lm_input_params params = { 1809 + struct func_input_params params = { 1826 1810 .function_num = 0x1, 1827 1811 .commun_devices = 0xFFFF, 1828 1812 .devices = 0xFFFF, 1829 - .lm_status = 0x00, /* Launch Manager Deactive */ 1813 + .app_status = 0x00, /* Launch Manager Deactive */ 1814 + .app_mask = 0x01, 1830 1815 }; 1831 1816 1832 - status = wmid3_set_lm_mode(&params, &return_value); 1817 + status = wmid3_set_function_mode(&params, &return_value); 1833 1818 1834 1819 if (return_value.error_code || return_value.ec_return_value) 1835 1820 pr_warn("Enabling EC raw mode failed: 0x%x - 0x%x\n", ··· 1844 1827 1845 1828 static int __init acer_wmi_enable_lm(void) 1846 1829 { 1847 - struct lm_return_value return_value; 1830 + struct func_return_value return_value; 1848 1831 acpi_status status; 1849 - struct lm_input_params params = { 1832 + struct func_input_params params = { 1850 1833 .function_num = 0x1, 1851 1834 .commun_devices = 0xFFFF, 1852 1835 .devices = 0xFFFF, 1853 - .lm_status = 0x01, /* Launch Manager Active */ 1836 + .app_status = 0x01, /* Launch Manager Active */ 1837 + .app_mask = 0x01, 1854 1838 }; 1855 1839 1856 - status = wmid3_set_lm_mode(&params, &return_value); 1840 + status = wmid3_set_function_mode(&params, &return_value); 1857 1841 1858 1842 if (return_value.error_code || return_value.ec_return_value) 1859 1843 pr_warn("Enabling Launch Manager failed: 0x%x - 0x%x\n", ··· 1864 1846 return status; 1865 1847 } 1866 1848 1849 + static int __init acer_wmi_enable_rf_button(void) 1850 + { 1851 + struct func_return_value return_value; 1852 + acpi_status status; 1853 + struct func_input_params params = { 1854 + .function_num = 0x1, 1855 + .commun_devices = 0xFFFF, 1856 + .devices = 0xFFFF, 1857 + .app_status = 0x10, /* RF Button Active */ 1858 + .app_mask = 0x10, 1859 + }; 1860 + 1861 + status = wmid3_set_function_mode(&params, &return_value); 1862 + 1863 + if (return_value.error_code || return_value.ec_return_value) 1864 + pr_warn("Enabling RF Button failed: 0x%x - 0x%x\n", 1865 + return_value.error_code, 1866 + return_value.ec_return_value); 1867 + 1868 + return status; 1869 + } 1870 + 1871 + #define ACER_WMID_ACCEL_HID "BST0001" 1872 + 1867 1873 static acpi_status __init acer_wmi_get_handle_cb(acpi_handle ah, u32 level, 1868 1874 void *ctx, void **retval) 1869 1875 { 1876 + struct acpi_device *dev; 1877 + 1878 + if (!strcmp(ctx, "SENR")) { 1879 + if (acpi_bus_get_device(ah, &dev)) 1880 + return AE_OK; 1881 + if (!strcmp(ACER_WMID_ACCEL_HID, acpi_device_hid(dev))) 1882 + return AE_OK; 1883 + } else 1884 + return AE_OK; 1885 + 1870 1886 *(acpi_handle *)retval = ah; 1871 - return AE_OK; 1887 + 1888 + return AE_CTRL_TERMINATE; 1872 1889 } 1873 1890 1874 1891 static int __init acer_wmi_get_handle(const char *name, const char *prop, ··· 1930 1877 { 1931 1878 int err; 1932 1879 1933 - err = acer_wmi_get_handle("SENR", "BST0001", &gsensor_handle); 1880 + err = acer_wmi_get_handle("SENR", ACER_WMID_ACCEL_HID, &gsensor_handle); 1934 1881 if (err) 1935 1882 return err; 1936 1883 ··· 2269 2216 interface->capability &= ~ACER_CAP_BRIGHTNESS; 2270 2217 2271 2218 if (wmi_has_guid(WMID_GUID3)) { 2219 + if (ACPI_FAILURE(acer_wmi_enable_rf_button())) 2220 + pr_warn("Cannot enable RF Button Driver\n"); 2221 + 2272 2222 if (ec_raw_mode) { 2273 2223 if (ACPI_FAILURE(acer_wmi_enable_ec_raw())) { 2274 2224 pr_err("Cannot enable EC raw mode\n"); ··· 2289 2233 err = acer_wmi_input_setup(); 2290 2234 if (err) 2291 2235 return err; 2236 + err = acer_wmi_accel_setup(); 2237 + if (err) 2238 + return err; 2292 2239 } 2293 - 2294 - acer_wmi_accel_setup(); 2295 2240 2296 2241 err = platform_driver_register(&acer_platform_driver); 2297 2242 if (err) {
-1
drivers/platform/x86/alienware-wmi.c
··· 21 21 #include <linux/module.h> 22 22 #include <linux/platform_device.h> 23 23 #include <linux/dmi.h> 24 - #include <linux/acpi.h> 25 24 #include <linux/leds.h> 26 25 27 26 #define LEGACY_CONTROL_GUID "A90597CE-A997-11DA-B012-B622A1EF5492"
+43 -17
drivers/platform/x86/asus-wireless.c
··· 17 17 #include <linux/pci_ids.h> 18 18 #include <linux/leds.h> 19 19 20 - #define ASUS_WIRELESS_LED_STATUS 0x2 21 - #define ASUS_WIRELESS_LED_OFF 0x4 22 - #define ASUS_WIRELESS_LED_ON 0x5 20 + struct hswc_params { 21 + u8 on; 22 + u8 off; 23 + u8 status; 24 + }; 23 25 24 26 struct asus_wireless_data { 25 27 struct input_dev *idev; 26 28 struct acpi_device *adev; 29 + const struct hswc_params *hswc_params; 27 30 struct workqueue_struct *wq; 28 31 struct work_struct led_work; 29 32 struct led_classdev led; 30 33 int led_state; 31 34 }; 35 + 36 + static const struct hswc_params atk4001_id_params = { 37 + .on = 0x0, 38 + .off = 0x1, 39 + .status = 0x2, 40 + }; 41 + 42 + static const struct hswc_params atk4002_id_params = { 43 + .on = 0x5, 44 + .off = 0x4, 45 + .status = 0x2, 46 + }; 47 + 48 + static const struct acpi_device_id device_ids[] = { 49 + {"ATK4001", (kernel_ulong_t)&atk4001_id_params}, 50 + {"ATK4002", (kernel_ulong_t)&atk4002_id_params}, 51 + {"", 0}, 52 + }; 53 + MODULE_DEVICE_TABLE(acpi, device_ids); 32 54 33 55 static u64 asus_wireless_method(acpi_handle handle, const char *method, 34 56 int param) ··· 83 61 84 62 data = container_of(led, struct asus_wireless_data, led); 85 63 s = asus_wireless_method(acpi_device_handle(data->adev), "HSWC", 86 - ASUS_WIRELESS_LED_STATUS); 87 - if (s == ASUS_WIRELESS_LED_ON) 64 + data->hswc_params->status); 65 + if (s == data->hswc_params->on) 88 66 return LED_FULL; 89 67 return LED_OFF; 90 68 } ··· 98 76 data->led_state); 99 77 } 100 78 101 - static void led_state_set(struct led_classdev *led, 102 - enum led_brightness value) 79 + static void led_state_set(struct led_classdev *led, enum led_brightness value) 103 80 { 104 81 struct asus_wireless_data *data; 105 82 106 83 data = container_of(led, struct asus_wireless_data, led); 107 - data->led_state = value == LED_OFF ? ASUS_WIRELESS_LED_OFF : 108 - ASUS_WIRELESS_LED_ON; 84 + data->led_state = value == LED_OFF ? data->hswc_params->off : 85 + data->hswc_params->on; 109 86 queue_work(data->wq, &data->led_work); 110 87 } 111 88 ··· 125 104 static int asus_wireless_add(struct acpi_device *adev) 126 105 { 127 106 struct asus_wireless_data *data; 107 + const struct acpi_device_id *id; 128 108 int err; 129 109 130 110 data = devm_kzalloc(&adev->dev, sizeof(*data), GFP_KERNEL); 131 111 if (!data) 132 112 return -ENOMEM; 133 113 adev->driver_data = data; 114 + data->adev = adev; 134 115 135 116 data->idev = devm_input_allocate_device(&adev->dev); 136 117 if (!data->idev) ··· 147 124 if (err) 148 125 return err; 149 126 150 - data->adev = adev; 127 + for (id = device_ids; id->id[0]; id++) { 128 + if (!strcmp((char *) id->id, acpi_device_hid(adev))) { 129 + data->hswc_params = 130 + (const struct hswc_params *)id->driver_data; 131 + break; 132 + } 133 + } 134 + if (!data->hswc_params) 135 + return 0; 136 + 151 137 data->wq = create_singlethread_workqueue("asus_wireless_workqueue"); 152 138 if (!data->wq) 153 139 return -ENOMEM; ··· 169 137 err = devm_led_classdev_register(&adev->dev, &data->led); 170 138 if (err) 171 139 destroy_workqueue(data->wq); 140 + 172 141 return err; 173 142 } 174 143 ··· 181 148 destroy_workqueue(data->wq); 182 149 return 0; 183 150 } 184 - 185 - static const struct acpi_device_id device_ids[] = { 186 - {"ATK4001", 0}, 187 - {"ATK4002", 0}, 188 - {"", 0}, 189 - }; 190 - MODULE_DEVICE_TABLE(acpi, device_ids); 191 151 192 152 static struct acpi_driver asus_wireless_driver = { 193 153 .name = "Asus Wireless Radio Control Driver",
+6
drivers/platform/x86/dell-laptop.c
··· 106 106 }, 107 107 }, 108 108 { 109 + .matches = { 110 + DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."), 111 + DMI_MATCH(DMI_CHASSIS_TYPE, "10"), /*Notebook*/ 112 + }, 113 + }, 114 + { 109 115 .ident = "Dell Computer Corporation", 110 116 .matches = { 111 117 DMI_MATCH(DMI_SYS_VENDOR, "Dell Computer Corporation"),
+121 -105
drivers/platform/x86/fujitsu-laptop.c
··· 202 202 203 203 static struct led_classdev radio_led = { 204 204 .name = "fujitsu::radio_led", 205 + .default_trigger = "rfkill-any", 205 206 .brightness_get = radio_led_get, 206 207 .brightness_set_blocking = radio_led_set 207 208 }; ··· 271 270 static int logolamp_set(struct led_classdev *cdev, 272 271 enum led_brightness brightness) 273 272 { 274 - if (brightness >= LED_FULL) { 275 - call_fext_func(FUNC_LEDS, 0x1, LOGOLAMP_POWERON, FUNC_LED_ON); 276 - return call_fext_func(FUNC_LEDS, 0x1, LOGOLAMP_ALWAYS, FUNC_LED_ON); 277 - } else if (brightness >= LED_HALF) { 278 - call_fext_func(FUNC_LEDS, 0x1, LOGOLAMP_POWERON, FUNC_LED_ON); 279 - return call_fext_func(FUNC_LEDS, 0x1, LOGOLAMP_ALWAYS, FUNC_LED_OFF); 280 - } else { 281 - return call_fext_func(FUNC_LEDS, 0x1, LOGOLAMP_POWERON, FUNC_LED_OFF); 282 - } 273 + int poweron = FUNC_LED_ON, always = FUNC_LED_ON; 274 + int ret; 275 + 276 + if (brightness < LED_HALF) 277 + poweron = FUNC_LED_OFF; 278 + 279 + if (brightness < LED_FULL) 280 + always = FUNC_LED_OFF; 281 + 282 + ret = call_fext_func(FUNC_LEDS, 0x1, LOGOLAMP_POWERON, poweron); 283 + if (ret < 0) 284 + return ret; 285 + 286 + return call_fext_func(FUNC_LEDS, 0x1, LOGOLAMP_ALWAYS, always); 283 287 } 284 288 285 289 static int kblamps_set(struct led_classdev *cdev, ··· 319 313 320 314 static enum led_brightness logolamp_get(struct led_classdev *cdev) 321 315 { 322 - enum led_brightness brightness = LED_OFF; 323 - int poweron, always; 316 + int ret; 324 317 325 - poweron = call_fext_func(FUNC_LEDS, 0x2, LOGOLAMP_POWERON, 0x0); 326 - if (poweron == FUNC_LED_ON) { 327 - brightness = LED_HALF; 328 - always = call_fext_func(FUNC_LEDS, 0x2, LOGOLAMP_ALWAYS, 0x0); 329 - if (always == FUNC_LED_ON) 330 - brightness = LED_FULL; 331 - } 332 - return brightness; 318 + ret = call_fext_func(FUNC_LEDS, 0x2, LOGOLAMP_ALWAYS, 0x0); 319 + if (ret == FUNC_LED_ON) 320 + return LED_FULL; 321 + 322 + ret = call_fext_func(FUNC_LEDS, 0x2, LOGOLAMP_POWERON, 0x0); 323 + if (ret == FUNC_LED_ON) 324 + return LED_HALF; 325 + 326 + return LED_OFF; 333 327 } 334 328 335 329 static enum led_brightness kblamps_get(struct led_classdev *cdev) ··· 1035 1029 return 0; 1036 1030 } 1037 1031 1032 + static void acpi_fujitsu_hotkey_press(int keycode) 1033 + { 1034 + struct input_dev *input = fujitsu_hotkey->input; 1035 + int status; 1036 + 1037 + status = kfifo_in_locked(&fujitsu_hotkey->fifo, 1038 + (unsigned char *)&keycode, sizeof(keycode), 1039 + &fujitsu_hotkey->fifo_lock); 1040 + if (status != sizeof(keycode)) { 1041 + vdbg_printk(FUJLAPTOP_DBG_WARN, 1042 + "Could not push keycode [0x%x]\n", keycode); 1043 + return; 1044 + } 1045 + input_report_key(input, keycode, 1); 1046 + input_sync(input); 1047 + vdbg_printk(FUJLAPTOP_DBG_TRACE, 1048 + "Push keycode into ringbuffer [%d]\n", keycode); 1049 + } 1050 + 1051 + static void acpi_fujitsu_hotkey_release(void) 1052 + { 1053 + struct input_dev *input = fujitsu_hotkey->input; 1054 + int keycode, status; 1055 + 1056 + while (true) { 1057 + status = kfifo_out_locked(&fujitsu_hotkey->fifo, 1058 + (unsigned char *)&keycode, 1059 + sizeof(keycode), 1060 + &fujitsu_hotkey->fifo_lock); 1061 + if (status != sizeof(keycode)) 1062 + return; 1063 + input_report_key(input, keycode, 0); 1064 + input_sync(input); 1065 + vdbg_printk(FUJLAPTOP_DBG_TRACE, 1066 + "Pop keycode from ringbuffer [%d]\n", keycode); 1067 + } 1068 + } 1069 + 1038 1070 static void acpi_fujitsu_hotkey_notify(struct acpi_device *device, u32 event) 1039 1071 { 1040 1072 struct input_dev *input; 1041 - int keycode, keycode_r; 1073 + int keycode; 1042 1074 unsigned int irb = 1; 1043 - int i, status; 1075 + int i; 1044 1076 1045 1077 input = fujitsu_hotkey->input; 1046 1078 1047 - if (fujitsu_hotkey->rfkill_supported) 1048 - fujitsu_hotkey->rfkill_state = 1049 - call_fext_func(FUNC_RFKILL, 0x4, 0x0, 0x0); 1050 - 1051 - switch (event) { 1052 - case ACPI_FUJITSU_NOTIFY_CODE1: 1053 - i = 0; 1054 - while ((irb = 1055 - call_fext_func(FUNC_BUTTONS, 0x1, 0x0, 0x0)) != 0 1056 - && (i++) < MAX_HOTKEY_RINGBUFFER_SIZE) { 1057 - switch (irb & 0x4ff) { 1058 - case KEY1_CODE: 1059 - keycode = fujitsu->keycode1; 1060 - break; 1061 - case KEY2_CODE: 1062 - keycode = fujitsu->keycode2; 1063 - break; 1064 - case KEY3_CODE: 1065 - keycode = fujitsu->keycode3; 1066 - break; 1067 - case KEY4_CODE: 1068 - keycode = fujitsu->keycode4; 1069 - break; 1070 - case KEY5_CODE: 1071 - keycode = fujitsu->keycode5; 1072 - break; 1073 - case 0: 1074 - keycode = 0; 1075 - break; 1076 - default: 1077 - vdbg_printk(FUJLAPTOP_DBG_WARN, 1078 - "Unknown GIRB result [%x]\n", irb); 1079 - keycode = -1; 1080 - break; 1081 - } 1082 - if (keycode > 0) { 1083 - vdbg_printk(FUJLAPTOP_DBG_TRACE, 1084 - "Push keycode into ringbuffer [%d]\n", 1085 - keycode); 1086 - status = kfifo_in_locked(&fujitsu_hotkey->fifo, 1087 - (unsigned char *)&keycode, 1088 - sizeof(keycode), 1089 - &fujitsu_hotkey->fifo_lock); 1090 - if (status != sizeof(keycode)) { 1091 - vdbg_printk(FUJLAPTOP_DBG_WARN, 1092 - "Could not push keycode [0x%x]\n", 1093 - keycode); 1094 - } else { 1095 - input_report_key(input, keycode, 1); 1096 - input_sync(input); 1097 - } 1098 - } else if (keycode == 0) { 1099 - while ((status = 1100 - kfifo_out_locked( 1101 - &fujitsu_hotkey->fifo, 1102 - (unsigned char *) &keycode_r, 1103 - sizeof(keycode_r), 1104 - &fujitsu_hotkey->fifo_lock)) 1105 - == sizeof(keycode_r)) { 1106 - input_report_key(input, keycode_r, 0); 1107 - input_sync(input); 1108 - vdbg_printk(FUJLAPTOP_DBG_TRACE, 1109 - "Pop keycode from ringbuffer [%d]\n", 1110 - keycode_r); 1111 - } 1112 - } 1113 - } 1114 - 1115 - /* On some models (first seen on the Skylake-based Lifebook 1116 - * E736/E746/E756), the touchpad toggle hotkey (Fn+F4) is 1117 - * handled in software; its state is queried using FUNC_RFKILL 1118 - */ 1119 - if ((fujitsu_hotkey->rfkill_supported & BIT(26)) && 1120 - (call_fext_func(FUNC_RFKILL, 0x1, 0x0, 0x0) & BIT(26))) { 1121 - keycode = KEY_TOUCHPAD_TOGGLE; 1122 - input_report_key(input, keycode, 1); 1123 - input_sync(input); 1124 - input_report_key(input, keycode, 0); 1125 - input_sync(input); 1126 - } 1127 - 1128 - break; 1129 - default: 1079 + if (event != ACPI_FUJITSU_NOTIFY_CODE1) { 1130 1080 keycode = KEY_UNKNOWN; 1131 1081 vdbg_printk(FUJLAPTOP_DBG_WARN, 1132 1082 "Unsupported event [0x%x]\n", event); ··· 1090 1128 input_sync(input); 1091 1129 input_report_key(input, keycode, 0); 1092 1130 input_sync(input); 1093 - break; 1131 + return; 1094 1132 } 1133 + 1134 + if (fujitsu_hotkey->rfkill_supported) 1135 + fujitsu_hotkey->rfkill_state = 1136 + call_fext_func(FUNC_RFKILL, 0x4, 0x0, 0x0); 1137 + 1138 + i = 0; 1139 + while ((irb = 1140 + call_fext_func(FUNC_BUTTONS, 0x1, 0x0, 0x0)) != 0 1141 + && (i++) < MAX_HOTKEY_RINGBUFFER_SIZE) { 1142 + switch (irb & 0x4ff) { 1143 + case KEY1_CODE: 1144 + keycode = fujitsu->keycode1; 1145 + break; 1146 + case KEY2_CODE: 1147 + keycode = fujitsu->keycode2; 1148 + break; 1149 + case KEY3_CODE: 1150 + keycode = fujitsu->keycode3; 1151 + break; 1152 + case KEY4_CODE: 1153 + keycode = fujitsu->keycode4; 1154 + break; 1155 + case KEY5_CODE: 1156 + keycode = fujitsu->keycode5; 1157 + break; 1158 + case 0: 1159 + keycode = 0; 1160 + break; 1161 + default: 1162 + vdbg_printk(FUJLAPTOP_DBG_WARN, 1163 + "Unknown GIRB result [%x]\n", irb); 1164 + keycode = -1; 1165 + break; 1166 + } 1167 + 1168 + if (keycode > 0) 1169 + acpi_fujitsu_hotkey_press(keycode); 1170 + else if (keycode == 0) 1171 + acpi_fujitsu_hotkey_release(); 1172 + } 1173 + 1174 + /* On some models (first seen on the Skylake-based Lifebook 1175 + * E736/E746/E756), the touchpad toggle hotkey (Fn+F4) is 1176 + * handled in software; its state is queried using FUNC_RFKILL 1177 + */ 1178 + if ((fujitsu_hotkey->rfkill_supported & BIT(26)) && 1179 + (call_fext_func(FUNC_RFKILL, 0x1, 0x0, 0x0) & BIT(26))) { 1180 + keycode = KEY_TOUCHPAD_TOGGLE; 1181 + input_report_key(input, keycode, 1); 1182 + input_sync(input); 1183 + input_report_key(input, keycode, 0); 1184 + input_sync(input); 1185 + } 1186 + 1095 1187 } 1096 1188 1097 1189 /* Initialization */
+1
drivers/platform/x86/hp_accel.c
··· 251 251 AXIS_DMI_MATCH("HPB64xx", "HP EliteBook 84", xy_swap), 252 252 AXIS_DMI_MATCH("HPB65xx", "HP ProBook 65", x_inverted), 253 253 AXIS_DMI_MATCH("HPZBook15", "HP ZBook 15", x_inverted), 254 + AXIS_DMI_MATCH("HPZBook17", "HP ZBook 17", xy_swap_yz_inverted), 254 255 { NULL, } 255 256 /* Laptop models without axis info (yet): 256 257 * "NC6910" "HP Compaq 6910"
+91 -5
drivers/platform/x86/intel-hid.c
··· 1 1 /* 2 - * Intel HID event driver for Windows 8 2 + * Intel HID event & 5 button array driver 3 3 * 4 4 * Copyright (C) 2015 Alex Hung <alex.hung@canonical.com> 5 5 * Copyright (C) 2015 Andrew Lutomirski <luto@kernel.org> ··· 57 57 { KE_END }, 58 58 }; 59 59 60 + /* 5 button array notification value. */ 61 + static const struct key_entry intel_array_keymap[] = { 62 + { KE_KEY, 0xC2, { KEY_LEFTMETA } }, /* Press */ 63 + { KE_IGNORE, 0xC3, { KEY_LEFTMETA } }, /* Release */ 64 + { KE_KEY, 0xC4, { KEY_VOLUMEUP } }, /* Press */ 65 + { KE_IGNORE, 0xC5, { KEY_VOLUMEUP } }, /* Release */ 66 + { KE_KEY, 0xC6, { KEY_VOLUMEDOWN } }, /* Press */ 67 + { KE_IGNORE, 0xC7, { KEY_VOLUMEDOWN } }, /* Release */ 68 + { KE_SW, 0xC8, { .sw = { SW_ROTATE_LOCK, 1 } } }, /* Press */ 69 + { KE_SW, 0xC9, { .sw = { SW_ROTATE_LOCK, 0 } } }, /* Release */ 70 + { KE_KEY, 0xCE, { KEY_POWER } }, /* Press */ 71 + { KE_IGNORE, 0xCF, { KEY_POWER } }, /* Release */ 72 + { KE_END }, 73 + }; 74 + 60 75 struct intel_hid_priv { 61 76 struct input_dev *input_dev; 77 + struct input_dev *array; 62 78 }; 63 79 64 80 static int intel_hid_set_enable(struct device *device, int enable) ··· 94 78 return 0; 95 79 } 96 80 81 + static void intel_button_array_enable(struct device *device, bool enable) 82 + { 83 + struct intel_hid_priv *priv = dev_get_drvdata(device); 84 + acpi_handle handle = ACPI_HANDLE(device); 85 + unsigned long long button_cap; 86 + acpi_status status; 87 + 88 + if (!priv->array) 89 + return; 90 + 91 + /* Query supported platform features */ 92 + status = acpi_evaluate_integer(handle, "BTNC", NULL, &button_cap); 93 + if (ACPI_FAILURE(status)) { 94 + dev_warn(device, "failed to get button capability\n"); 95 + return; 96 + } 97 + 98 + /* Enable|disable features - power button is always enabled */ 99 + status = acpi_execute_simple_method(handle, "BTNE", 100 + enable ? button_cap : 1); 101 + if (ACPI_FAILURE(status)) 102 + dev_warn(device, "failed to set button capability\n"); 103 + } 104 + 97 105 static int intel_hid_pl_suspend_handler(struct device *device) 98 106 { 99 107 intel_hid_set_enable(device, 0); 108 + intel_button_array_enable(device, false); 109 + 100 110 return 0; 101 111 } 102 112 103 113 static int intel_hid_pl_resume_handler(struct device *device) 104 114 { 105 115 intel_hid_set_enable(device, 1); 116 + intel_button_array_enable(device, true); 117 + 106 118 return 0; 107 119 } 108 120 ··· 170 126 return ret; 171 127 } 172 128 129 + static int intel_button_array_input_setup(struct platform_device *device) 130 + { 131 + struct intel_hid_priv *priv = dev_get_drvdata(&device->dev); 132 + int ret; 133 + 134 + /* Setup input device for 5 button array */ 135 + priv->array = devm_input_allocate_device(&device->dev); 136 + if (!priv->array) 137 + return -ENOMEM; 138 + 139 + ret = sparse_keymap_setup(priv->array, intel_array_keymap, NULL); 140 + if (ret) 141 + return ret; 142 + 143 + priv->array->dev.parent = &device->dev; 144 + priv->array->name = "Intel HID 5 button array"; 145 + priv->array->id.bustype = BUS_HOST; 146 + 147 + return input_register_device(priv->array); 148 + } 149 + 173 150 static void intel_hid_input_destroy(struct platform_device *device) 174 151 { 175 152 struct intel_hid_priv *priv = dev_get_drvdata(&device->dev); ··· 205 140 unsigned long long ev_index; 206 141 acpi_status status; 207 142 208 - /* The platform spec only defines one event code: 0xC0. */ 143 + /* 0xC0 is for HID events, other values are for 5 button array */ 209 144 if (event != 0xc0) { 210 - dev_warn(&device->dev, "received unknown event (0x%x)\n", 211 - event); 145 + if (!priv->array || 146 + !sparse_keymap_report_event(priv->array, event, 1, true)) 147 + dev_info(&device->dev, "unknown event 0x%x\n", event); 212 148 return; 213 149 } 214 150 ··· 227 161 static int intel_hid_probe(struct platform_device *device) 228 162 { 229 163 acpi_handle handle = ACPI_HANDLE(&device->dev); 164 + unsigned long long event_cap, mode; 230 165 struct intel_hid_priv *priv; 231 - unsigned long long mode; 232 166 acpi_status status; 233 167 int err; 234 168 ··· 259 193 return err; 260 194 } 261 195 196 + /* Setup 5 button array */ 197 + status = acpi_evaluate_integer(handle, "HEBC", NULL, &event_cap); 198 + if (ACPI_SUCCESS(status) && (event_cap & 0x20000)) { 199 + dev_info(&device->dev, "platform supports 5 button array\n"); 200 + err = intel_button_array_input_setup(device); 201 + if (err) 202 + pr_err("Failed to setup Intel 5 button array hotkeys\n"); 203 + } 204 + 262 205 status = acpi_install_notify_handler(handle, 263 206 ACPI_DEVICE_NOTIFY, 264 207 notify_handler, ··· 280 205 err = intel_hid_set_enable(&device->dev, 1); 281 206 if (err) 282 207 goto err_remove_notify; 208 + 209 + if (priv->array) { 210 + intel_button_array_enable(&device->dev, true); 211 + 212 + /* Call button load method to enable HID power button */ 213 + status = acpi_evaluate_object(handle, "BTNL", NULL, NULL); 214 + if (ACPI_FAILURE(status)) 215 + dev_warn(&device->dev, 216 + "failed to enable HID power button\n"); 217 + } 283 218 284 219 return 0; 285 220 ··· 309 224 acpi_remove_notify_handler(handle, ACPI_DEVICE_NOTIFY, notify_handler); 310 225 intel_hid_input_destroy(device); 311 226 intel_hid_set_enable(&device->dev, 0); 227 + intel_button_array_enable(&device->dev, false); 312 228 313 229 /* 314 230 * Even if we failed to shut off the event stream, we can still
+135 -52
drivers/platform/x86/intel_mid_powerbtn.c
··· 1 1 /* 2 - * Power button driver for Medfield. 2 + * Power button driver for Intel MID platforms. 3 3 * 4 - * Copyright (C) 2010 Intel Corp 4 + * Copyright (C) 2010,2017 Intel Corp 5 + * 6 + * Author: Hong Liu <hong.liu@intel.com> 7 + * Author: Andy Shevchenko <andriy.shevchenko@linux.intel.com> 5 8 * 6 9 * This program is free software; you can redistribute it and/or modify 7 10 * it under the terms of the GNU General Public License as published by ··· 14 11 * WITHOUT ANY WARRANTY; without even the implied warranty of 15 12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 16 13 * General Public License for more details. 17 - * 18 - * You should have received a copy of the GNU General Public License along 19 - * with this program; if not, write to the Free Software Foundation, Inc., 20 - * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. 21 14 */ 22 15 23 - #include <linux/module.h> 24 16 #include <linux/init.h> 25 - #include <linux/interrupt.h> 26 - #include <linux/slab.h> 27 - #include <linux/platform_device.h> 28 17 #include <linux/input.h> 18 + #include <linux/interrupt.h> 29 19 #include <linux/mfd/intel_msic.h> 20 + #include <linux/module.h> 21 + #include <linux/platform_device.h> 30 22 #include <linux/pm_wakeirq.h> 23 + #include <linux/slab.h> 24 + 25 + #include <asm/cpu_device_id.h> 26 + #include <asm/intel-family.h> 27 + #include <asm/intel_scu_ipc.h> 31 28 32 29 #define DRIVER_NAME "msic_power_btn" 33 30 ··· 39 36 */ 40 37 #define MSIC_PWRBTNM (1 << 0) 41 38 42 - static irqreturn_t mfld_pb_isr(int irq, void *dev_id) 39 + /* Intel Tangier */ 40 + #define BCOVE_PB_LEVEL (1 << 4) /* 1 - release, 0 - press */ 41 + 42 + /* Basin Cove PMIC */ 43 + #define BCOVE_PBIRQ 0x02 44 + #define BCOVE_IRQLVL1MSK 0x0c 45 + #define BCOVE_PBIRQMASK 0x0d 46 + #define BCOVE_PBSTATUS 0x27 47 + 48 + struct mid_pb_ddata { 49 + struct device *dev; 50 + int irq; 51 + struct input_dev *input; 52 + unsigned short mirqlvl1_addr; 53 + unsigned short pbstat_addr; 54 + u8 pbstat_mask; 55 + int (*setup)(struct mid_pb_ddata *ddata); 56 + }; 57 + 58 + static int mid_pbstat(struct mid_pb_ddata *ddata, int *value) 43 59 { 44 - struct input_dev *input = dev_id; 60 + struct input_dev *input = ddata->input; 45 61 int ret; 46 62 u8 pbstat; 47 63 48 - ret = intel_msic_reg_read(INTEL_MSIC_PBSTATUS, &pbstat); 64 + ret = intel_scu_ipc_ioread8(ddata->pbstat_addr, &pbstat); 65 + if (ret) 66 + return ret; 67 + 49 68 dev_dbg(input->dev.parent, "PB_INT status= %d\n", pbstat); 50 69 70 + *value = !(pbstat & ddata->pbstat_mask); 71 + return 0; 72 + } 73 + 74 + static int mid_irq_ack(struct mid_pb_ddata *ddata) 75 + { 76 + return intel_scu_ipc_update_register(ddata->mirqlvl1_addr, 0, MSIC_PWRBTNM); 77 + } 78 + 79 + static int mrfld_setup(struct mid_pb_ddata *ddata) 80 + { 81 + /* Unmask the PBIRQ and MPBIRQ on Tangier */ 82 + intel_scu_ipc_update_register(BCOVE_PBIRQ, 0, MSIC_PWRBTNM); 83 + intel_scu_ipc_update_register(BCOVE_PBIRQMASK, 0, MSIC_PWRBTNM); 84 + 85 + return 0; 86 + } 87 + 88 + static irqreturn_t mid_pb_isr(int irq, void *dev_id) 89 + { 90 + struct mid_pb_ddata *ddata = dev_id; 91 + struct input_dev *input = ddata->input; 92 + int value = 0; 93 + int ret; 94 + 95 + ret = mid_pbstat(ddata, &value); 51 96 if (ret < 0) { 52 - dev_err(input->dev.parent, "Read error %d while reading" 53 - " MSIC_PB_STATUS\n", ret); 97 + dev_err(input->dev.parent, 98 + "Read error %d while reading MSIC_PB_STATUS\n", ret); 54 99 } else { 55 - input_event(input, EV_KEY, KEY_POWER, 56 - !(pbstat & MSIC_PB_LEVEL)); 100 + input_event(input, EV_KEY, KEY_POWER, value); 57 101 input_sync(input); 58 102 } 59 103 104 + mid_irq_ack(ddata); 60 105 return IRQ_HANDLED; 61 106 } 62 107 63 - static int mfld_pb_probe(struct platform_device *pdev) 108 + static struct mid_pb_ddata mfld_ddata = { 109 + .mirqlvl1_addr = INTEL_MSIC_IRQLVL1MSK, 110 + .pbstat_addr = INTEL_MSIC_PBSTATUS, 111 + .pbstat_mask = MSIC_PB_LEVEL, 112 + }; 113 + 114 + static struct mid_pb_ddata mrfld_ddata = { 115 + .mirqlvl1_addr = BCOVE_IRQLVL1MSK, 116 + .pbstat_addr = BCOVE_PBSTATUS, 117 + .pbstat_mask = BCOVE_PB_LEVEL, 118 + .setup = mrfld_setup, 119 + }; 120 + 121 + #define ICPU(model, ddata) \ 122 + { X86_VENDOR_INTEL, 6, model, X86_FEATURE_ANY, (kernel_ulong_t)&ddata } 123 + 124 + static const struct x86_cpu_id mid_pb_cpu_ids[] = { 125 + ICPU(INTEL_FAM6_ATOM_PENWELL, mfld_ddata), 126 + ICPU(INTEL_FAM6_ATOM_MERRIFIELD, mrfld_ddata), 127 + {} 128 + }; 129 + 130 + static int mid_pb_probe(struct platform_device *pdev) 64 131 { 132 + const struct x86_cpu_id *id; 133 + struct mid_pb_ddata *ddata; 65 134 struct input_dev *input; 66 135 int irq = platform_get_irq(pdev, 0); 67 136 int error; 68 137 138 + id = x86_match_cpu(mid_pb_cpu_ids); 139 + if (!id) 140 + return -ENODEV; 141 + 69 142 if (irq < 0) 70 143 return -EINVAL; 71 144 72 - input = input_allocate_device(); 145 + input = devm_input_allocate_device(&pdev->dev); 73 146 if (!input) 74 147 return -ENOMEM; 75 148 ··· 156 77 157 78 input_set_capability(input, EV_KEY, KEY_POWER); 158 79 159 - error = request_threaded_irq(irq, NULL, mfld_pb_isr, IRQF_ONESHOT, 160 - DRIVER_NAME, input); 161 - if (error) { 162 - dev_err(&pdev->dev, "Unable to request irq %d for mfld power" 163 - "button\n", irq); 164 - goto err_free_input; 80 + ddata = (struct mid_pb_ddata *)id->driver_data; 81 + if (!ddata) 82 + return -ENODATA; 83 + 84 + ddata->dev = &pdev->dev; 85 + ddata->irq = irq; 86 + ddata->input = input; 87 + 88 + if (ddata->setup) { 89 + error = ddata->setup(ddata); 90 + if (error) 91 + return error; 165 92 } 166 93 167 - device_init_wakeup(&pdev->dev, true); 168 - dev_pm_set_wake_irq(&pdev->dev, irq); 94 + error = devm_request_threaded_irq(&pdev->dev, irq, NULL, mid_pb_isr, 95 + IRQF_ONESHOT, DRIVER_NAME, ddata); 96 + if (error) { 97 + dev_err(&pdev->dev, 98 + "Unable to request irq %d for MID power button\n", irq); 99 + return error; 100 + } 169 101 170 102 error = input_register_device(input); 171 103 if (error) { 172 - dev_err(&pdev->dev, "Unable to register input dev, error " 173 - "%d\n", error); 174 - goto err_free_irq; 104 + dev_err(&pdev->dev, 105 + "Unable to register input dev, error %d\n", error); 106 + return error; 175 107 } 176 108 177 - platform_set_drvdata(pdev, input); 109 + platform_set_drvdata(pdev, ddata); 178 110 179 111 /* 180 112 * SCU firmware might send power button interrupts to IA core before ··· 197 107 * initialization. The race happens rarely. So we needn't worry 198 108 * about it. 199 109 */ 200 - error = intel_msic_reg_update(INTEL_MSIC_IRQLVL1MSK, 0, MSIC_PWRBTNM); 110 + error = mid_irq_ack(ddata); 201 111 if (error) { 202 - dev_err(&pdev->dev, "Unable to clear power button interrupt, " 203 - "error: %d\n", error); 204 - goto err_free_irq; 112 + dev_err(&pdev->dev, 113 + "Unable to clear power button interrupt, error: %d\n", 114 + error); 115 + return error; 205 116 } 206 117 207 - return 0; 118 + device_init_wakeup(&pdev->dev, true); 119 + dev_pm_set_wake_irq(&pdev->dev, irq); 208 120 209 - err_free_irq: 210 - free_irq(irq, input); 211 - err_free_input: 212 - input_free_device(input); 213 - return error; 121 + return 0; 214 122 } 215 123 216 - static int mfld_pb_remove(struct platform_device *pdev) 124 + static int mid_pb_remove(struct platform_device *pdev) 217 125 { 218 - struct input_dev *input = platform_get_drvdata(pdev); 219 - int irq = platform_get_irq(pdev, 0); 220 - 221 126 dev_pm_clear_wake_irq(&pdev->dev); 222 127 device_init_wakeup(&pdev->dev, false); 223 - free_irq(irq, input); 224 - input_unregister_device(input); 225 128 226 129 return 0; 227 130 } 228 131 229 - static struct platform_driver mfld_pb_driver = { 132 + static struct platform_driver mid_pb_driver = { 230 133 .driver = { 231 134 .name = DRIVER_NAME, 232 135 }, 233 - .probe = mfld_pb_probe, 234 - .remove = mfld_pb_remove, 136 + .probe = mid_pb_probe, 137 + .remove = mid_pb_remove, 235 138 }; 236 139 237 - module_platform_driver(mfld_pb_driver); 140 + module_platform_driver(mid_pb_driver); 238 141 239 142 MODULE_AUTHOR("Hong Liu <hong.liu@intel.com>"); 240 - MODULE_DESCRIPTION("Intel Medfield Power Button Driver"); 143 + MODULE_DESCRIPTION("Intel MID Power Button Driver"); 241 144 MODULE_LICENSE("GPL v2"); 242 145 MODULE_ALIAS("platform:" DRIVER_NAME);
+1 -1
drivers/platform/x86/intel_mid_thermal.c
··· 549 549 550 550 static const struct platform_device_id therm_id_table[] = { 551 551 { DRIVER_NAME, 1 }, 552 - { "msic_thermal", 1 }, 553 552 { } 554 553 }; 554 + MODULE_DEVICE_TABLE(platform, therm_id_table); 555 555 556 556 static struct platform_driver mid_thermal_driver = { 557 557 .driver = {
+2 -4
drivers/platform/x86/intel_pmc_core.c
··· 188 188 u32 value; 189 189 190 190 value = pmc_core_reg_read(pmcdev, SPT_PMC_PM_CFG_OFFSET); 191 - return test_bit(SPT_PMC_READ_DISABLE_BIT, 192 - (unsigned long *)&value); 191 + return value & BIT(SPT_PMC_READ_DISABLE_BIT); 193 192 } 194 193 195 194 #if IS_ENABLED(CONFIG_DEBUG_FS) ··· 237 238 u32 value; 238 239 239 240 value = pmc_core_reg_read(pmcdev, SPT_PMC_PM_STS_OFFSET); 240 - return test_bit(SPT_PMC_MSG_FULL_STS_BIT, 241 - (unsigned long *)&value); 241 + return value & BIT(SPT_PMC_MSG_FULL_STS_BIT); 242 242 } 243 243 244 244 static int pmc_core_send_msg(u32 *addr_xram)
+59 -8
drivers/platform/x86/intel_pmc_ipc.c
··· 32 32 #include <linux/notifier.h> 33 33 #include <linux/suspend.h> 34 34 #include <linux/acpi.h> 35 + #include <linux/io-64-nonatomic-lo-hi.h> 36 + 35 37 #include <asm/intel_pmc_ipc.h> 38 + 36 39 #include <linux/platform_data/itco_wdt.h> 37 40 38 41 /* ··· 57 54 #define IPC_WRITE_BUFFER 0x80 58 55 #define IPC_READ_BUFFER 0x90 59 56 57 + /* PMC Global Control Registers */ 58 + #define GCR_TELEM_DEEP_S0IX_OFFSET 0x1078 59 + #define GCR_TELEM_SHLW_S0IX_OFFSET 0x1080 60 + 61 + /* Residency with clock rate at 19.2MHz to usecs */ 62 + #define S0IX_RESIDENCY_IN_USECS(d, s) \ 63 + ({ \ 64 + u64 result = 10ull * ((d) + (s)); \ 65 + do_div(result, 192); \ 66 + result; \ 67 + }) 68 + 60 69 /* 61 70 * 16-byte buffer for sending data associated with IPC command. 62 71 */ ··· 83 68 #define PLAT_RESOURCE_IPC_INDEX 0 84 69 #define PLAT_RESOURCE_IPC_SIZE 0x1000 85 70 #define PLAT_RESOURCE_GCR_OFFSET 0x1008 86 - #define PLAT_RESOURCE_GCR_SIZE 0x4 71 + #define PLAT_RESOURCE_GCR_SIZE 0x1000 87 72 #define PLAT_RESOURCE_BIOS_DATA_INDEX 1 88 73 #define PLAT_RESOURCE_BIOS_IFACE_INDEX 2 89 74 #define PLAT_RESOURCE_TELEM_SSRAM_INDEX 3 ··· 112 97 #define TCO_PMC_OFFSET 0x8 113 98 #define TCO_PMC_SIZE 0x4 114 99 115 - static const int iTCO_version = 3; 116 - 117 100 static struct intel_pmc_ipc_dev { 118 101 struct device *dev; 119 102 void __iomem *ipc_base; ··· 128 115 /* gcr */ 129 116 resource_size_t gcr_base; 130 117 int gcr_size; 118 + bool has_gcr_regs; 131 119 132 120 /* punit */ 133 121 struct platform_device *punit_dev; ··· 192 178 static inline u32 ipc_data_readl(u32 offset) 193 179 { 194 180 return readl(ipcdev.ipc_base + IPC_READ_BUFFER + offset); 181 + } 182 + 183 + static inline u64 gcr_data_readq(u32 offset) 184 + { 185 + return readq(ipcdev.ipc_base + offset); 195 186 } 196 187 197 188 static int intel_pmc_ipc_check_status(void) ··· 408 389 static const struct pci_device_id ipc_pci_ids[] = { 409 390 {PCI_VDEVICE(INTEL, 0x0a94), 0}, 410 391 {PCI_VDEVICE(INTEL, 0x1a94), 0}, 392 + {PCI_VDEVICE(INTEL, 0x5a94), 0}, 411 393 { 0,} 412 394 }; 413 395 MODULE_DEVICE_TABLE(pci, ipc_pci_ids); ··· 732 712 dev_err(&pdev->dev, "Failed to get ipc resource\n"); 733 713 return -ENXIO; 734 714 } 735 - size = PLAT_RESOURCE_IPC_SIZE; 715 + size = PLAT_RESOURCE_IPC_SIZE + PLAT_RESOURCE_GCR_SIZE; 716 + 736 717 if (!request_mem_region(res->start, size, pdev->name)) { 737 718 dev_err(&pdev->dev, "Failed to request ipc resource\n"); 738 719 return -EBUSY; ··· 768 747 769 748 return 0; 770 749 } 750 + 751 + /** 752 + * intel_pmc_s0ix_counter_read() - Read S0ix residency. 753 + * @data: Out param that contains current S0ix residency count. 754 + * 755 + * Return: an error code or 0 on success. 756 + */ 757 + int intel_pmc_s0ix_counter_read(u64 *data) 758 + { 759 + u64 deep, shlw; 760 + 761 + if (!ipcdev.has_gcr_regs) 762 + return -EACCES; 763 + 764 + deep = gcr_data_readq(GCR_TELEM_DEEP_S0IX_OFFSET); 765 + shlw = gcr_data_readq(GCR_TELEM_SHLW_S0IX_OFFSET); 766 + 767 + *data = S0IX_RESIDENCY_IN_USECS(deep, shlw); 768 + 769 + return 0; 770 + } 771 + EXPORT_SYMBOL_GPL(intel_pmc_s0ix_counter_read); 771 772 772 773 #ifdef CONFIG_ACPI 773 774 static const struct acpi_device_id ipc_acpi_ids[] = { ··· 840 797 goto err_sys; 841 798 } 842 799 800 + ipcdev.has_gcr_regs = true; 801 + 843 802 return 0; 844 803 err_sys: 845 804 free_irq(ipcdev.irq, &ipcdev); ··· 853 808 iounmap(ipcdev.ipc_base); 854 809 res = platform_get_resource(pdev, IORESOURCE_MEM, 855 810 PLAT_RESOURCE_IPC_INDEX); 856 - if (res) 857 - release_mem_region(res->start, PLAT_RESOURCE_IPC_SIZE); 811 + if (res) { 812 + release_mem_region(res->start, 813 + PLAT_RESOURCE_IPC_SIZE + 814 + PLAT_RESOURCE_GCR_SIZE); 815 + } 858 816 return ret; 859 817 } 860 818 ··· 873 825 iounmap(ipcdev.ipc_base); 874 826 res = platform_get_resource(pdev, IORESOURCE_MEM, 875 827 PLAT_RESOURCE_IPC_INDEX); 876 - if (res) 877 - release_mem_region(res->start, PLAT_RESOURCE_IPC_SIZE); 828 + if (res) { 829 + release_mem_region(res->start, 830 + PLAT_RESOURCE_IPC_SIZE + 831 + PLAT_RESOURCE_GCR_SIZE); 832 + } 878 833 ipcdev.dev = NULL; 879 834 return 0; 880 835 }
+151
drivers/platform/x86/intel_turbo_max_3.c
··· 1 + /* 2 + * Intel Turbo Boost Max Technology 3.0 legacy (non HWP) enumeration driver 3 + * Copyright (c) 2017, Intel Corporation. 4 + * All rights reserved. 5 + * 6 + * Author: Srinivas Pandruvada <srinivas.pandruvada@linux.intel.com> 7 + * 8 + * This program is free software; you can redistribute it and/or modify it 9 + * under the terms and conditions of the GNU General Public License, 10 + * version 2, as published by the Free Software Foundation. 11 + * 12 + * This program is distributed in the hope it will be useful, but WITHOUT 13 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 14 + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for 15 + * more details. 16 + * 17 + */ 18 + #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt 19 + 20 + #include <linux/kernel.h> 21 + #include <linux/init.h> 22 + #include <linux/topology.h> 23 + #include <linux/workqueue.h> 24 + #include <linux/cpuhotplug.h> 25 + #include <linux/cpufeature.h> 26 + #include <asm/cpu_device_id.h> 27 + #include <asm/intel-family.h> 28 + 29 + #define MSR_OC_MAILBOX 0x150 30 + #define MSR_OC_MAILBOX_CMD_OFFSET 32 31 + #define MSR_OC_MAILBOX_RSP_OFFSET 32 32 + #define MSR_OC_MAILBOX_BUSY_BIT 63 33 + #define OC_MAILBOX_FC_CONTROL_CMD 0x1C 34 + 35 + /* 36 + * Typical latency to get mail box response is ~3us, It takes +3 us to 37 + * process reading mailbox after issuing mailbox write on a Broadwell 3.4 GHz 38 + * system. So for most of the time, the first mailbox read should have the 39 + * response, but to avoid some boundary cases retry twice. 40 + */ 41 + #define OC_MAILBOX_RETRY_COUNT 2 42 + 43 + static int get_oc_core_priority(unsigned int cpu) 44 + { 45 + u64 value, cmd = OC_MAILBOX_FC_CONTROL_CMD; 46 + int ret, i; 47 + 48 + /* Issue favored core read command */ 49 + value = cmd << MSR_OC_MAILBOX_CMD_OFFSET; 50 + /* Set the busy bit to indicate OS is trying to issue command */ 51 + value |= BIT_ULL(MSR_OC_MAILBOX_BUSY_BIT); 52 + ret = wrmsrl_safe(MSR_OC_MAILBOX, value); 53 + if (ret) { 54 + pr_debug("cpu %d OC mailbox write failed\n", cpu); 55 + return ret; 56 + } 57 + 58 + for (i = 0; i < OC_MAILBOX_RETRY_COUNT; ++i) { 59 + ret = rdmsrl_safe(MSR_OC_MAILBOX, &value); 60 + if (ret) { 61 + pr_debug("cpu %d OC mailbox read failed\n", cpu); 62 + break; 63 + } 64 + 65 + if (value & BIT_ULL(MSR_OC_MAILBOX_BUSY_BIT)) { 66 + pr_debug("cpu %d OC mailbox still processing\n", cpu); 67 + ret = -EBUSY; 68 + continue; 69 + } 70 + 71 + if ((value >> MSR_OC_MAILBOX_RSP_OFFSET) & 0xff) { 72 + pr_debug("cpu %d OC mailbox cmd failed\n", cpu); 73 + ret = -ENXIO; 74 + break; 75 + } 76 + 77 + ret = value & 0xff; 78 + pr_debug("cpu %d max_ratio %d\n", cpu, ret); 79 + break; 80 + } 81 + 82 + return ret; 83 + } 84 + 85 + /* 86 + * The work item is needed to avoid CPU hotplug locking issues. The function 87 + * itmt_legacy_set_priority() is called from CPU online callback, so can't 88 + * call sched_set_itmt_support() from there as this function will aquire 89 + * hotplug locks in its path. 90 + */ 91 + static void itmt_legacy_work_fn(struct work_struct *work) 92 + { 93 + sched_set_itmt_support(); 94 + } 95 + 96 + static DECLARE_WORK(sched_itmt_work, itmt_legacy_work_fn); 97 + 98 + static int itmt_legacy_cpu_online(unsigned int cpu) 99 + { 100 + static u32 max_highest_perf = 0, min_highest_perf = U32_MAX; 101 + int priority; 102 + 103 + priority = get_oc_core_priority(cpu); 104 + if (priority < 0) 105 + return 0; 106 + 107 + sched_set_itmt_core_prio(priority, cpu); 108 + 109 + /* Enable ITMT feature when a core with different priority is found */ 110 + if (max_highest_perf <= min_highest_perf) { 111 + if (priority > max_highest_perf) 112 + max_highest_perf = priority; 113 + 114 + if (priority < min_highest_perf) 115 + min_highest_perf = priority; 116 + 117 + if (max_highest_perf > min_highest_perf) 118 + schedule_work(&sched_itmt_work); 119 + } 120 + 121 + return 0; 122 + } 123 + 124 + #define ICPU(model) { X86_VENDOR_INTEL, 6, model, X86_FEATURE_ANY, } 125 + 126 + static const struct x86_cpu_id itmt_legacy_cpu_ids[] = { 127 + ICPU(INTEL_FAM6_BROADWELL_X), 128 + {} 129 + }; 130 + 131 + static int __init itmt_legacy_init(void) 132 + { 133 + const struct x86_cpu_id *id; 134 + int ret; 135 + 136 + id = x86_match_cpu(itmt_legacy_cpu_ids); 137 + if (!id) 138 + return -ENODEV; 139 + 140 + if (boot_cpu_has(X86_FEATURE_HWP)) 141 + return -ENODEV; 142 + 143 + ret = cpuhp_setup_state(CPUHP_AP_ONLINE_DYN, 144 + "platform/x86/turbo_max_3:online", 145 + itmt_legacy_cpu_online, NULL); 146 + if (ret < 0) 147 + return ret; 148 + 149 + return 0; 150 + } 151 + late_initcall(itmt_legacy_init)
+50 -34
drivers/platform/x86/mlx-platform.c
··· 45 45 /* LPC bus IO offsets */ 46 46 #define MLXPLAT_CPLD_LPC_I2C_BASE_ADRR 0x2000 47 47 #define MLXPLAT_CPLD_LPC_REG_BASE_ADRR 0x2500 48 + #define MLXPLAT_CPLD_LPC_REG_AGGR_ADRR 0x253a 49 + #define MLXPLAT_CPLD_LPC_REG_PSU_ADRR 0x2558 50 + #define MLXPLAT_CPLD_LPC_REG_PWR_ADRR 0x2564 51 + #define MLXPLAT_CPLD_LPC_REG_FAN_ADRR 0x2588 48 52 #define MLXPLAT_CPLD_LPC_IO_RANGE 0x100 49 53 #define MLXPLAT_CPLD_LPC_I2C_CH1_OFF 0xdb 50 54 #define MLXPLAT_CPLD_LPC_I2C_CH2_OFF 0xda ··· 59 55 #define MLXPLAT_CPLD_LPC_REG2 ((MLXPLAT_CPLD_LPC_REG_BASE_ADRR + \ 60 56 MLXPLAT_CPLD_LPC_I2C_CH2_OFF) | \ 61 57 MLXPLAT_CPLD_LPC_PIO_OFFSET) 58 + 59 + /* Masks for aggregation, psu, pwr and fan event in CPLD related registers. */ 60 + #define MLXPLAT_CPLD_AGGR_PSU_MASK_DEF 0x08 61 + #define MLXPLAT_CPLD_AGGR_PWR_MASK_DEF 0x08 62 + #define MLXPLAT_CPLD_AGGR_FAN_MASK_DEF 0x40 63 + #define MLXPLAT_CPLD_AGGR_MASK_DEF (MLXPLAT_CPLD_AGGR_PSU_MASK_DEF | \ 64 + MLXPLAT_CPLD_AGGR_FAN_MASK_DEF) 65 + #define MLXPLAT_CPLD_AGGR_MASK_MSN21XX 0x04 66 + #define MLXPLAT_CPLD_PSU_MASK GENMASK(1, 0) 67 + #define MLXPLAT_CPLD_PWR_MASK GENMASK(1, 0) 68 + #define MLXPLAT_CPLD_FAN_MASK GENMASK(3, 0) 62 69 63 70 /* Start channel numbers */ 64 71 #define MLXPLAT_CPLD_CH1 2 ··· 138 123 }; 139 124 140 125 /* Platform hotplug devices */ 141 - static struct mlxcpld_hotplug_device mlxplat_mlxcpld_hotplug_psu[] = { 126 + static struct mlxcpld_hotplug_device mlxplat_mlxcpld_psu[] = { 142 127 { 143 128 .brdinfo = { I2C_BOARD_INFO("24c02", 0x51) }, 144 129 .bus = 10, ··· 149 134 }, 150 135 }; 151 136 152 - static struct mlxcpld_hotplug_device mlxplat_mlxcpld_hotplug_pwr[] = { 137 + static struct mlxcpld_hotplug_device mlxplat_mlxcpld_pwr[] = { 153 138 { 154 139 .brdinfo = { I2C_BOARD_INFO("dps460", 0x59) }, 155 140 .bus = 10, ··· 160 145 }, 161 146 }; 162 147 163 - static struct mlxcpld_hotplug_device mlxplat_mlxcpld_hotplug_fan[] = { 148 + static struct mlxcpld_hotplug_device mlxplat_mlxcpld_fan[] = { 164 149 { 165 150 .brdinfo = { I2C_BOARD_INFO("24c32", 0x50) }, 166 151 .bus = 11, ··· 181 166 182 167 /* Platform hotplug default data */ 183 168 static 184 - struct mlxcpld_hotplug_platform_data mlxplat_mlxcpld_hotplug_default_data = { 185 - .top_aggr_offset = (MLXPLAT_CPLD_LPC_REG_BASE_ADRR | 0x3a), 186 - .top_aggr_mask = 0x48, 187 - .top_aggr_psu_mask = 0x08, 188 - .psu_reg_offset = (MLXPLAT_CPLD_LPC_REG_BASE_ADRR | 0x58), 189 - .psu_mask = 0x03, 190 - .psu_count = ARRAY_SIZE(mlxplat_mlxcpld_hotplug_psu), 191 - .psu = mlxplat_mlxcpld_hotplug_psu, 192 - .top_aggr_pwr_mask = 0x08, 193 - .pwr_reg_offset = (MLXPLAT_CPLD_LPC_REG_BASE_ADRR | 0x64), 194 - .pwr_mask = 0x03, 195 - .pwr_count = ARRAY_SIZE(mlxplat_mlxcpld_hotplug_pwr), 196 - .pwr = mlxplat_mlxcpld_hotplug_pwr, 197 - .top_aggr_fan_mask = 0x40, 198 - .fan_reg_offset = (MLXPLAT_CPLD_LPC_REG_BASE_ADRR | 0x88), 199 - .fan_mask = 0x0f, 200 - .fan_count = ARRAY_SIZE(mlxplat_mlxcpld_hotplug_fan), 201 - .fan = mlxplat_mlxcpld_hotplug_fan, 169 + struct mlxcpld_hotplug_platform_data mlxplat_mlxcpld_default_data = { 170 + .top_aggr_offset = MLXPLAT_CPLD_LPC_REG_AGGR_ADRR, 171 + .top_aggr_mask = MLXPLAT_CPLD_AGGR_MASK_DEF, 172 + .top_aggr_psu_mask = MLXPLAT_CPLD_AGGR_PSU_MASK_DEF, 173 + .psu_reg_offset = MLXPLAT_CPLD_LPC_REG_PSU_ADRR, 174 + .psu_mask = MLXPLAT_CPLD_PSU_MASK, 175 + .psu_count = ARRAY_SIZE(mlxplat_mlxcpld_psu), 176 + .psu = mlxplat_mlxcpld_psu, 177 + .top_aggr_pwr_mask = MLXPLAT_CPLD_AGGR_PWR_MASK_DEF, 178 + .pwr_reg_offset = MLXPLAT_CPLD_LPC_REG_PWR_ADRR, 179 + .pwr_mask = MLXPLAT_CPLD_PWR_MASK, 180 + .pwr_count = ARRAY_SIZE(mlxplat_mlxcpld_pwr), 181 + .pwr = mlxplat_mlxcpld_pwr, 182 + .top_aggr_fan_mask = MLXPLAT_CPLD_AGGR_FAN_MASK_DEF, 183 + .fan_reg_offset = MLXPLAT_CPLD_LPC_REG_FAN_ADRR, 184 + .fan_mask = MLXPLAT_CPLD_FAN_MASK, 185 + .fan_count = ARRAY_SIZE(mlxplat_mlxcpld_fan), 186 + .fan = mlxplat_mlxcpld_fan, 202 187 }; 203 188 204 189 /* Platform hotplug MSN21xx system family data */ 205 190 static 206 - struct mlxcpld_hotplug_platform_data mlxplat_mlxcpld_hotplug_msn21xx_data = { 207 - .top_aggr_offset = (MLXPLAT_CPLD_LPC_REG_BASE_ADRR | 0x3a), 208 - .top_aggr_mask = 0x04, 209 - .top_aggr_pwr_mask = 0x04, 210 - .pwr_reg_offset = (MLXPLAT_CPLD_LPC_REG_BASE_ADRR | 0x64), 211 - .pwr_mask = 0x03, 212 - .pwr_count = ARRAY_SIZE(mlxplat_mlxcpld_hotplug_pwr), 191 + struct mlxcpld_hotplug_platform_data mlxplat_mlxcpld_msn21xx_data = { 192 + .top_aggr_offset = MLXPLAT_CPLD_LPC_REG_AGGR_ADRR, 193 + .top_aggr_mask = MLXPLAT_CPLD_AGGR_MASK_MSN21XX, 194 + .top_aggr_pwr_mask = MLXPLAT_CPLD_AGGR_MASK_MSN21XX, 195 + .pwr_reg_offset = MLXPLAT_CPLD_LPC_REG_PWR_ADRR, 196 + .pwr_mask = MLXPLAT_CPLD_PWR_MASK, 197 + .pwr_count = ARRAY_SIZE(mlxplat_mlxcpld_pwr), 213 198 }; 214 199 215 - static struct resource mlxplat_mlxcpld_hotplug_resources[] = { 200 + static struct resource mlxplat_mlxcpld_resources[] = { 216 201 [0] = DEFINE_RES_IRQ_NAMED(17, "mlxcpld-hotplug"), 217 202 }; 218 203 ··· 228 213 mlxplat_mux_data[i].n_values = 229 214 ARRAY_SIZE(mlxplat_default_channels[i]); 230 215 } 231 - mlxplat_hotplug = &mlxplat_mlxcpld_hotplug_default_data; 216 + mlxplat_hotplug = &mlxplat_mlxcpld_default_data; 232 217 233 218 return 1; 234 219 }; ··· 242 227 mlxplat_mux_data[i].n_values = 243 228 ARRAY_SIZE(mlxplat_msn21xx_channels); 244 229 } 245 - mlxplat_hotplug = &mlxplat_mlxcpld_hotplug_msn21xx_data; 230 + mlxplat_hotplug = &mlxplat_mlxcpld_msn21xx_data; 246 231 247 232 return 1; 248 233 }; ··· 329 314 } 330 315 331 316 priv->pdev_hotplug = platform_device_register_resndata( 332 - &mlxplat_dev->dev, "mlxcpld-hotplug", -1, 333 - mlxplat_mlxcpld_hotplug_resources, 334 - ARRAY_SIZE(mlxplat_mlxcpld_hotplug_resources), 317 + &mlxplat_dev->dev, "mlxcpld-hotplug", 318 + PLATFORM_DEVID_NONE, 319 + mlxplat_mlxcpld_resources, 320 + ARRAY_SIZE(mlxplat_mlxcpld_resources), 335 321 mlxplat_hotplug, sizeof(*mlxplat_hotplug)); 336 322 if (IS_ERR(priv->pdev_hotplug)) { 337 323 err = PTR_ERR(priv->pdev_hotplug);
+136
drivers/platform/x86/silead_dmi.c
··· 1 + /* 2 + * Silead touchscreen driver DMI based configuration code 3 + * 4 + * Copyright (c) 2017 Red Hat Inc. 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 + * Red Hat authors: 12 + * Hans de Goede <hdegoede@redhat.com> 13 + */ 14 + 15 + #include <linux/acpi.h> 16 + #include <linux/device.h> 17 + #include <linux/dmi.h> 18 + #include <linux/i2c.h> 19 + #include <linux/notifier.h> 20 + #include <linux/property.h> 21 + #include <linux/string.h> 22 + 23 + struct silead_ts_dmi_data { 24 + const char *acpi_name; 25 + struct property_entry *properties; 26 + }; 27 + 28 + static struct property_entry cube_iwork8_air_props[] = { 29 + PROPERTY_ENTRY_U32("touchscreen-size-x", 1660), 30 + PROPERTY_ENTRY_U32("touchscreen-size-y", 900), 31 + PROPERTY_ENTRY_BOOL("touchscreen-swapped-x-y"), 32 + PROPERTY_ENTRY_STRING("firmware-name", "gsl3670-cube-iwork8-air.fw"), 33 + PROPERTY_ENTRY_U32("silead,max-fingers", 10), 34 + { } 35 + }; 36 + 37 + static const struct silead_ts_dmi_data cube_iwork8_air_data = { 38 + .acpi_name = "MSSL1680:00", 39 + .properties = cube_iwork8_air_props, 40 + }; 41 + 42 + static struct property_entry jumper_ezpad_mini3_props[] = { 43 + PROPERTY_ENTRY_U32("touchscreen-size-x", 1700), 44 + PROPERTY_ENTRY_U32("touchscreen-size-y", 1150), 45 + PROPERTY_ENTRY_BOOL("touchscreen-swapped-x-y"), 46 + PROPERTY_ENTRY_STRING("firmware-name", "gsl3676-jumper-ezpad-mini3.fw"), 47 + PROPERTY_ENTRY_U32("silead,max-fingers", 10), 48 + { } 49 + }; 50 + 51 + static const struct silead_ts_dmi_data jumper_ezpad_mini3_data = { 52 + .acpi_name = "MSSL1680:00", 53 + .properties = jumper_ezpad_mini3_props, 54 + }; 55 + 56 + static const struct dmi_system_id silead_ts_dmi_table[] = { 57 + { 58 + /* CUBE iwork8 Air */ 59 + .driver_data = (void *)&cube_iwork8_air_data, 60 + .matches = { 61 + DMI_MATCH(DMI_SYS_VENDOR, "cube"), 62 + DMI_MATCH(DMI_PRODUCT_NAME, "i1-TF"), 63 + DMI_MATCH(DMI_BOARD_NAME, "Cherry Trail CR"), 64 + }, 65 + }, 66 + { 67 + /* Jumper EZpad mini3 */ 68 + .driver_data = (void *)&jumper_ezpad_mini3_data, 69 + .matches = { 70 + DMI_MATCH(DMI_SYS_VENDOR, "Insyde"), 71 + /* jumperx.T87.KFBNEEA02 with the version-nr dropped */ 72 + DMI_MATCH(DMI_BIOS_VERSION, "jumperx.T87.KFBNEEA"), 73 + }, 74 + }, 75 + { }, 76 + }; 77 + 78 + static void silead_ts_dmi_add_props(struct device *dev) 79 + { 80 + struct i2c_client *client = to_i2c_client(dev); 81 + const struct dmi_system_id *dmi_id; 82 + const struct silead_ts_dmi_data *ts_data; 83 + int error; 84 + 85 + dmi_id = dmi_first_match(silead_ts_dmi_table); 86 + if (!dmi_id) 87 + return; 88 + 89 + ts_data = dmi_id->driver_data; 90 + if (has_acpi_companion(dev) && 91 + !strncmp(ts_data->acpi_name, client->name, I2C_NAME_SIZE)) { 92 + error = device_add_properties(dev, ts_data->properties); 93 + if (error) 94 + dev_err(dev, "failed to add properties: %d\n", error); 95 + } 96 + } 97 + 98 + static int silead_ts_dmi_notifier_call(struct notifier_block *nb, 99 + unsigned long action, void *data) 100 + { 101 + struct device *dev = data; 102 + 103 + switch (action) { 104 + case BUS_NOTIFY_ADD_DEVICE: 105 + silead_ts_dmi_add_props(dev); 106 + break; 107 + 108 + default: 109 + break; 110 + } 111 + 112 + return 0; 113 + } 114 + 115 + static struct notifier_block silead_ts_dmi_notifier = { 116 + .notifier_call = silead_ts_dmi_notifier_call, 117 + }; 118 + 119 + static int __init silead_ts_dmi_init(void) 120 + { 121 + int error; 122 + 123 + error = bus_register_notifier(&i2c_bus_type, &silead_ts_dmi_notifier); 124 + if (error) 125 + pr_err("%s: failed to register i2c bus notifier: %d\n", 126 + __func__, error); 127 + 128 + return error; 129 + } 130 + 131 + /* 132 + * We are registering out notifier after i2c core is initialized and i2c bus 133 + * itself is ready (which happens at postcore initcall level), but before 134 + * ACPI starts enumerating devices (at subsys initcall level). 135 + */ 136 + arch_initcall(silead_ts_dmi_init);
+54 -70
drivers/platform/x86/thinkpad_acpi.c
··· 163 163 TP_HKEY_EV_HOTKEY_BASE = 0x1001, /* first hotkey (FN+F1) */ 164 164 TP_HKEY_EV_BRGHT_UP = 0x1010, /* Brightness up */ 165 165 TP_HKEY_EV_BRGHT_DOWN = 0x1011, /* Brightness down */ 166 + TP_HKEY_EV_KBD_LIGHT = 0x1012, /* Thinklight/kbd backlight */ 166 167 TP_HKEY_EV_VOL_UP = 0x1015, /* Volume up or unmute */ 167 168 TP_HKEY_EV_VOL_DOWN = 0x1016, /* Volume down or unmute */ 168 169 TP_HKEY_EV_VOL_MUTE = 0x1017, /* Mixer output mute */ ··· 373 372 TPACPI_LED_BLINK, 374 373 }; 375 374 376 - /* Special LED class that can defer work */ 375 + /* tpacpi LED class */ 377 376 struct tpacpi_led_classdev { 378 377 struct led_classdev led_classdev; 379 - struct work_struct work; 380 - enum led_status_t new_state; 381 378 int led; 382 379 }; 383 380 ··· 1958 1959 TP_ACPI_HKEY_HIBERNATE_MASK = 1 << TP_ACPI_HOTKEYSCAN_FNF12, 1959 1960 TP_ACPI_HKEY_BRGHTUP_MASK = 1 << TP_ACPI_HOTKEYSCAN_FNHOME, 1960 1961 TP_ACPI_HKEY_BRGHTDWN_MASK = 1 << TP_ACPI_HOTKEYSCAN_FNEND, 1961 - TP_ACPI_HKEY_THNKLGHT_MASK = 1 << TP_ACPI_HOTKEYSCAN_FNPAGEUP, 1962 + TP_ACPI_HKEY_KBD_LIGHT_MASK = 1 << TP_ACPI_HOTKEYSCAN_FNPAGEUP, 1962 1963 TP_ACPI_HKEY_ZOOM_MASK = 1 << TP_ACPI_HOTKEYSCAN_FNSPACE, 1963 1964 TP_ACPI_HKEY_VOLUP_MASK = 1 << TP_ACPI_HOTKEYSCAN_VOLUMEUP, 1964 1965 TP_ACPI_HKEY_VOLDWN_MASK = 1 << TP_ACPI_HOTKEYSCAN_VOLUMEDOWN, ··· 2343 2344 n->display_toggle = !!(d & TP_NVRAM_MASK_HKT_DISPLAY); 2344 2345 n->hibernate_toggle = !!(d & TP_NVRAM_MASK_HKT_HIBERNATE); 2345 2346 } 2346 - if (m & TP_ACPI_HKEY_THNKLGHT_MASK) { 2347 + if (m & TP_ACPI_HKEY_KBD_LIGHT_MASK) { 2347 2348 d = nvram_read_byte(TP_NVRAM_ADDR_THINKLIGHT); 2348 2349 n->thinklight_toggle = !!(d & TP_NVRAM_MASK_THINKLIGHT); 2349 2350 } ··· 5083 5084 * Keyboard backlight subdriver 5084 5085 */ 5085 5086 5087 + static enum led_brightness kbdlight_brightness; 5088 + static DEFINE_MUTEX(kbdlight_mutex); 5089 + 5086 5090 static int kbdlight_set_level(int level) 5087 5091 { 5092 + int ret = 0; 5093 + 5088 5094 if (!hkey_handle) 5089 5095 return -ENXIO; 5090 5096 5097 + mutex_lock(&kbdlight_mutex); 5098 + 5091 5099 if (!acpi_evalf(hkey_handle, NULL, "MLCS", "dd", level)) 5092 - return -EIO; 5100 + ret = -EIO; 5101 + else 5102 + kbdlight_brightness = level; 5093 5103 5094 - return 0; 5104 + mutex_unlock(&kbdlight_mutex); 5105 + 5106 + return ret; 5095 5107 } 5096 - 5097 - static int kbdlight_set_level_and_update(int level); 5098 5108 5099 5109 static int kbdlight_get_level(void) 5100 5110 { ··· 5166 5158 return status & BIT(9); 5167 5159 } 5168 5160 5169 - static void kbdlight_set_worker(struct work_struct *work) 5170 - { 5171 - struct tpacpi_led_classdev *data = 5172 - container_of(work, struct tpacpi_led_classdev, work); 5173 - 5174 - if (likely(tpacpi_lifecycle == TPACPI_LIFE_RUNNING)) 5175 - kbdlight_set_level_and_update(data->new_state); 5176 - } 5177 - 5178 - static void kbdlight_sysfs_set(struct led_classdev *led_cdev, 5161 + static int kbdlight_sysfs_set(struct led_classdev *led_cdev, 5179 5162 enum led_brightness brightness) 5180 5163 { 5181 - struct tpacpi_led_classdev *data = 5182 - container_of(led_cdev, 5183 - struct tpacpi_led_classdev, 5184 - led_classdev); 5185 - data->new_state = brightness; 5186 - queue_work(tpacpi_wq, &data->work); 5164 + return kbdlight_set_level(brightness); 5187 5165 } 5188 5166 5189 5167 static enum led_brightness kbdlight_sysfs_get(struct led_classdev *led_cdev) ··· 5187 5193 .led_classdev = { 5188 5194 .name = "tpacpi::kbd_backlight", 5189 5195 .max_brightness = 2, 5190 - .brightness_set = &kbdlight_sysfs_set, 5196 + .flags = LED_BRIGHT_HW_CHANGED, 5197 + .brightness_set_blocking = &kbdlight_sysfs_set, 5191 5198 .brightness_get = &kbdlight_sysfs_get, 5192 5199 } 5193 5200 }; ··· 5200 5205 vdbg_printk(TPACPI_DBG_INIT, "initializing kbdlight subdriver\n"); 5201 5206 5202 5207 TPACPI_ACPIHANDLE_INIT(hkey); 5203 - INIT_WORK(&tpacpi_led_kbdlight.work, kbdlight_set_worker); 5204 5208 5205 5209 if (!kbdlight_is_supported()) { 5206 5210 tp_features.kbdlight = 0; ··· 5207 5213 return 1; 5208 5214 } 5209 5215 5216 + kbdlight_brightness = kbdlight_sysfs_get(NULL); 5210 5217 tp_features.kbdlight = 1; 5211 5218 5212 5219 rc = led_classdev_register(&tpacpi_pdev->dev, ··· 5217 5222 return rc; 5218 5223 } 5219 5224 5225 + tpacpi_hotkey_driver_mask_set(hotkey_driver_mask | 5226 + TP_ACPI_HKEY_KBD_LIGHT_MASK); 5220 5227 return 0; 5221 5228 } 5222 5229 ··· 5226 5229 { 5227 5230 if (tp_features.kbdlight) 5228 5231 led_classdev_unregister(&tpacpi_led_kbdlight.led_classdev); 5229 - flush_workqueue(tpacpi_wq); 5230 5232 } 5231 5233 5232 5234 static int kbdlight_set_level_and_update(int level) ··· 5354 5358 return -ENXIO; 5355 5359 } 5356 5360 5357 - static void light_set_status_worker(struct work_struct *work) 5358 - { 5359 - struct tpacpi_led_classdev *data = 5360 - container_of(work, struct tpacpi_led_classdev, work); 5361 - 5362 - if (likely(tpacpi_lifecycle == TPACPI_LIFE_RUNNING)) 5363 - light_set_status((data->new_state != TPACPI_LED_OFF)); 5364 - } 5365 - 5366 - static void light_sysfs_set(struct led_classdev *led_cdev, 5361 + static int light_sysfs_set(struct led_classdev *led_cdev, 5367 5362 enum led_brightness brightness) 5368 5363 { 5369 - struct tpacpi_led_classdev *data = 5370 - container_of(led_cdev, 5371 - struct tpacpi_led_classdev, 5372 - led_classdev); 5373 - data->new_state = (brightness != LED_OFF) ? 5374 - TPACPI_LED_ON : TPACPI_LED_OFF; 5375 - queue_work(tpacpi_wq, &data->work); 5364 + return light_set_status((brightness != LED_OFF) ? 5365 + TPACPI_LED_ON : TPACPI_LED_OFF); 5376 5366 } 5377 5367 5378 5368 static enum led_brightness light_sysfs_get(struct led_classdev *led_cdev) ··· 5369 5387 static struct tpacpi_led_classdev tpacpi_led_thinklight = { 5370 5388 .led_classdev = { 5371 5389 .name = "tpacpi::thinklight", 5372 - .brightness_set = &light_sysfs_set, 5390 + .brightness_set_blocking = &light_sysfs_set, 5373 5391 .brightness_get = &light_sysfs_get, 5374 5392 } 5375 5393 }; ··· 5385 5403 TPACPI_ACPIHANDLE_INIT(lght); 5386 5404 } 5387 5405 TPACPI_ACPIHANDLE_INIT(cmos); 5388 - INIT_WORK(&tpacpi_led_thinklight.work, light_set_status_worker); 5389 5406 5390 5407 /* light not supported on 570, 600e/x, 770e, 770x, G4x, R30, R31 */ 5391 5408 tp_features.light = (cmos_handle || lght_handle) && !ledb_handle; ··· 5418 5437 static void light_exit(void) 5419 5438 { 5420 5439 led_classdev_unregister(&tpacpi_led_thinklight.led_classdev); 5421 - flush_workqueue(tpacpi_wq); 5422 5440 } 5423 5441 5424 5442 static int light_read(struct seq_file *m) ··· 5684 5704 return rc; 5685 5705 } 5686 5706 5687 - static void led_set_status_worker(struct work_struct *work) 5688 - { 5689 - struct tpacpi_led_classdev *data = 5690 - container_of(work, struct tpacpi_led_classdev, work); 5691 - 5692 - if (likely(tpacpi_lifecycle == TPACPI_LIFE_RUNNING)) 5693 - led_set_status(data->led, data->new_state); 5694 - } 5695 - 5696 - static void led_sysfs_set(struct led_classdev *led_cdev, 5707 + static int led_sysfs_set(struct led_classdev *led_cdev, 5697 5708 enum led_brightness brightness) 5698 5709 { 5699 5710 struct tpacpi_led_classdev *data = container_of(led_cdev, 5700 5711 struct tpacpi_led_classdev, led_classdev); 5712 + enum led_status_t new_state; 5701 5713 5702 5714 if (brightness == LED_OFF) 5703 - data->new_state = TPACPI_LED_OFF; 5715 + new_state = TPACPI_LED_OFF; 5704 5716 else if (tpacpi_led_state_cache[data->led] != TPACPI_LED_BLINK) 5705 - data->new_state = TPACPI_LED_ON; 5717 + new_state = TPACPI_LED_ON; 5706 5718 else 5707 - data->new_state = TPACPI_LED_BLINK; 5719 + new_state = TPACPI_LED_BLINK; 5708 5720 5709 - queue_work(tpacpi_wq, &data->work); 5721 + return led_set_status(data->led, new_state); 5710 5722 } 5711 5723 5712 5724 static int led_sysfs_blink_set(struct led_classdev *led_cdev, ··· 5715 5743 } else if ((*delay_on != 500) || (*delay_off != 500)) 5716 5744 return -EINVAL; 5717 5745 5718 - data->new_state = TPACPI_LED_BLINK; 5719 - queue_work(tpacpi_wq, &data->work); 5720 - 5721 - return 0; 5746 + return led_set_status(data->led, TPACPI_LED_BLINK); 5722 5747 } 5723 5748 5724 5749 static enum led_brightness led_sysfs_get(struct led_classdev *led_cdev) ··· 5744 5775 led_classdev_unregister(&tpacpi_leds[i].led_classdev); 5745 5776 } 5746 5777 5747 - flush_workqueue(tpacpi_wq); 5748 5778 kfree(tpacpi_leds); 5749 5779 } 5750 5780 ··· 5757 5789 if (!tpacpi_led_names[led]) 5758 5790 return 0; 5759 5791 5760 - tpacpi_leds[led].led_classdev.brightness_set = &led_sysfs_set; 5792 + tpacpi_leds[led].led_classdev.brightness_set_blocking = &led_sysfs_set; 5761 5793 tpacpi_leds[led].led_classdev.blink_set = &led_sysfs_blink_set; 5762 5794 if (led_supported == TPACPI_LED_570) 5763 5795 tpacpi_leds[led].led_classdev.brightness_get = 5764 5796 &led_sysfs_get; 5765 5797 5766 5798 tpacpi_leds[led].led_classdev.name = tpacpi_led_names[led]; 5767 - 5768 - INIT_WORK(&tpacpi_leds[led].work, led_set_status_worker); 5769 5799 5770 5800 rc = led_classdev_register(&tpacpi_pdev->dev, 5771 5801 &tpacpi_leds[led].led_classdev); ··· 9134 9168 case TP_HKEY_EV_VOL_MUTE: 9135 9169 volume_alsa_notify_change(); 9136 9170 } 9171 + } 9172 + if (tp_features.kbdlight && hkey_event == TP_HKEY_EV_KBD_LIGHT) { 9173 + enum led_brightness brightness; 9174 + 9175 + mutex_lock(&kbdlight_mutex); 9176 + 9177 + /* 9178 + * Check the brightness actually changed, setting the brightness 9179 + * through kbdlight_set_level() also triggers this event. 9180 + */ 9181 + brightness = kbdlight_sysfs_get(NULL); 9182 + if (kbdlight_brightness != brightness) { 9183 + kbdlight_brightness = brightness; 9184 + led_classdev_notify_brightness_hw_changed( 9185 + &tpacpi_led_kbdlight.led_classdev, brightness); 9186 + } 9187 + 9188 + mutex_unlock(&kbdlight_mutex); 9137 9189 } 9138 9190 } 9139 9191