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

Configure Feed

Select the types of activity you want to include in your feed.

Merge tag 'platform-drivers-x86-v6.10-1' of git://git.kernel.org/pub/scm/linux/kernel/git/pdx86/platform-drivers-x86

Pull x86 platform driver updates from Hans de Goede:

- New drivers/platform/arm64 directory for arm64 embedded-controller
drivers

- New drivers:
- Acer Aspire 1 embedded controllers (for arm64 models)
- ACPI quickstart PNP0C32 buttons
- Dell All-In-One backlight support (dell-uart-backlight)
- Lenovo WMI camera buttons
- Lenovo Yoga Tablet 2 Pro 1380F/L fast charging
- MeeGoPad ANX7428 Type-C Cross Switch (power sequencing only)
- MSI WMI sensors (fan speed sensors only for now)

- Asus WMI:
- 2024 ROG Mini-LED support
- MCU powersave support
- Vivobook GPU MUX support
- Misc. other improvements

- Ideapad laptop:
- Export FnLock LED as LED class device
- Switch platform profiles using thermal management key

- Intel drivers:
- IFS: various improvements
- PMC: Lunar Lake support
- SDSI: various improvements
- TPMI/ISST: various improvements
- tools: intel-speed-select: various improvements

- MS Surface drivers:
- Fan profile switching support
- Surface Pro thermal sensors support

- ThinkPad ACPI:
- Reworked hotkey support to use sparse keymaps
- Add support for new trackpoint-doubletap, Fn+N and Fn+G hotkeys

- WMI core:
- New WMI driver development guide

- x86 Android tablets:
- Lenovo Yoga Tablet 2 Pro 1380F/L support
- Xiaomi MiPad 2 status LED and bezel touch buttons backlight
support

- Miscellaneous cleanups / fixes / improvements

* tag 'platform-drivers-x86-v6.10-1' of git://git.kernel.org/pub/scm/linux/kernel/git/pdx86/platform-drivers-x86: (128 commits)
platform/x86: Add new MeeGoPad ANX7428 Type-C Cross Switch driver
devm-helpers: Fix a misspelled cancellation in the comments
tools arch x86: Add dell-uart-backlight-emulator
platform/x86: Add new Dell UART backlight driver
platform/x86: x86-android-tablets: Create LED device for Xiaomi Pad 2 bottom bezel touch buttons
platform/x86: x86-android-tablets: Xiaomi pad2 RGB LED fwnode updates
platform/x86: x86-android-tablets: Pass struct device to init()
platform/x86/amd: pmc: Add new ACPI ID AMDI000B
platform/x86/amd: pmf: Add new ACPI ID AMDI0105
platform/x86: p2sb: Don't init until unassigned resources have been assigned
platform/surface: aggregator: Log critical errors during SAM probing
platform/x86: ISST: Support SST-BF and SST-TF per level
platform/x86/fujitsu-laptop: Replace sprintf() with sysfs_emit()
tools/power/x86/intel-speed-select: v1.19 release
tools/power/x86/intel-speed-select: Display CPU as None for -1
tools/power/x86/intel-speed-select: SST BF/TF support per level
tools/power/x86/intel-speed-select: Increase number of CPUs displayed
tools/power/x86/intel-speed-select: Present all TRL levels for turbo-freq
tools/power/x86/intel-speed-select: Fix display for unsupported levels
tools/power/x86/intel-speed-select: Support multiple dies
...

+5942 -1201
+14
Documentation/ABI/testing/debugfs-msi-wmi-platform
··· 1 + What: /sys/kernel/debug/msi-wmi-platform-<wmi_device_name>/* 2 + Date: April 2024 3 + KernelVersion: 6.10 4 + Contact: Armin Wolf <W_Armin@gmx.de> 5 + Description: 6 + This file allows to execute the associated WMI method with the same name. 7 + 8 + To start the execution, write a buffer containing the method arguments 9 + at file offset 0. Partial writes or writes at a different offset are not 10 + supported. 11 + 12 + The buffer returned by the WMI method can then be read from the file. 13 + 14 + See Documentation/wmi/devices/msi-wmi-platform.rst for details.
+26
Documentation/ABI/testing/sysfs-platform-asus-wmi
··· 126 126 Change the mini-LED mode: 127 127 * 0 - Single-zone, 128 128 * 1 - Multi-zone 129 + * 2 - Multi-zone strong (available on newer generation mini-led) 130 + 131 + What: /sys/devices/platform/<platform>/available_mini_led_mode 132 + Date: Apr 2024 133 + KernelVersion: 6.10 134 + Contact: "Luke Jones" <luke@ljones.dev> 135 + Description: 136 + List the available mini-led modes. 129 137 130 138 What: /sys/devices/platform/<platform>/ppt_pl1_spl 131 139 Date: Jun 2023 ··· 194 186 Description: 195 187 Set the target temperature limit of the Nvidia dGPU: 196 188 * min=75, max=87 189 + 190 + What: /sys/devices/platform/<platform>/boot_sound 191 + Date: Apr 2024 192 + KernelVersion: 6.10 193 + Contact: "Luke Jones" <luke@ljones.dev> 194 + Description: 195 + Set if the BIOS POST sound is played on boot. 196 + * 0 - False, 197 + * 1 - True 198 + 199 + What: /sys/devices/platform/<platform>/mcu_powersave 200 + Date: Apr 2024 201 + KernelVersion: 6.10 202 + Contact: "Luke Jones" <luke@ljones.dev> 203 + Description: 204 + Set if the MCU can go in to low-power mode on system sleep 205 + * 0 - False, 206 + * 1 - True
+60
Documentation/devicetree/bindings/platform/acer,aspire1-ec.yaml
··· 1 + # SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) 2 + %YAML 1.2 3 + --- 4 + $id: http://devicetree.org/schemas/platform/acer,aspire1-ec.yaml# 5 + $schema: http://devicetree.org/meta-schemas/core.yaml# 6 + 7 + title: Acer Aspire 1 Embedded Controller 8 + 9 + maintainers: 10 + - Nikita Travkin <nikita@trvn.ru> 11 + 12 + description: 13 + The Acer Aspire 1 laptop uses an embedded controller to control battery 14 + and charging as well as to provide a set of misc features such as the 15 + laptop lid status and HPD events for the USB Type-C DP alt mode. 16 + 17 + properties: 18 + compatible: 19 + const: acer,aspire1-ec 20 + 21 + reg: 22 + const: 0x76 23 + 24 + interrupts: 25 + maxItems: 1 26 + 27 + connector: 28 + $ref: /schemas/connector/usb-connector.yaml# 29 + 30 + required: 31 + - compatible 32 + - reg 33 + - interrupts 34 + 35 + additionalProperties: false 36 + 37 + examples: 38 + - | 39 + #include <dt-bindings/interrupt-controller/irq.h> 40 + i2c { 41 + #address-cells = <1>; 42 + #size-cells = <0>; 43 + 44 + embedded-controller@76 { 45 + compatible = "acer,aspire1-ec"; 46 + reg = <0x76>; 47 + 48 + interrupts-extended = <&tlmm 30 IRQ_TYPE_LEVEL_LOW>; 49 + 50 + connector { 51 + compatible = "usb-c-connector"; 52 + 53 + port { 54 + ec_dp_in: endpoint { 55 + remote-endpoint = <&mdss_dp_out>; 56 + }; 57 + }; 58 + }; 59 + }; 60 + };
+194
Documentation/wmi/devices/msi-wmi-platform.rst
··· 1 + .. SPDX-License-Identifier: GPL-2.0-or-later 2 + 3 + =================================================== 4 + MSI WMI Platform Features driver (msi-wmi-platform) 5 + =================================================== 6 + 7 + Introduction 8 + ============ 9 + 10 + Many MSI notebooks support various features like reading fan sensors. This features are controlled 11 + by the embedded controller, with the ACPI firmware exposing a standard ACPI WMI interface on top 12 + of the embedded controller interface. 13 + 14 + WMI interface description 15 + ========================= 16 + 17 + The WMI interface description can be decoded from the embedded binary MOF (bmof) 18 + data using the `bmfdec <https://github.com/pali/bmfdec>`_ utility: 19 + 20 + :: 21 + 22 + [WMI, Locale("MS\0x409"), 23 + Description("This class contains the definition of the package used in other classes"), 24 + guid("{ABBC0F60-8EA1-11d1-00A0-C90629100000}")] 25 + class Package { 26 + [WmiDataId(1), read, write, Description("16 bytes of data")] uint8 Bytes[16]; 27 + }; 28 + 29 + [WMI, Locale("MS\0x409"), 30 + Description("This class contains the definition of the package used in other classes"), 31 + guid("{ABBC0F63-8EA1-11d1-00A0-C90629100000}")] 32 + class Package_32 { 33 + [WmiDataId(1), read, write, Description("32 bytes of data")] uint8 Bytes[32]; 34 + }; 35 + 36 + [WMI, Dynamic, Provider("WmiProv"), Locale("MS\0x409"), 37 + Description("Class used to operate methods on a package"), 38 + guid("{ABBC0F6E-8EA1-11d1-00A0-C90629100000}")] 39 + class MSI_ACPI { 40 + [key, read] string InstanceName; 41 + [read] boolean Active; 42 + 43 + [WmiMethodId(1), Implemented, read, write, Description("Return the contents of a package")] 44 + void GetPackage([out, id(0)] Package Data); 45 + 46 + [WmiMethodId(2), Implemented, read, write, Description("Set the contents of a package")] 47 + void SetPackage([in, id(0)] Package Data); 48 + 49 + [WmiMethodId(3), Implemented, read, write, Description("Return the contents of a package")] 50 + void Get_EC([out, id(0)] Package_32 Data); 51 + 52 + [WmiMethodId(4), Implemented, read, write, Description("Set the contents of a package")] 53 + void Set_EC([in, id(0)] Package_32 Data); 54 + 55 + [WmiMethodId(5), Implemented, read, write, Description("Return the contents of a package")] 56 + void Get_BIOS([in, out, id(0)] Package_32 Data); 57 + 58 + [WmiMethodId(6), Implemented, read, write, Description("Set the contents of a package")] 59 + void Set_BIOS([in, out, id(0)] Package_32 Data); 60 + 61 + [WmiMethodId(7), Implemented, read, write, Description("Return the contents of a package")] 62 + void Get_SMBUS([in, out, id(0)] Package_32 Data); 63 + 64 + [WmiMethodId(8), Implemented, read, write, Description("Set the contents of a package")] 65 + void Set_SMBUS([in, out, id(0)] Package_32 Data); 66 + 67 + [WmiMethodId(9), Implemented, read, write, Description("Return the contents of a package")] 68 + void Get_MasterBattery([in, out, id(0)] Package_32 Data); 69 + 70 + [WmiMethodId(10), Implemented, read, write, Description("Set the contents of a package")] 71 + void Set_MasterBattery([in, out, id(0)] Package_32 Data); 72 + 73 + [WmiMethodId(11), Implemented, read, write, Description("Return the contents of a package")] 74 + void Get_SlaveBattery([in, out, id(0)] Package_32 Data); 75 + 76 + [WmiMethodId(12), Implemented, read, write, Description("Set the contents of a package")] 77 + void Set_SlaveBattery([in, out, id(0)] Package_32 Data); 78 + 79 + [WmiMethodId(13), Implemented, read, write, Description("Return the contents of a package")] 80 + void Get_Temperature([in, out, id(0)] Package_32 Data); 81 + 82 + [WmiMethodId(14), Implemented, read, write, Description("Set the contents of a package")] 83 + void Set_Temperature([in, out, id(0)] Package_32 Data); 84 + 85 + [WmiMethodId(15), Implemented, read, write, Description("Return the contents of a package")] 86 + void Get_Thermal([in, out, id(0)] Package_32 Data); 87 + 88 + [WmiMethodId(16), Implemented, read, write, Description("Set the contents of a package")] 89 + void Set_Thermal([in, out, id(0)] Package_32 Data); 90 + 91 + [WmiMethodId(17), Implemented, read, write, Description("Return the contents of a package")] 92 + void Get_Fan([in, out, id(0)] Package_32 Data); 93 + 94 + [WmiMethodId(18), Implemented, read, write, Description("Set the contents of a package")] 95 + void Set_Fan([in, out, id(0)] Package_32 Data); 96 + 97 + [WmiMethodId(19), Implemented, read, write, Description("Return the contents of a package")] 98 + void Get_Device([in, out, id(0)] Package_32 Data); 99 + 100 + [WmiMethodId(20), Implemented, read, write, Description("Set the contents of a package")] 101 + void Set_Device([in, out, id(0)] Package_32 Data); 102 + 103 + [WmiMethodId(21), Implemented, read, write, Description("Return the contents of a package")] 104 + void Get_Power([in, out, id(0)] Package_32 Data); 105 + 106 + [WmiMethodId(22), Implemented, read, write, Description("Set the contents of a package")] 107 + void Set_Power([in, out, id(0)] Package_32 Data); 108 + 109 + [WmiMethodId(23), Implemented, read, write, Description("Return the contents of a package")] 110 + void Get_Debug([in, out, id(0)] Package_32 Data); 111 + 112 + [WmiMethodId(24), Implemented, read, write, Description("Set the contents of a package")] 113 + void Set_Debug([in, out, id(0)] Package_32 Data); 114 + 115 + [WmiMethodId(25), Implemented, read, write, Description("Return the contents of a package")] 116 + void Get_AP([in, out, id(0)] Package_32 Data); 117 + 118 + [WmiMethodId(26), Implemented, read, write, Description("Set the contents of a package")] 119 + void Set_AP([in, out, id(0)] Package_32 Data); 120 + 121 + [WmiMethodId(27), Implemented, read, write, Description("Return the contents of a package")] 122 + void Get_Data([in, out, id(0)] Package_32 Data); 123 + 124 + [WmiMethodId(28), Implemented, read, write, Description("Set the contents of a package")] 125 + void Set_Data([in, out, id(0)] Package_32 Data); 126 + 127 + [WmiMethodId(29), Implemented, read, write, Description("Return the contents of a package")] 128 + void Get_WMI([out, id(0)] Package_32 Data); 129 + }; 130 + 131 + Due to a peculiarity in how Windows handles the ``CreateByteField()`` ACPI operator (errors only 132 + happen when a invalid byte field is ultimately accessed), all methods require a 32 byte input 133 + buffer, even if the Binay MOF says otherwise. 134 + 135 + The input buffer contains a single byte to select the subfeature to be accessed and 31 bytes of 136 + input data, the meaning of which depends on the subfeature being accessed. 137 + 138 + The output buffer contains a singe byte which signals success or failure (``0x00`` on failure) 139 + and 31 bytes of output data, the meaning if which depends on the subfeature being accessed. 140 + 141 + WMI method Get_EC() 142 + ------------------- 143 + 144 + Returns embedded controller information, the selected subfeature does not matter. The output 145 + data contains a flag byte and a 28 byte controller firmware version string. 146 + 147 + The first 4 bits of the flag byte contain the minor version of the embedded controller interface, 148 + with the next 2 bits containing the major version of the embedded controller interface. 149 + 150 + The 7th bit signals if the embedded controller page chaged (exact meaning is unknown), and the 151 + last bit signals if the platform is a Tigerlake platform. 152 + 153 + The MSI software seems to only use this interface when the last bit is set. 154 + 155 + WMI method Get_Fan() 156 + -------------------- 157 + 158 + Fan speed sensors can be accessed by selecting subfeature ``0x00``. The output data contains 159 + up to four 16-bit fan speed readings in big-endian format. Most machines do not support all 160 + four fan speed sensors, so the remaining reading are hardcoded to ``0x0000``. 161 + 162 + The fan RPM readings can be calculated with the following formula: 163 + 164 + RPM = 480000 / <fan speed reading> 165 + 166 + If the fan speed reading is zero, then the fan RPM is zero too. 167 + 168 + WMI method Get_WMI() 169 + -------------------- 170 + 171 + Returns the version of the ACPI WMI interface, the selected subfeature does not matter. 172 + The output data contains two bytes, the first one contains the major version and the last one 173 + contains the minor revision of the ACPI WMI interface. 174 + 175 + The MSI software seems to only use this interface when the major version is greater than two. 176 + 177 + Reverse-Engineering the MSI WMI Platform interface 178 + ================================================== 179 + 180 + .. warning:: Randomly poking the embedded controller interface can potentially cause damage 181 + to the machine and other unwanted side effects, please be careful. 182 + 183 + The underlying embedded controller interface is used by the ``msi-ec`` driver, and it seems 184 + that many methods just copy a part of the embedded controller memory into the output buffer. 185 + 186 + This means that the remaining WMI methods can be reverse-engineered by looking which part of 187 + the embedded controller memory is accessed by the ACPI AML code. The driver also supports a 188 + debugfs interface for directly executing WMI methods. Additionally, any safety checks regarding 189 + unsupported hardware can be disabled by loading the module with ``force=true``. 190 + 191 + More information about the MSI embedded controller interface can be found at the 192 + `msi-ec project <https://github.com/BeardOverflow/msi-ec>`_. 193 + 194 + Special thanks go to github user `glpnk` for showing how to decode the fan speed readings.
+178
Documentation/wmi/driver-development-guide.rst
··· 1 + .. SPDX-License-Identifier: GPL-2.0-or-later 2 + 3 + ============================ 4 + WMI driver development guide 5 + ============================ 6 + 7 + The WMI subsystem provides a rich driver API for implementing WMI drivers, 8 + documented at Documentation/driver-api/wmi.rst. This document will serve 9 + as an introductory guide for WMI driver writers using this API. It is supposed 10 + to be a successor to the original LWN article [1]_ which deals with WMI drivers 11 + using the deprecated GUID-based WMI interface. 12 + 13 + Obtaining WMI device information 14 + -------------------------------- 15 + 16 + Before developing an WMI driver, information about the WMI device in question 17 + must be obtained. The `lswmi <https://pypi.org/project/lswmi>`_ utility can be 18 + used to extract detailed WMI device information using the following command: 19 + 20 + :: 21 + 22 + lswmi -V 23 + 24 + The resulting output will contain information about all WMI devices available on 25 + a given machine, plus some extra information. 26 + 27 + In order to find out more about the interface used to communicate with a WMI device, 28 + the `bmfdec <https://github.com/pali/bmfdec>`_ utilities can be used to decode 29 + the Binary MOF (Managed Object Format) information used to describe WMI devices. 30 + The ``wmi-bmof`` driver exposes this information to userspace, see 31 + Documentation/wmi/devices/wmi-bmof.rst. 32 + 33 + In order to retrieve the decoded Binary MOF information, use the following command (requires root): 34 + 35 + :: 36 + 37 + ./bmf2mof /sys/bus/wmi/devices/05901221-D566-11D1-B2F0-00A0C9062910[-X]/bmof 38 + 39 + Sometimes, looking at the disassembled ACPI tables used to describe the WMI device 40 + helps in understanding how the WMI device is supposed to work. The path of the ACPI 41 + method associated with a given WMI device can be retrieved using the ``lswmi`` utility 42 + as mentioned above. 43 + 44 + Basic WMI driver structure 45 + -------------------------- 46 + 47 + The basic WMI driver is build around the struct wmi_driver, which is then bound 48 + to matching WMI devices using a struct wmi_device_id table: 49 + 50 + :: 51 + 52 + static const struct wmi_device_id foo_id_table[] = { 53 + { "936DA01F-9ABD-4D9D-80C7-02AF85C822A8", NULL }, 54 + { } 55 + }; 56 + MODULE_DEVICE_TABLE(wmi, foo_id_table); 57 + 58 + static struct wmi_driver foo_driver = { 59 + .driver = { 60 + .name = "foo", 61 + .probe_type = PROBE_PREFER_ASYNCHRONOUS, /* recommended */ 62 + .pm = pm_sleep_ptr(&foo_dev_pm_ops), /* optional */ 63 + }, 64 + .id_table = foo_id_table, 65 + .probe = foo_probe, 66 + .remove = foo_remove, /* optional, devres is preferred */ 67 + .notify = foo_notify, /* optional, for event handling */ 68 + .no_notify_data = true, /* optional, enables events containing no additional data */ 69 + .no_singleton = true, /* required for new WMI drivers */ 70 + }; 71 + module_wmi_driver(foo_driver); 72 + 73 + The probe() callback is called when the WMI driver is bound to a matching WMI device. Allocating 74 + driver-specific data structures and initialising interfaces to other kernel subsystems should 75 + normally be done in this function. 76 + 77 + The remove() callback is then called when the WMI driver is unbound from a WMI device. In order 78 + to unregister interfaces to other kernel subsystems and release resources, devres should be used. 79 + This simplifies error handling during probe and often allows to omit this callback entirely, see 80 + Documentation/driver-api/driver-model/devres.rst for details. 81 + 82 + Please note that new WMI drivers are required to be able to be instantiated multiple times, 83 + and are forbidden from using any deprecated GUID-based WMI functions. This means that the 84 + WMI driver should be prepared for the scenario that multiple matching WMI devices are present 85 + on a given machine. 86 + 87 + Because of this, WMI drivers should use the state container design pattern as described in 88 + Documentation/driver-api/driver-model/design-patterns.rst. 89 + 90 + WMI method drivers 91 + ------------------ 92 + 93 + WMI drivers can call WMI device methods using wmidev_evaluate_method(), the 94 + structure of the ACPI buffer passed to this function is device-specific and usually 95 + needs some tinkering to get right. Looking at the ACPI tables containing the WMI 96 + device usually helps here. The method id and instance number passed to this function 97 + are also device-specific, looking at the decoded Binary MOF is usually enough to 98 + find the right values. 99 + 100 + The maximum instance number can be retrieved during runtime using wmidev_instance_count(). 101 + 102 + Take a look at drivers/platform/x86/inspur_platform_profile.c for an example WMI method driver. 103 + 104 + WMI data block drivers 105 + ---------------------- 106 + 107 + WMI drivers can query WMI device data blocks using wmidev_block_query(), the 108 + structure of the returned ACPI object is again device-specific. Some WMI devices 109 + also allow for setting data blocks using wmidev_block_set(). 110 + 111 + The maximum instance number can also be retrieved using wmidev_instance_count(). 112 + 113 + Take a look at drivers/platform/x86/intel/wmi/sbl-fw-update.c for an example 114 + WMI data block driver. 115 + 116 + WMI event drivers 117 + ----------------- 118 + 119 + WMI drivers can receive WMI events via the notify() callback inside the struct wmi_driver. 120 + The WMI subsystem will then take care of setting up the WMI event accordingly. Please note that 121 + the structure of the ACPI object passed to this callback is device-specific, and freeing the 122 + ACPI object is being done by the WMI subsystem, not the driver. 123 + 124 + The WMI driver core will take care that the notify() callback will only be called after 125 + the probe() callback has been called, and that no events are being received by the driver 126 + right before and after calling its remove() callback. 127 + 128 + However WMI driver developers should be aware that multiple WMI events can be received concurrently, 129 + so any locking (if necessary) needs to be provided by the WMI driver itself. 130 + 131 + In order to be able to receive WMI events containing no additional event data, 132 + the ``no_notify_data`` flag inside struct wmi_driver should be set to ``true``. 133 + 134 + Take a look at drivers/platform/x86/xiaomi-wmi.c for an example WMI event driver. 135 + 136 + Handling multiple WMI devices at once 137 + ------------------------------------- 138 + 139 + There are many cases of firmware vendors using multiple WMI devices to control different aspects 140 + of a single physical device. This can make developing WMI drivers complicated, as those drivers 141 + might need to communicate with each other to present a unified interface to userspace. 142 + 143 + On such case involves a WMI event device which needs to talk to a WMI data block device or WMI 144 + method device upon receiving an WMI event. In such a case, two WMI drivers should be developed, 145 + one for the WMI event device and one for the other WMI device. 146 + 147 + The WMI event device driver has only one purpose: to receive WMI events, validate any additional 148 + event data and invoke a notifier chain. The other WMI driver adds itself to this notifier chain 149 + during probing and thus gets notified every time a WMI event is received. This WMI driver might 150 + then process the event further for example by using an input device. 151 + 152 + For other WMI device constellations, similar mechanisms can be used. 153 + 154 + Things to avoid 155 + --------------- 156 + 157 + When developing WMI drivers, there are a couple of things which should be avoided: 158 + 159 + - usage of the deprecated GUID-based WMI interface which uses GUIDs instead of WMI device structs 160 + - bypassing of the WMI subsystem when talking to WMI devices 161 + - WMI drivers which cannot be instantiated multiple times. 162 + 163 + Many older WMI drivers violate one or more points from this list. The reason for 164 + this is that the WMI subsystem evolved significantly over the last two decades, 165 + so there is a lot of legacy cruft inside older WMI drivers. 166 + 167 + New WMI drivers are also required to conform to the linux kernel coding style as specified in 168 + Documentation/process/coding-style.rst. The checkpatch utility can catch many common coding style 169 + violations, you can invoke it with the following command: 170 + 171 + :: 172 + 173 + ./scripts/checkpatch.pl --strict <path to driver file> 174 + 175 + References 176 + ========== 177 + 178 + .. [1] https://lwn.net/Articles/391230/
+1
Documentation/wmi/index.rst
··· 8 8 :maxdepth: 1 9 9 10 10 acpi-interface 11 + driver-development-guide 11 12 devices/index 12 13 13 14 .. only:: subproject and html
+30 -1
MAINTAINERS
··· 258 258 S: Maintained 259 259 F: drivers/net/ethernet/alteon/acenic* 260 260 261 + ACER ASPIRE 1 EMBEDDED CONTROLLER DRIVER 262 + M: Nikita Travkin <nikita@trvn.ru> 263 + S: Maintained 264 + F: Documentation/devicetree/bindings/platform/acer,aspire1-ec.yaml 265 + F: drivers/platform/arm64/acer-aspire1-ec.c 266 + 261 267 ACER ASPIRE ONE TEMPERATURE AND FAN DRIVER 262 268 M: Peter Kaestle <peter@piie.net> 263 269 L: platform-driver-x86@vger.kernel.org ··· 359 353 B: https://bugzilla.kernel.org 360 354 T: git git://git.kernel.org/pub/scm/linux/kernel/git/rafael/linux-pm 361 355 F: drivers/acpi/pmic/ 356 + 357 + ACPI QUICKSTART DRIVER 358 + M: Armin Wolf <W_Armin@gmx.de> 359 + L: platform-driver-x86@vger.kernel.org 360 + S: Maintained 361 + F: drivers/platform/x86/quickstart.c 362 362 363 363 ACPI SERIAL MULTI INSTANTIATE DRIVER 364 364 M: Hans de Goede <hdegoede@redhat.com> ··· 3122 3110 F: arch/arm64/boot/Makefile 3123 3111 F: scripts/make_fit.py 3124 3112 3113 + ARM64 PLATFORM DRIVERS 3114 + M: Hans de Goede <hdegoede@redhat.com> 3115 + M: Ilpo Järvinen <ilpo.jarvinen@linux.intel.com> 3116 + R: Bryan O'Donoghue <bryan.odonoghue@linaro.org> 3117 + L: platform-driver-x86@vger.kernel.org 3118 + S: Maintained 3119 + Q: https://patchwork.kernel.org/project/platform-driver-x86/list/ 3120 + T: git git://git.kernel.org/pub/scm/linux/kernel/git/pdx86/platform-drivers-x86.git 3121 + F: drivers/platform/arm64/ 3122 + 3125 3123 ARM64 PORT (AARCH64 ARCHITECTURE) 3126 3124 M: Catalin Marinas <catalin.marinas@arm.com> 3127 3125 M: Will Deacon <will@kernel.org> ··· 5313 5291 5314 5292 CMPC ACPI DRIVER 5315 5293 M: Thadeu Lima de Souza Cascardo <cascardo@holoscopio.com> 5316 - M: Daniel Oliveira Nascimento <don@syst.com.br> 5317 5294 L: platform-driver-x86@vger.kernel.org 5318 5295 S: Supported 5319 5296 F: drivers/platform/x86/classmate-laptop.c ··· 15211 15190 L: platform-driver-x86@vger.kernel.org 15212 15191 S: Orphan 15213 15192 F: drivers/platform/x86/msi-wmi.c 15193 + 15194 + MSI WMI PLATFORM FEATURES 15195 + M: Armin Wolf <W_Armin@gmx.de> 15196 + L: platform-driver-x86@vger.kernel.org 15197 + S: Maintained 15198 + F: Documentation/ABI/testing/debugfs-msi-wmi-platform 15199 + F: Documentation/wmi/devices/msi-wmi-platform.rst 15200 + F: drivers/platform/x86/msi-wmi-platform.c 15214 15201 15215 15202 MSI001 MEDIA DRIVER 15216 15203 L: linux-media@vger.kernel.org
+39 -1
arch/arm64/boot/dts/qcom/sc7180-acer-aspire1.dts
··· 255 255 clock-frequency = <400000>; 256 256 status = "okay"; 257 257 258 - /* embedded-controller@76 */ 258 + embedded-controller@76 { 259 + compatible = "acer,aspire1-ec"; 260 + reg = <0x76>; 261 + 262 + interrupts-extended = <&tlmm 30 IRQ_TYPE_LEVEL_LOW>; 263 + 264 + pinctrl-0 = <&ec_int_default>; 265 + pinctrl-names = "default"; 266 + 267 + connector { 268 + compatible = "usb-c-connector"; 269 + 270 + port { 271 + ec_dp_in: endpoint { 272 + remote-endpoint = <&mdss_dp_out>; 273 + }; 274 + }; 275 + }; 276 + }; 259 277 }; 260 278 261 279 &i2c4 { ··· 435 417 436 418 &mdss { 437 419 status = "okay"; 420 + }; 421 + 422 + &mdss_dp { 423 + data-lanes = <0 1>; 424 + 425 + vdda-1p2-supply = <&vreg_l3c_1p2>; 426 + vdda-0p9-supply = <&vreg_l4a_0p8>; 427 + 428 + status = "okay"; 429 + }; 430 + 431 + &mdss_dp_out { 432 + remote-endpoint = <&ec_dp_in>; 438 433 }; 439 434 440 435 &mdss_dsi0 { ··· 883 852 884 853 codec_irq_default: codec-irq-deault-state { 885 854 pins = "gpio28"; 855 + function = "gpio"; 856 + drive-strength = <2>; 857 + bias-disable; 858 + }; 859 + 860 + ec_int_default: ec-int-default-state { 861 + pins = "gpio30"; 886 862 function = "gpio"; 887 863 drive-strength = <2>; 888 864 bias-disable;
+39
drivers/acpi/platform_profile.c
··· 136 136 } 137 137 EXPORT_SYMBOL_GPL(platform_profile_notify); 138 138 139 + int platform_profile_cycle(void) 140 + { 141 + enum platform_profile_option profile; 142 + enum platform_profile_option next; 143 + int err; 144 + 145 + err = mutex_lock_interruptible(&profile_lock); 146 + if (err) 147 + return err; 148 + 149 + if (!cur_profile) { 150 + mutex_unlock(&profile_lock); 151 + return -ENODEV; 152 + } 153 + 154 + err = cur_profile->profile_get(cur_profile, &profile); 155 + if (err) { 156 + mutex_unlock(&profile_lock); 157 + return err; 158 + } 159 + 160 + next = find_next_bit_wrap(cur_profile->choices, PLATFORM_PROFILE_LAST, 161 + profile + 1); 162 + 163 + if (WARN_ON(next == PLATFORM_PROFILE_LAST)) { 164 + mutex_unlock(&profile_lock); 165 + return -EINVAL; 166 + } 167 + 168 + err = cur_profile->profile_set(cur_profile, next); 169 + mutex_unlock(&profile_lock); 170 + 171 + if (!err) 172 + sysfs_notify(acpi_kobj, NULL, "platform_profile"); 173 + 174 + return err; 175 + } 176 + EXPORT_SYMBOL_GPL(platform_profile_cycle); 177 + 139 178 int platform_profile_register(struct platform_profile_handler *pprof) 140 179 { 141 180 int err;
+2
drivers/platform/Kconfig
··· 14 14 source "drivers/platform/surface/Kconfig" 15 15 16 16 source "drivers/platform/x86/Kconfig" 17 + 18 + source "drivers/platform/arm64/Kconfig"
+1
drivers/platform/Makefile
··· 11 11 obj-$(CONFIG_GOLDFISH) += goldfish/ 12 12 obj-$(CONFIG_CHROME_PLATFORMS) += chrome/ 13 13 obj-$(CONFIG_SURFACE_PLATFORMS) += surface/ 14 + obj-$(CONFIG_ARM64) += arm64/
+35
drivers/platform/arm64/Kconfig
··· 1 + # SPDX-License-Identifier: GPL-2.0-only 2 + # 3 + # EC-like Drivers for aarch64 based devices. 4 + # 5 + 6 + menuconfig ARM64_PLATFORM_DEVICES 7 + bool "ARM64 Platform-Specific Device Drivers" 8 + depends on ARM64 || COMPILE_TEST 9 + default y 10 + help 11 + Say Y here to get to see options for platform-specific device drivers 12 + for arm64 based devices, primarily EC-like device drivers. 13 + This option alone does not add any kernel code. 14 + 15 + If you say N, all options in this submenu will be skipped and disabled. 16 + 17 + if ARM64_PLATFORM_DEVICES 18 + 19 + config EC_ACER_ASPIRE1 20 + tristate "Acer Aspire 1 Embedded Controller driver" 21 + depends on I2C 22 + depends on DRM 23 + depends on POWER_SUPPLY 24 + depends on INPUT 25 + help 26 + Say Y here to enable the EC driver for the (Snapdragon-based) 27 + Acer Aspire 1 laptop. The EC handles battery and charging 28 + monitoring as well as some misc functions like the lid sensor 29 + and USB Type-C DP HPD events. 30 + 31 + This driver provides battery and AC status support for the mentioned 32 + laptop where this information is not properly exposed via the 33 + standard ACPI devices. 34 + 35 + endif # ARM64_PLATFORM_DEVICES
+8
drivers/platform/arm64/Makefile
··· 1 + # SPDX-License-Identifier: GPL-2.0-only 2 + # 3 + # Makefile for linux/drivers/platform/arm64 4 + # 5 + # This dir should only include drivers for EC-like devices. 6 + # 7 + 8 + obj-$(CONFIG_EC_ACER_ASPIRE1) += acer-aspire1-ec.o
+562
drivers/platform/arm64/acer-aspire1-ec.c
··· 1 + // SPDX-License-Identifier: GPL-2.0-only 2 + /* Copyright (c) 2024, Nikita Travkin <nikita@trvn.ru> */ 3 + 4 + #include <asm-generic/unaligned.h> 5 + #include <drm/drm_bridge.h> 6 + #include <linux/bits.h> 7 + #include <linux/delay.h> 8 + #include <linux/i2c.h> 9 + #include <linux/input.h> 10 + #include <linux/module.h> 11 + #include <linux/platform_device.h> 12 + #include <linux/power_supply.h> 13 + #include <linux/usb/typec_mux.h> 14 + #include <linux/workqueue_types.h> 15 + 16 + #define MILLI_TO_MICRO 1000 17 + 18 + #define ASPIRE_EC_EVENT 0x05 19 + 20 + #define ASPIRE_EC_EVENT_WATCHDOG 0x20 21 + #define ASPIRE_EC_EVENT_KBD_BKL_ON 0x57 22 + #define ASPIRE_EC_EVENT_KBD_BKL_OFF 0x58 23 + #define ASPIRE_EC_EVENT_LID_CLOSE 0x9b 24 + #define ASPIRE_EC_EVENT_LID_OPEN 0x9c 25 + #define ASPIRE_EC_EVENT_BKL_UNBLANKED 0x9d 26 + #define ASPIRE_EC_EVENT_BKL_BLANKED 0x9e 27 + #define ASPIRE_EC_EVENT_FG_INF_CHG 0x85 28 + #define ASPIRE_EC_EVENT_FG_STA_CHG 0xc6 29 + #define ASPIRE_EC_EVENT_HPD_DIS 0xa3 30 + #define ASPIRE_EC_EVENT_HPD_CON 0xa4 31 + 32 + #define ASPIRE_EC_FG_DYNAMIC 0x07 33 + #define ASPIRE_EC_FG_STATIC 0x08 34 + 35 + #define ASPIRE_EC_FG_FLAG_PRESENT BIT(0) 36 + #define ASPIRE_EC_FG_FLAG_FULL BIT(1) 37 + #define ASPIRE_EC_FG_FLAG_DISCHARGING BIT(2) 38 + #define ASPIRE_EC_FG_FLAG_CHARGING BIT(3) 39 + 40 + #define ASPIRE_EC_RAM_READ 0x20 41 + #define ASPIRE_EC_RAM_WRITE 0x21 42 + 43 + #define ASPIRE_EC_RAM_WATCHDOG 0x19 44 + #define ASPIRE_EC_WATCHDOG_BIT BIT(6) 45 + 46 + #define ASPIRE_EC_RAM_KBD_MODE 0x43 47 + 48 + #define ASPIRE_EC_RAM_KBD_FN_EN BIT(0) 49 + #define ASPIRE_EC_RAM_KBD_MEDIA_ON_TOP BIT(5) 50 + #define ASPIRE_EC_RAM_KBD_ALWAYS_SET BIT(6) 51 + #define ASPIRE_EC_RAM_KBD_NUM_LAYER_EN BIT(7) 52 + 53 + #define ASPIRE_EC_RAM_KBD_MODE_2 0x60 54 + 55 + #define ASPIRE_EC_RAM_KBD_MEDIA_NOTIFY BIT(3) 56 + 57 + #define ASPIRE_EC_RAM_HPD_STATUS 0xf4 58 + #define ASPIRE_EC_HPD_CONNECTED 0x03 59 + 60 + #define ASPIRE_EC_RAM_LID_STATUS 0x4c 61 + #define ASPIRE_EC_LID_OPEN BIT(6) 62 + 63 + #define ASPIRE_EC_RAM_ADP 0x40 64 + #define ASPIRE_EC_AC_STATUS BIT(0) 65 + 66 + struct aspire_ec { 67 + struct i2c_client *client; 68 + struct power_supply *bat_psy; 69 + struct power_supply *adp_psy; 70 + struct input_dev *idev; 71 + 72 + bool bridge_configured; 73 + struct drm_bridge bridge; 74 + struct work_struct work; 75 + }; 76 + 77 + static int aspire_ec_ram_read(struct i2c_client *client, u8 off, u8 *data, u8 data_len) 78 + { 79 + i2c_smbus_write_byte_data(client, ASPIRE_EC_RAM_READ, off); 80 + i2c_smbus_read_i2c_block_data(client, ASPIRE_EC_RAM_READ, data_len, data); 81 + return 0; 82 + } 83 + 84 + static int aspire_ec_ram_write(struct i2c_client *client, u8 off, u8 data) 85 + { 86 + u8 tmp[2] = {off, data}; 87 + 88 + i2c_smbus_write_i2c_block_data(client, ASPIRE_EC_RAM_WRITE, sizeof(tmp), tmp); 89 + return 0; 90 + } 91 + 92 + static irqreturn_t aspire_ec_irq_handler(int irq, void *data) 93 + { 94 + struct aspire_ec *ec = data; 95 + int id; 96 + u8 tmp; 97 + 98 + /* 99 + * The original ACPI firmware actually has a small sleep in the handler. 100 + * 101 + * It seems like in most cases it's not needed but when the device 102 + * just exits suspend, our i2c driver has a brief time where data 103 + * transfer is not possible yet. So this delay allows us to suppress 104 + * quite a bunch of spurious error messages in dmesg. Thus it's kept. 105 + */ 106 + usleep_range(15000, 30000); 107 + 108 + id = i2c_smbus_read_byte_data(ec->client, ASPIRE_EC_EVENT); 109 + if (id < 0) { 110 + dev_err(&ec->client->dev, "Failed to read event id: %pe\n", ERR_PTR(id)); 111 + return IRQ_HANDLED; 112 + } 113 + 114 + switch (id) { 115 + case 0x0: /* No event */ 116 + break; 117 + 118 + case ASPIRE_EC_EVENT_WATCHDOG: 119 + /* 120 + * Here acpi responds to the event and clears some bit. 121 + * Notify (\_SB.I2C3.BAT1, 0x81) // Information Change 122 + * Notify (\_SB.I2C3.ADP1, 0x80) // Status Change 123 + */ 124 + aspire_ec_ram_read(ec->client, ASPIRE_EC_RAM_WATCHDOG, &tmp, sizeof(tmp)); 125 + tmp &= ~ASPIRE_EC_WATCHDOG_BIT; 126 + aspire_ec_ram_write(ec->client, ASPIRE_EC_RAM_WATCHDOG, tmp); 127 + break; 128 + 129 + case ASPIRE_EC_EVENT_LID_CLOSE: 130 + /* Notify (\_SB.LID0, 0x80) // Status Change */ 131 + input_report_switch(ec->idev, SW_LID, 1); 132 + input_sync(ec->idev); 133 + break; 134 + 135 + case ASPIRE_EC_EVENT_LID_OPEN: 136 + /* Notify (\_SB.LID0, 0x80) // Status Change */ 137 + input_report_switch(ec->idev, SW_LID, 0); 138 + input_sync(ec->idev); 139 + break; 140 + 141 + case ASPIRE_EC_EVENT_FG_INF_CHG: 142 + /* Notify (\_SB.I2C3.BAT1, 0x81) // Information Change */ 143 + fallthrough; 144 + case ASPIRE_EC_EVENT_FG_STA_CHG: 145 + /* Notify (\_SB.I2C3.BAT1, 0x80) // Status Change */ 146 + power_supply_changed(ec->bat_psy); 147 + power_supply_changed(ec->adp_psy); 148 + break; 149 + 150 + case ASPIRE_EC_EVENT_HPD_DIS: 151 + if (ec->bridge_configured) 152 + drm_bridge_hpd_notify(&ec->bridge, connector_status_disconnected); 153 + break; 154 + 155 + case ASPIRE_EC_EVENT_HPD_CON: 156 + if (ec->bridge_configured) 157 + drm_bridge_hpd_notify(&ec->bridge, connector_status_connected); 158 + break; 159 + 160 + case ASPIRE_EC_EVENT_BKL_BLANKED: 161 + case ASPIRE_EC_EVENT_BKL_UNBLANKED: 162 + /* Display backlight blanked on FN+F6. No action needed. */ 163 + break; 164 + 165 + case ASPIRE_EC_EVENT_KBD_BKL_ON: 166 + case ASPIRE_EC_EVENT_KBD_BKL_OFF: 167 + /* 168 + * There is a keyboard backlight connector on Aspire 1 that is 169 + * controlled by FN+F8. There is no kb backlight on the device though. 170 + * Seems like this is used on other devices like Acer Spin 7. 171 + * No action needed. 172 + */ 173 + break; 174 + 175 + default: 176 + dev_warn(&ec->client->dev, "Unknown event id=0x%x\n", id); 177 + } 178 + 179 + return IRQ_HANDLED; 180 + } 181 + 182 + /* 183 + * Power supply. 184 + */ 185 + 186 + struct aspire_ec_bat_psy_static_data { 187 + u8 unk1; 188 + u8 flags; 189 + __le16 unk2; 190 + __le16 voltage_design; 191 + __le16 capacity_full; 192 + __le16 unk3; 193 + __le16 serial; 194 + u8 model_id; 195 + u8 vendor_id; 196 + } __packed; 197 + 198 + static const char * const aspire_ec_bat_psy_battery_model[] = { 199 + "AP18C4K", 200 + "AP18C8K", 201 + "AP19B8K", 202 + "AP16M4J", 203 + "AP16M5J", 204 + }; 205 + 206 + static const char * const aspire_ec_bat_psy_battery_vendor[] = { 207 + "SANYO", 208 + "SONY", 209 + "PANASONIC", 210 + "SAMSUNG", 211 + "SIMPLO", 212 + "MOTOROLA", 213 + "CELXPERT", 214 + "LGC", 215 + "GETAC", 216 + "MURATA", 217 + }; 218 + 219 + struct aspire_ec_bat_psy_dynamic_data { 220 + u8 unk1; 221 + u8 flags; 222 + u8 unk2; 223 + __le16 capacity_now; 224 + __le16 voltage_now; 225 + __le16 current_now; 226 + __le16 unk3; 227 + __le16 unk4; 228 + } __packed; 229 + 230 + static int aspire_ec_bat_psy_get_property(struct power_supply *psy, 231 + enum power_supply_property psp, 232 + union power_supply_propval *val) 233 + { 234 + struct aspire_ec *ec = power_supply_get_drvdata(psy); 235 + struct aspire_ec_bat_psy_static_data sdat; 236 + struct aspire_ec_bat_psy_dynamic_data ddat; 237 + int str_index = 0; 238 + 239 + i2c_smbus_read_i2c_block_data(ec->client, ASPIRE_EC_FG_STATIC, sizeof(sdat), (u8 *)&sdat); 240 + i2c_smbus_read_i2c_block_data(ec->client, ASPIRE_EC_FG_DYNAMIC, sizeof(ddat), (u8 *)&ddat); 241 + 242 + switch (psp) { 243 + case POWER_SUPPLY_PROP_STATUS: 244 + val->intval = POWER_SUPPLY_STATUS_UNKNOWN; 245 + if (ddat.flags & ASPIRE_EC_FG_FLAG_CHARGING) 246 + val->intval = POWER_SUPPLY_STATUS_CHARGING; 247 + else if (ddat.flags & ASPIRE_EC_FG_FLAG_DISCHARGING) 248 + val->intval = POWER_SUPPLY_STATUS_DISCHARGING; 249 + else if (ddat.flags & ASPIRE_EC_FG_FLAG_FULL) 250 + val->intval = POWER_SUPPLY_STATUS_FULL; 251 + break; 252 + 253 + case POWER_SUPPLY_PROP_VOLTAGE_NOW: 254 + val->intval = get_unaligned_le16(&ddat.voltage_now) * MILLI_TO_MICRO; 255 + break; 256 + 257 + case POWER_SUPPLY_PROP_VOLTAGE_MAX_DESIGN: 258 + val->intval = le16_to_cpu(sdat.voltage_design) * MILLI_TO_MICRO; 259 + break; 260 + 261 + case POWER_SUPPLY_PROP_CHARGE_NOW: 262 + val->intval = get_unaligned_le16(&ddat.capacity_now) * MILLI_TO_MICRO; 263 + break; 264 + 265 + case POWER_SUPPLY_PROP_CHARGE_FULL: 266 + val->intval = le16_to_cpu(sdat.capacity_full) * MILLI_TO_MICRO; 267 + break; 268 + 269 + case POWER_SUPPLY_PROP_CAPACITY: 270 + val->intval = get_unaligned_le16(&ddat.capacity_now) * 100; 271 + val->intval /= le16_to_cpu(sdat.capacity_full); 272 + break; 273 + 274 + case POWER_SUPPLY_PROP_CURRENT_NOW: 275 + val->intval = (s16)get_unaligned_le16(&ddat.current_now) * MILLI_TO_MICRO; 276 + break; 277 + 278 + case POWER_SUPPLY_PROP_PRESENT: 279 + val->intval = !!(ddat.flags & ASPIRE_EC_FG_FLAG_PRESENT); 280 + break; 281 + 282 + case POWER_SUPPLY_PROP_SCOPE: 283 + val->intval = POWER_SUPPLY_SCOPE_SYSTEM; 284 + break; 285 + 286 + case POWER_SUPPLY_PROP_MODEL_NAME: 287 + str_index = sdat.model_id - 1; 288 + 289 + if (str_index >= 0 && str_index < ARRAY_SIZE(aspire_ec_bat_psy_battery_model)) 290 + val->strval = aspire_ec_bat_psy_battery_model[str_index]; 291 + else 292 + val->strval = "Unknown"; 293 + break; 294 + 295 + case POWER_SUPPLY_PROP_MANUFACTURER: 296 + str_index = sdat.vendor_id - 3; /* ACPI uses 3 as an offset here. */ 297 + 298 + if (str_index >= 0 && str_index < ARRAY_SIZE(aspire_ec_bat_psy_battery_vendor)) 299 + val->strval = aspire_ec_bat_psy_battery_vendor[str_index]; 300 + else 301 + val->strval = "Unknown"; 302 + break; 303 + 304 + default: 305 + return -EINVAL; 306 + } 307 + 308 + return 0; 309 + } 310 + 311 + static enum power_supply_property aspire_ec_bat_psy_props[] = { 312 + POWER_SUPPLY_PROP_STATUS, 313 + POWER_SUPPLY_PROP_VOLTAGE_NOW, 314 + POWER_SUPPLY_PROP_VOLTAGE_MAX_DESIGN, 315 + POWER_SUPPLY_PROP_CHARGE_NOW, 316 + POWER_SUPPLY_PROP_CHARGE_FULL, 317 + POWER_SUPPLY_PROP_CAPACITY, 318 + POWER_SUPPLY_PROP_CURRENT_NOW, 319 + POWER_SUPPLY_PROP_PRESENT, 320 + POWER_SUPPLY_PROP_SCOPE, 321 + POWER_SUPPLY_PROP_MODEL_NAME, 322 + POWER_SUPPLY_PROP_MANUFACTURER, 323 + }; 324 + 325 + static const struct power_supply_desc aspire_ec_bat_psy_desc = { 326 + .name = "aspire-ec-bat", 327 + .type = POWER_SUPPLY_TYPE_BATTERY, 328 + .get_property = aspire_ec_bat_psy_get_property, 329 + .properties = aspire_ec_bat_psy_props, 330 + .num_properties = ARRAY_SIZE(aspire_ec_bat_psy_props), 331 + }; 332 + 333 + static int aspire_ec_adp_psy_get_property(struct power_supply *psy, 334 + enum power_supply_property psp, 335 + union power_supply_propval *val) 336 + { 337 + struct aspire_ec *ec = power_supply_get_drvdata(psy); 338 + u8 tmp; 339 + 340 + switch (psp) { 341 + case POWER_SUPPLY_PROP_ONLINE: 342 + aspire_ec_ram_read(ec->client, ASPIRE_EC_RAM_ADP, &tmp, sizeof(tmp)); 343 + val->intval = !!(tmp & ASPIRE_EC_AC_STATUS); 344 + break; 345 + 346 + default: 347 + return -EINVAL; 348 + } 349 + 350 + return 0; 351 + } 352 + 353 + static enum power_supply_property aspire_ec_adp_psy_props[] = { 354 + POWER_SUPPLY_PROP_ONLINE, 355 + }; 356 + 357 + static const struct power_supply_desc aspire_ec_adp_psy_desc = { 358 + .name = "aspire-ec-adp", 359 + .type = POWER_SUPPLY_TYPE_MAINS, 360 + .get_property = aspire_ec_adp_psy_get_property, 361 + .properties = aspire_ec_adp_psy_props, 362 + .num_properties = ARRAY_SIZE(aspire_ec_adp_psy_props), 363 + }; 364 + 365 + /* 366 + * USB-C DP Alt mode HPD. 367 + */ 368 + 369 + static int aspire_ec_bridge_attach(struct drm_bridge *bridge, enum drm_bridge_attach_flags flags) 370 + { 371 + return flags & DRM_BRIDGE_ATTACH_NO_CONNECTOR ? 0 : -EINVAL; 372 + } 373 + 374 + static void aspire_ec_bridge_update_hpd_work(struct work_struct *work) 375 + { 376 + struct aspire_ec *ec = container_of(work, struct aspire_ec, work); 377 + u8 tmp; 378 + 379 + aspire_ec_ram_read(ec->client, ASPIRE_EC_RAM_HPD_STATUS, &tmp, sizeof(tmp)); 380 + if (tmp == ASPIRE_EC_HPD_CONNECTED) 381 + drm_bridge_hpd_notify(&ec->bridge, connector_status_connected); 382 + else 383 + drm_bridge_hpd_notify(&ec->bridge, connector_status_disconnected); 384 + } 385 + 386 + static void aspire_ec_bridge_hpd_enable(struct drm_bridge *bridge) 387 + { 388 + struct aspire_ec *ec = container_of(bridge, struct aspire_ec, bridge); 389 + 390 + schedule_work(&ec->work); 391 + } 392 + 393 + static const struct drm_bridge_funcs aspire_ec_bridge_funcs = { 394 + .hpd_enable = aspire_ec_bridge_hpd_enable, 395 + .attach = aspire_ec_bridge_attach, 396 + }; 397 + 398 + /* 399 + * Sysfs attributes. 400 + */ 401 + 402 + static ssize_t fn_lock_show(struct device *dev, struct device_attribute *attr, char *buf) 403 + { 404 + struct aspire_ec *ec = i2c_get_clientdata(to_i2c_client(dev)); 405 + u8 tmp; 406 + 407 + aspire_ec_ram_read(ec->client, ASPIRE_EC_RAM_KBD_MODE, &tmp, sizeof(tmp)); 408 + 409 + return sysfs_emit(buf, "%u\n", !(tmp & ASPIRE_EC_RAM_KBD_MEDIA_ON_TOP)); 410 + } 411 + 412 + static ssize_t fn_lock_store(struct device *dev, struct device_attribute *attr, 413 + const char *buf, size_t count) 414 + { 415 + struct aspire_ec *ec = i2c_get_clientdata(to_i2c_client(dev)); 416 + u8 tmp; 417 + 418 + bool state; 419 + int ret; 420 + 421 + ret = kstrtobool(buf, &state); 422 + if (ret) 423 + return ret; 424 + 425 + aspire_ec_ram_read(ec->client, ASPIRE_EC_RAM_KBD_MODE, &tmp, sizeof(tmp)); 426 + 427 + if (state) 428 + tmp &= ~ASPIRE_EC_RAM_KBD_MEDIA_ON_TOP; 429 + else 430 + tmp |= ASPIRE_EC_RAM_KBD_MEDIA_ON_TOP; 431 + 432 + aspire_ec_ram_write(ec->client, ASPIRE_EC_RAM_KBD_MODE, tmp); 433 + 434 + return count; 435 + } 436 + 437 + static DEVICE_ATTR_RW(fn_lock); 438 + 439 + static struct attribute *aspire_ec_attrs[] = { 440 + &dev_attr_fn_lock.attr, 441 + NULL 442 + }; 443 + ATTRIBUTE_GROUPS(aspire_ec); 444 + 445 + static int aspire_ec_probe(struct i2c_client *client) 446 + { 447 + struct power_supply_config psy_cfg = {0}; 448 + struct device *dev = &client->dev; 449 + struct fwnode_handle *fwnode; 450 + struct aspire_ec *ec; 451 + int ret; 452 + u8 tmp; 453 + 454 + ec = devm_kzalloc(dev, sizeof(*ec), GFP_KERNEL); 455 + if (!ec) 456 + return -ENOMEM; 457 + 458 + ec->client = client; 459 + i2c_set_clientdata(client, ec); 460 + 461 + /* Battery status reports */ 462 + psy_cfg.drv_data = ec; 463 + ec->bat_psy = devm_power_supply_register(dev, &aspire_ec_bat_psy_desc, &psy_cfg); 464 + if (IS_ERR(ec->bat_psy)) 465 + return dev_err_probe(dev, PTR_ERR(ec->bat_psy), 466 + "Failed to register battery power supply\n"); 467 + 468 + ec->adp_psy = devm_power_supply_register(dev, &aspire_ec_adp_psy_desc, &psy_cfg); 469 + if (IS_ERR(ec->adp_psy)) 470 + return dev_err_probe(dev, PTR_ERR(ec->adp_psy), 471 + "Failed to register AC power supply\n"); 472 + 473 + /* Lid switch */ 474 + ec->idev = devm_input_allocate_device(dev); 475 + if (!ec->idev) 476 + return -ENOMEM; 477 + 478 + ec->idev->name = "aspire-ec"; 479 + ec->idev->phys = "aspire-ec/input0"; 480 + input_set_capability(ec->idev, EV_SW, SW_LID); 481 + 482 + ret = input_register_device(ec->idev); 483 + if (ret) 484 + return dev_err_probe(dev, ret, "Input device register failed\n"); 485 + 486 + /* Enable the keyboard fn keys */ 487 + tmp = ASPIRE_EC_RAM_KBD_FN_EN | ASPIRE_EC_RAM_KBD_ALWAYS_SET; 488 + tmp |= ASPIRE_EC_RAM_KBD_MEDIA_ON_TOP; 489 + aspire_ec_ram_write(client, ASPIRE_EC_RAM_KBD_MODE, tmp); 490 + 491 + aspire_ec_ram_read(client, ASPIRE_EC_RAM_KBD_MODE_2, &tmp, sizeof(tmp)); 492 + tmp |= ASPIRE_EC_RAM_KBD_MEDIA_NOTIFY; 493 + aspire_ec_ram_write(client, ASPIRE_EC_RAM_KBD_MODE_2, tmp); 494 + 495 + /* External Type-C display attach reports */ 496 + fwnode = device_get_named_child_node(dev, "connector"); 497 + if (fwnode) { 498 + INIT_WORK(&ec->work, aspire_ec_bridge_update_hpd_work); 499 + ec->bridge.funcs = &aspire_ec_bridge_funcs; 500 + ec->bridge.of_node = to_of_node(fwnode); 501 + ec->bridge.ops = DRM_BRIDGE_OP_HPD; 502 + ec->bridge.type = DRM_MODE_CONNECTOR_USB; 503 + 504 + ret = devm_drm_bridge_add(dev, &ec->bridge); 505 + if (ret) { 506 + fwnode_handle_put(fwnode); 507 + return dev_err_probe(dev, ret, "Failed to register drm bridge\n"); 508 + } 509 + 510 + ec->bridge_configured = true; 511 + } 512 + 513 + ret = devm_request_threaded_irq(dev, client->irq, NULL, 514 + aspire_ec_irq_handler, IRQF_ONESHOT, 515 + dev_name(dev), ec); 516 + if (ret) 517 + return dev_err_probe(dev, ret, "Failed to request irq\n"); 518 + 519 + return 0; 520 + } 521 + 522 + static int aspire_ec_resume(struct device *dev) 523 + { 524 + struct aspire_ec *ec = i2c_get_clientdata(to_i2c_client(dev)); 525 + u8 tmp; 526 + 527 + aspire_ec_ram_read(ec->client, ASPIRE_EC_RAM_LID_STATUS, &tmp, sizeof(tmp)); 528 + input_report_switch(ec->idev, SW_LID, !!(tmp & ASPIRE_EC_LID_OPEN)); 529 + input_sync(ec->idev); 530 + 531 + return 0; 532 + } 533 + 534 + static const struct i2c_device_id aspire_ec_id[] = { 535 + { "aspire1-ec", }, 536 + { } 537 + }; 538 + MODULE_DEVICE_TABLE(i2c, aspire_ec_id); 539 + 540 + static const struct of_device_id aspire_ec_of_match[] = { 541 + { .compatible = "acer,aspire1-ec", }, 542 + { } 543 + }; 544 + MODULE_DEVICE_TABLE(of, aspire_ec_of_match); 545 + 546 + static DEFINE_SIMPLE_DEV_PM_OPS(aspire_ec_pm_ops, NULL, aspire_ec_resume); 547 + 548 + static struct i2c_driver aspire_ec_driver = { 549 + .driver = { 550 + .name = "aspire-ec", 551 + .of_match_table = aspire_ec_of_match, 552 + .pm = pm_sleep_ptr(&aspire_ec_pm_ops), 553 + .dev_groups = aspire_ec_groups, 554 + }, 555 + .probe = aspire_ec_probe, 556 + .id_table = aspire_ec_id, 557 + }; 558 + module_i2c_driver(aspire_ec_driver); 559 + 560 + MODULE_DESCRIPTION("Acer Aspire 1 embedded controller"); 561 + MODULE_AUTHOR("Nikita Travkin <nikita@trvn.ru>"); 562 + MODULE_LICENSE("GPL");
+28 -14
drivers/platform/surface/aggregator/core.c
··· 618 618 619 619 static int ssam_serial_hub_probe(struct serdev_device *serdev) 620 620 { 621 - struct acpi_device *ssh = ACPI_COMPANION(&serdev->dev); 621 + struct device *dev = &serdev->dev; 622 + struct acpi_device *ssh = ACPI_COMPANION(dev); 622 623 struct ssam_controller *ctrl; 623 624 acpi_status astatus; 624 625 int status; 625 626 626 - if (gpiod_count(&serdev->dev, NULL) < 0) 627 - return -ENODEV; 627 + status = gpiod_count(dev, NULL); 628 + if (status < 0) 629 + return dev_err_probe(dev, status, "no GPIO found\n"); 628 630 629 - status = devm_acpi_dev_add_driver_gpios(&serdev->dev, ssam_acpi_gpios); 631 + status = devm_acpi_dev_add_driver_gpios(dev, ssam_acpi_gpios); 630 632 if (status) 631 633 return status; 632 634 ··· 639 637 640 638 /* Initialize controller. */ 641 639 status = ssam_controller_init(ctrl, serdev); 642 - if (status) 640 + if (status) { 641 + dev_err_probe(dev, status, "failed to initialize ssam controller\n"); 643 642 goto err_ctrl_init; 643 + } 644 644 645 645 ssam_controller_lock(ctrl); 646 646 ··· 650 646 serdev_device_set_drvdata(serdev, ctrl); 651 647 serdev_device_set_client_ops(serdev, &ssam_serdev_ops); 652 648 status = serdev_device_open(serdev); 653 - if (status) 649 + if (status) { 650 + dev_err_probe(dev, status, "failed to open serdev device\n"); 654 651 goto err_devopen; 652 + } 655 653 656 654 astatus = ssam_serdev_setup_via_acpi(ssh->handle, serdev); 657 655 if (ACPI_FAILURE(astatus)) { 658 - status = -ENXIO; 656 + status = dev_err_probe(dev, -ENXIO, "failed to setup serdev\n"); 659 657 goto err_devinit; 660 658 } 661 659 ··· 673 667 * states. 674 668 */ 675 669 status = ssam_log_firmware_version(ctrl); 676 - if (status) 670 + if (status) { 671 + dev_err_probe(dev, status, "failed to get firmware version\n"); 677 672 goto err_initrq; 673 + } 678 674 679 675 status = ssam_ctrl_notif_d0_entry(ctrl); 680 - if (status) 676 + if (status) { 677 + dev_err_probe(dev, status, "D0-entry notification failed\n"); 681 678 goto err_initrq; 679 + } 682 680 683 681 status = ssam_ctrl_notif_display_on(ctrl); 684 - if (status) 682 + if (status) { 683 + dev_err_probe(dev, status, "display-on notification failed\n"); 685 684 goto err_initrq; 685 + } 686 686 687 - status = sysfs_create_group(&serdev->dev.kobj, &ssam_sam_group); 687 + status = sysfs_create_group(&dev->kobj, &ssam_sam_group); 688 688 if (status) 689 689 goto err_initrq; 690 690 691 691 /* Set up IRQ. */ 692 692 status = ssam_irq_setup(ctrl); 693 - if (status) 693 + if (status) { 694 + dev_err_probe(dev, status, "failed to setup IRQ\n"); 694 695 goto err_irq; 696 + } 695 697 696 698 /* Finally, set main controller reference. */ 697 699 status = ssam_try_set_controller(ctrl); ··· 716 702 * resumed. In short, this causes some spurious unwanted wake-ups. 717 703 * For now let's thus default power/wakeup to false. 718 704 */ 719 - device_set_wakeup_capable(&serdev->dev, true); 705 + device_set_wakeup_capable(dev, true); 720 706 acpi_dev_clear_dependencies(ssh); 721 707 722 708 return 0; ··· 724 710 err_mainref: 725 711 ssam_irq_free(ctrl); 726 712 err_irq: 727 - sysfs_remove_group(&serdev->dev.kobj, &ssam_sam_group); 713 + sysfs_remove_group(&dev->kobj, &ssam_sam_group); 728 714 err_initrq: 729 715 ssam_controller_lock(ctrl); 730 716 ssam_controller_shutdown(ctrl);
+32 -11
drivers/platform/surface/surface_aggregator_registry.c
··· 68 68 .parent = &ssam_node_hub_base, 69 69 }; 70 70 71 - /* Platform profile / performance-mode device. */ 72 - static const struct software_node ssam_node_tmp_pprof = { 71 + /* Platform profile / performance-mode device without a fan. */ 72 + static const struct software_node ssam_node_tmp_perf_profile = { 73 73 .name = "ssam:01:03:01:00:01", 74 + .parent = &ssam_node_root, 75 + }; 76 + 77 + /* Platform profile / performance-mode device with a fan, such that 78 + * the fan controller profile can also be switched. 79 + */ 80 + static const struct property_entry ssam_node_tmp_perf_profile_has_fan[] = { 81 + PROPERTY_ENTRY_BOOL("has_fan"), 82 + { } 83 + }; 84 + 85 + static const struct software_node ssam_node_tmp_perf_profile_with_fan = { 86 + .name = "ssam:01:03:01:00:01", 87 + .parent = &ssam_node_root, 88 + .properties = ssam_node_tmp_perf_profile_has_fan, 89 + }; 90 + 91 + /* Thermal sensors. */ 92 + static const struct software_node ssam_node_tmp_sensors = { 93 + .name = "ssam:01:03:01:00:02", 74 94 .parent = &ssam_node_root, 75 95 }; 76 96 ··· 228 208 */ 229 209 static const struct software_node *ssam_node_group_gen5[] = { 230 210 &ssam_node_root, 231 - &ssam_node_tmp_pprof, 211 + &ssam_node_tmp_perf_profile, 232 212 NULL, 233 213 }; 234 214 ··· 239 219 &ssam_node_bat_ac, 240 220 &ssam_node_bat_main, 241 221 &ssam_node_bat_sb3base, 242 - &ssam_node_tmp_pprof, 222 + &ssam_node_tmp_perf_profile, 243 223 &ssam_node_bas_dtx, 244 224 &ssam_node_hid_base_keyboard, 245 225 &ssam_node_hid_base_touchpad, ··· 253 233 &ssam_node_root, 254 234 &ssam_node_bat_ac, 255 235 &ssam_node_bat_main, 256 - &ssam_node_tmp_pprof, 236 + &ssam_node_tmp_perf_profile, 257 237 &ssam_node_hid_main_keyboard, 258 238 &ssam_node_hid_main_touchpad, 259 239 &ssam_node_hid_main_iid5, ··· 265 245 &ssam_node_root, 266 246 &ssam_node_bat_ac, 267 247 &ssam_node_bat_main, 268 - &ssam_node_tmp_pprof, 248 + &ssam_node_tmp_perf_profile, 269 249 &ssam_node_hid_main_keyboard, 270 250 &ssam_node_hid_main_touchpad, 271 251 &ssam_node_hid_main_iid5, ··· 278 258 &ssam_node_root, 279 259 &ssam_node_bat_ac, 280 260 &ssam_node_bat_main, 281 - &ssam_node_tmp_pprof, 261 + &ssam_node_tmp_perf_profile, 282 262 &ssam_node_pos_tablet_switch, 283 263 &ssam_node_hid_sam_keyboard, 284 264 &ssam_node_hid_sam_penstash, ··· 294 274 &ssam_node_root, 295 275 &ssam_node_bat_ac, 296 276 &ssam_node_bat_main, 297 - &ssam_node_tmp_pprof, 277 + &ssam_node_tmp_perf_profile, 298 278 NULL, 299 279 }; 300 280 ··· 303 283 &ssam_node_root, 304 284 &ssam_node_bat_ac, 305 285 &ssam_node_bat_main, 306 - &ssam_node_tmp_pprof, 286 + &ssam_node_tmp_perf_profile, 307 287 NULL, 308 288 }; 309 289 ··· 313 293 &ssam_node_hub_kip, 314 294 &ssam_node_bat_ac, 315 295 &ssam_node_bat_main, 316 - &ssam_node_tmp_pprof, 296 + &ssam_node_tmp_perf_profile, 317 297 &ssam_node_kip_tablet_switch, 318 298 &ssam_node_hid_kip_keyboard, 319 299 &ssam_node_hid_kip_penstash, ··· 330 310 &ssam_node_hub_kip, 331 311 &ssam_node_bat_ac, 332 312 &ssam_node_bat_main, 333 - &ssam_node_tmp_pprof, 313 + &ssam_node_tmp_perf_profile_with_fan, 314 + &ssam_node_tmp_sensors, 334 315 &ssam_node_fan_speed, 335 316 &ssam_node_pos_tablet_switch, 336 317 &ssam_node_hid_kip_keyboard,
+75 -13
drivers/platform/surface/surface_platform_profile.c
··· 1 1 // SPDX-License-Identifier: GPL-2.0+ 2 2 /* 3 3 * Surface Platform Profile / Performance Mode driver for Surface System 4 - * Aggregator Module (thermal subsystem). 4 + * Aggregator Module (thermal and fan subsystem). 5 5 * 6 6 * Copyright (C) 2021-2022 Maximilian Luz <luzmaximilian@gmail.com> 7 7 */ ··· 14 14 15 15 #include <linux/surface_aggregator/device.h> 16 16 17 + // Enum for the platform performance profile sent to the TMP module. 17 18 enum ssam_tmp_profile { 18 19 SSAM_TMP_PROFILE_NORMAL = 1, 19 20 SSAM_TMP_PROFILE_BATTERY_SAVER = 2, 20 21 SSAM_TMP_PROFILE_BETTER_PERFORMANCE = 3, 21 22 SSAM_TMP_PROFILE_BEST_PERFORMANCE = 4, 23 + }; 24 + 25 + // Enum for the fan profile sent to the FAN module. This fan profile is 26 + // only sent to the EC if the 'has_fan' property is set. The integers are 27 + // not a typo, they differ from the performance profile indices. 28 + enum ssam_fan_profile { 29 + SSAM_FAN_PROFILE_NORMAL = 2, 30 + SSAM_FAN_PROFILE_BATTERY_SAVER = 1, 31 + SSAM_FAN_PROFILE_BETTER_PERFORMANCE = 3, 32 + SSAM_FAN_PROFILE_BEST_PERFORMANCE = 4, 22 33 }; 23 34 24 35 struct ssam_tmp_profile_info { ··· 38 27 __le16 unknown2; 39 28 } __packed; 40 29 41 - struct ssam_tmp_profile_device { 30 + struct ssam_platform_profile_device { 42 31 struct ssam_device *sdev; 43 32 struct platform_profile_handler handler; 33 + bool has_fan; 44 34 }; 45 35 46 36 SSAM_DEFINE_SYNC_REQUEST_CL_R(__ssam_tmp_profile_get, struct ssam_tmp_profile_info, { ··· 52 40 SSAM_DEFINE_SYNC_REQUEST_CL_W(__ssam_tmp_profile_set, __le32, { 53 41 .target_category = SSAM_SSH_TC_TMP, 54 42 .command_id = 0x03, 43 + }); 44 + 45 + SSAM_DEFINE_SYNC_REQUEST_W(__ssam_fan_profile_set, u8, { 46 + .target_category = SSAM_SSH_TC_FAN, 47 + .target_id = SSAM_SSH_TID_SAM, 48 + .command_id = 0x0e, 49 + .instance_id = 0x01, 55 50 }); 56 51 57 52 static int ssam_tmp_profile_get(struct ssam_device *sdev, enum ssam_tmp_profile *p) ··· 76 57 77 58 static int ssam_tmp_profile_set(struct ssam_device *sdev, enum ssam_tmp_profile p) 78 59 { 79 - __le32 profile_le = cpu_to_le32(p); 60 + const __le32 profile_le = cpu_to_le32(p); 80 61 81 62 return ssam_retry(__ssam_tmp_profile_set, sdev, &profile_le); 82 63 } 83 64 84 - static int convert_ssam_to_profile(struct ssam_device *sdev, enum ssam_tmp_profile p) 65 + static int ssam_fan_profile_set(struct ssam_device *sdev, enum ssam_fan_profile p) 66 + { 67 + const u8 profile = p; 68 + 69 + return ssam_retry(__ssam_fan_profile_set, sdev->ctrl, &profile); 70 + } 71 + 72 + static int convert_ssam_tmp_to_profile(struct ssam_device *sdev, enum ssam_tmp_profile p) 85 73 { 86 74 switch (p) { 87 75 case SSAM_TMP_PROFILE_NORMAL: ··· 109 83 } 110 84 } 111 85 112 - static int convert_profile_to_ssam(struct ssam_device *sdev, enum platform_profile_option p) 86 + 87 + static int convert_profile_to_ssam_tmp(struct ssam_device *sdev, enum platform_profile_option p) 113 88 { 114 89 switch (p) { 115 90 case PLATFORM_PROFILE_LOW_POWER: ··· 132 105 } 133 106 } 134 107 108 + static int convert_profile_to_ssam_fan(struct ssam_device *sdev, enum platform_profile_option p) 109 + { 110 + switch (p) { 111 + case PLATFORM_PROFILE_LOW_POWER: 112 + return SSAM_FAN_PROFILE_BATTERY_SAVER; 113 + 114 + case PLATFORM_PROFILE_BALANCED: 115 + return SSAM_FAN_PROFILE_NORMAL; 116 + 117 + case PLATFORM_PROFILE_BALANCED_PERFORMANCE: 118 + return SSAM_FAN_PROFILE_BETTER_PERFORMANCE; 119 + 120 + case PLATFORM_PROFILE_PERFORMANCE: 121 + return SSAM_FAN_PROFILE_BEST_PERFORMANCE; 122 + 123 + default: 124 + /* This should have already been caught by platform_profile_store(). */ 125 + WARN(true, "unsupported platform profile"); 126 + return -EOPNOTSUPP; 127 + } 128 + } 129 + 135 130 static int ssam_platform_profile_get(struct platform_profile_handler *pprof, 136 131 enum platform_profile_option *profile) 137 132 { 138 - struct ssam_tmp_profile_device *tpd; 133 + struct ssam_platform_profile_device *tpd; 139 134 enum ssam_tmp_profile tp; 140 135 int status; 141 136 142 - tpd = container_of(pprof, struct ssam_tmp_profile_device, handler); 137 + tpd = container_of(pprof, struct ssam_platform_profile_device, handler); 143 138 144 139 status = ssam_tmp_profile_get(tpd->sdev, &tp); 145 140 if (status) 146 141 return status; 147 142 148 - status = convert_ssam_to_profile(tpd->sdev, tp); 143 + status = convert_ssam_tmp_to_profile(tpd->sdev, tp); 149 144 if (status < 0) 150 145 return status; 151 146 ··· 178 129 static int ssam_platform_profile_set(struct platform_profile_handler *pprof, 179 130 enum platform_profile_option profile) 180 131 { 181 - struct ssam_tmp_profile_device *tpd; 132 + struct ssam_platform_profile_device *tpd; 182 133 int tp; 183 134 184 - tpd = container_of(pprof, struct ssam_tmp_profile_device, handler); 135 + tpd = container_of(pprof, struct ssam_platform_profile_device, handler); 185 136 186 - tp = convert_profile_to_ssam(tpd->sdev, profile); 137 + tp = convert_profile_to_ssam_tmp(tpd->sdev, profile); 187 138 if (tp < 0) 188 139 return tp; 189 140 190 - return ssam_tmp_profile_set(tpd->sdev, tp); 141 + tp = ssam_tmp_profile_set(tpd->sdev, tp); 142 + if (tp < 0) 143 + return tp; 144 + 145 + if (tpd->has_fan) { 146 + tp = convert_profile_to_ssam_fan(tpd->sdev, profile); 147 + if (tp < 0) 148 + return tp; 149 + tp = ssam_fan_profile_set(tpd->sdev, tp); 150 + } 151 + 152 + return tp; 191 153 } 192 154 193 155 static int surface_platform_profile_probe(struct ssam_device *sdev) 194 156 { 195 - struct ssam_tmp_profile_device *tpd; 157 + struct ssam_platform_profile_device *tpd; 196 158 197 159 tpd = devm_kzalloc(&sdev->dev, sizeof(*tpd), GFP_KERNEL); 198 160 if (!tpd) ··· 213 153 214 154 tpd->handler.profile_get = ssam_platform_profile_get; 215 155 tpd->handler.profile_set = ssam_platform_profile_set; 156 + 157 + tpd->has_fan = device_property_read_bool(&sdev->dev, "has_fan"); 216 158 217 159 set_bit(PLATFORM_PROFILE_LOW_POWER, tpd->handler.choices); 218 160 set_bit(PLATFORM_PROFILE_BALANCED, tpd->handler.choices);
+58
drivers/platform/x86/Kconfig
··· 133 133 To compile this driver as a module, choose M here: the module will 134 134 be called lenovo-yogabook. 135 135 136 + config YT2_1380 137 + tristate "Lenovo Yoga Tablet 2 1380 fast charge driver" 138 + depends on SERIAL_DEV_BUS 139 + depends on ACPI 140 + help 141 + Say Y here to enable support for the custom fast charging protocol 142 + found on the Lenovo Yoga Tablet 2 1380F / 1380L models. 143 + 144 + To compile this driver as a module, choose M here: the module will 145 + be called lenovo-yogabook. 146 + 136 147 config ACERHDF 137 148 tristate "Acer Aspire One temperature and fan driver" 138 149 depends on ACPI && THERMAL ··· 653 642 654 643 source "drivers/platform/x86/intel/Kconfig" 655 644 645 + config ACPI_QUICKSTART 646 + tristate "ACPI Quickstart button driver" 647 + depends on ACPI 648 + depends on INPUT 649 + select INPUT_SPARSEKMAP 650 + help 651 + This driver adds support for ACPI quickstart button (PNP0C32) devices. 652 + The button emits a manufacturer-specific key value when pressed, so 653 + userspace has to map this value to a standard key code. 654 + 655 + To compile this driver as a module, choose M here: the module will be 656 + called quickstart. 657 + 658 + config MEEGOPAD_ANX7428 659 + tristate "MeeGoPad ANX7428 Type-C Switch" 660 + depends on ACPI && GPIOLIB && I2C 661 + help 662 + Some MeeGoPad top-set boxes have an ANX7428 Type-C Switch for 663 + USB3.1 Gen 1 and DisplayPort over Type-C alternate mode support. 664 + 665 + This driver takes care of powering on the ANX7428 on supported 666 + MeeGoPad top-set boxes. After this the ANX7428 takes care of Type-C 667 + connector orientation and PD alternate mode switching autonomously. 668 + 656 669 config MSI_EC 657 670 tristate "MSI EC Extras" 658 671 depends on ACPI ··· 719 684 720 685 To compile this driver as a module, choose M here: the module will 721 686 be called msi-wmi. 687 + 688 + config MSI_WMI_PLATFORM 689 + tristate "MSI WMI Platform features" 690 + depends on ACPI_WMI 691 + depends on HWMON 692 + help 693 + Say Y here if you want to have support for WMI-based platform features 694 + like fan sensor access on MSI machines. 695 + 696 + To compile this driver as a module, choose M here: the module will 697 + be called msi-wmi-platform. 722 698 723 699 config XO15_EBOOK 724 700 tristate "OLPC XO-1.5 ebook switch" ··· 1041 995 1042 996 To compile this driver as a module, choose M here: the module 1043 997 will be called inspur-platform-profile. 998 + 999 + config LENOVO_WMI_CAMERA 1000 + tristate "Lenovo WMI Camera Button driver" 1001 + depends on ACPI_WMI 1002 + depends on INPUT 1003 + help 1004 + This driver provides support for Lenovo camera button. The Camera 1005 + button is a GPIO device. This driver receives ACPI notifications when 1006 + the camera button is switched on/off. 1007 + 1008 + To compile this driver as a module, choose M here: the module 1009 + will be called lenovo-wmi-camera. 1044 1010 1045 1011 source "drivers/platform/x86/x86-android-tablets/Kconfig" 1046 1012
+9
drivers/platform/x86/Makefile
··· 66 66 obj-$(CONFIG_THINKPAD_ACPI) += thinkpad_acpi.o 67 67 obj-$(CONFIG_THINKPAD_LMI) += think-lmi.o 68 68 obj-$(CONFIG_YOGABOOK) += lenovo-yogabook.o 69 + obj-$(CONFIG_YT2_1380) += lenovo-yoga-tab2-pro-1380-fastcharger.o 70 + obj-$(CONFIG_LENOVO_WMI_CAMERA) += lenovo-wmi-camera.o 69 71 70 72 # Intel 71 73 obj-y += intel/ 74 + 75 + # Microsoft 76 + obj-$(CONFIG_ACPI_QUICKSTART) += quickstart.o 77 + 78 + # MeeGoPad 79 + obj-$(CONFIG_MEEGOPAD_ANX7428) += meegopad_anx7428.o 72 80 73 81 # MSI 74 82 obj-$(CONFIG_MSI_EC) += msi-ec.o 75 83 obj-$(CONFIG_MSI_LAPTOP) += msi-laptop.o 76 84 obj-$(CONFIG_MSI_WMI) += msi-wmi.o 85 + obj-$(CONFIG_MSI_WMI_PLATFORM) += msi-wmi-platform.o 77 86 78 87 # OLPC 79 88 obj-$(CONFIG_XO15_EBOOK) += xo15-ebook.o
+1 -1
drivers/platform/x86/amd/hsmp.c
··· 693 693 hsmp_create_attr_list(attr_grp, dev, i); 694 694 } 695 695 696 - return devm_device_add_groups(dev, hsmp_attr_grps); 696 + return device_add_groups(dev, hsmp_attr_grps); 697 697 } 698 698 699 699 static int hsmp_create_acpi_sysfs_if(struct device *dev)
+15
drivers/platform/x86/amd/pmc/Kconfig
··· 18 18 19 19 If you choose to compile this driver as a module the module will be 20 20 called amd-pmc. 21 + 22 + config AMD_MP2_STB 23 + bool "AMD SoC MP2 STB function" 24 + depends on AMD_PMC 25 + default AMD_PMC 26 + help 27 + AMD MP2 STB function provides a data buffer used to log debug 28 + information about the system execution during S2Idle suspend/resume. 29 + A data buffer known as the STB (Smart Trace Buffer) is a circular 30 + buffer which is a low-level log for the SoC which is used to debug 31 + any hangs/stalls during S2Idle suspend/resume. 32 + 33 + Creates debugfs to get STB, a userspace daemon can access STB log of 34 + last S2Idle suspend/resume which can help to debug if hangs/stalls 35 + during S2Idle suspend/resume.
+1
drivers/platform/x86/amd/pmc/Makefile
··· 6 6 7 7 amd-pmc-objs := pmc.o pmc-quirks.o 8 8 obj-$(CONFIG_AMD_PMC) += amd-pmc.o 9 + amd-pmc-$(CONFIG_AMD_MP2_STB) += mp2_stb.o
+280
drivers/platform/x86/amd/pmc/mp2_stb.c
··· 1 + // SPDX-License-Identifier: GPL-2.0 2 + /* 3 + * AMD MP2 STB layer 4 + * 5 + * Copyright (c) 2024, Advanced Micro Devices, Inc. 6 + * All Rights Reserved. 7 + * 8 + * Author: Basavaraj Natikar <Basavaraj.Natikar@amd.com> 9 + */ 10 + 11 + #include <linux/debugfs.h> 12 + #include <linux/device.h> 13 + #include <linux/io.h> 14 + #include <linux/io-64-nonatomic-lo-hi.h> 15 + #include <linux/iopoll.h> 16 + #include <linux/pci.h> 17 + #include <linux/sizes.h> 18 + #include <linux/time.h> 19 + 20 + #include "pmc.h" 21 + 22 + #define VALID_MSG 0xA 23 + #define VALID_RESPONSE 2 24 + 25 + #define AMD_C2P_MSG0 0x10500 26 + #define AMD_C2P_MSG1 0x10504 27 + #define AMD_P2C_MSG0 0x10680 28 + #define AMD_P2C_MSG1 0x10684 29 + 30 + #define MP2_RESP_SLEEP_US 500 31 + #define MP2_RESP_TIMEOUT_US (1600 * USEC_PER_MSEC) 32 + 33 + #define MP2_STB_DATA_LEN_2KB 1 34 + #define MP2_STB_DATA_LEN_16KB 4 35 + 36 + #define MP2_MMIO_BAR 2 37 + 38 + struct mp2_cmd_base { 39 + union { 40 + u32 ul; 41 + struct { 42 + u32 cmd_id : 4; 43 + u32 intr_disable : 1; 44 + u32 is_dma_used : 1; 45 + u32 rsvd : 26; 46 + } field; 47 + }; 48 + }; 49 + 50 + struct mp2_cmd_response { 51 + union { 52 + u32 resp; 53 + struct { 54 + u32 cmd_id : 4; 55 + u32 status : 4; 56 + u32 response : 4; 57 + u32 rsvd2 : 20; 58 + } field; 59 + }; 60 + }; 61 + 62 + struct mp2_stb_data_valid { 63 + union { 64 + u32 data_valid; 65 + struct { 66 + u32 valid : 16; 67 + u32 length : 16; 68 + } val; 69 + }; 70 + }; 71 + 72 + static int amd_mp2_wait_response(struct amd_mp2_dev *mp2, u8 cmd_id, u32 command_sts) 73 + { 74 + struct mp2_cmd_response cmd_resp; 75 + 76 + if (!readl_poll_timeout(mp2->mmio + AMD_P2C_MSG0, cmd_resp.resp, 77 + (cmd_resp.field.response == 0x0 && 78 + cmd_resp.field.status == command_sts && 79 + cmd_resp.field.cmd_id == cmd_id), MP2_RESP_SLEEP_US, 80 + MP2_RESP_TIMEOUT_US)) 81 + return cmd_resp.field.status; 82 + 83 + return -ETIMEDOUT; 84 + } 85 + 86 + static void amd_mp2_stb_send_cmd(struct amd_mp2_dev *mp2, u8 cmd_id, bool is_dma_used) 87 + { 88 + struct mp2_cmd_base cmd_base; 89 + 90 + cmd_base.ul = 0; 91 + cmd_base.field.cmd_id = cmd_id; 92 + cmd_base.field.intr_disable = 1; 93 + cmd_base.field.is_dma_used = is_dma_used; 94 + 95 + writeq(mp2->dma_addr, mp2->mmio + AMD_C2P_MSG1); 96 + writel(cmd_base.ul, mp2->mmio + AMD_C2P_MSG0); 97 + } 98 + 99 + static int amd_mp2_stb_region(struct amd_mp2_dev *mp2) 100 + { 101 + struct device *dev = &mp2->pdev->dev; 102 + unsigned int len = mp2->stb_len; 103 + 104 + if (!mp2->stbdata) { 105 + mp2->vslbase = dmam_alloc_coherent(dev, len, &mp2->dma_addr, GFP_KERNEL); 106 + if (!mp2->vslbase) 107 + return -ENOMEM; 108 + 109 + mp2->stbdata = devm_kzalloc(dev, len, GFP_KERNEL); 110 + if (!mp2->stbdata) 111 + return -ENOMEM; 112 + } 113 + 114 + return 0; 115 + } 116 + 117 + static int amd_mp2_process_cmd(struct amd_mp2_dev *mp2, struct file *filp) 118 + { 119 + struct device *dev = &mp2->pdev->dev; 120 + struct mp2_stb_data_valid stb_dv; 121 + int status; 122 + 123 + stb_dv.data_valid = readl(mp2->mmio + AMD_P2C_MSG1); 124 + 125 + if (stb_dv.val.valid != VALID_MSG) { 126 + dev_dbg(dev, "Invalid STB data\n"); 127 + return -EBADMSG; 128 + } 129 + 130 + if (stb_dv.val.length != MP2_STB_DATA_LEN_2KB && 131 + stb_dv.val.length != MP2_STB_DATA_LEN_16KB) { 132 + dev_dbg(dev, "Unsupported length\n"); 133 + return -EMSGSIZE; 134 + } 135 + 136 + mp2->stb_len = BIT(stb_dv.val.length) * SZ_1K; 137 + 138 + status = amd_mp2_stb_region(mp2); 139 + if (status) { 140 + dev_err(dev, "Failed to init STB region, status %d\n", status); 141 + return status; 142 + } 143 + 144 + amd_mp2_stb_send_cmd(mp2, VALID_MSG, true); 145 + status = amd_mp2_wait_response(mp2, VALID_MSG, VALID_RESPONSE); 146 + if (status == VALID_RESPONSE) { 147 + memcpy_fromio(mp2->stbdata, mp2->vslbase, mp2->stb_len); 148 + filp->private_data = mp2->stbdata; 149 + mp2->is_stb_data = true; 150 + } else { 151 + dev_err(dev, "Failed to start STB dump, status %d\n", status); 152 + return -EOPNOTSUPP; 153 + } 154 + 155 + return 0; 156 + } 157 + 158 + static int amd_mp2_stb_debugfs_open(struct inode *inode, struct file *filp) 159 + { 160 + struct amd_pmc_dev *dev = filp->f_inode->i_private; 161 + struct amd_mp2_dev *mp2 = dev->mp2; 162 + 163 + if (mp2) { 164 + if (!mp2->is_stb_data) 165 + return amd_mp2_process_cmd(mp2, filp); 166 + 167 + filp->private_data = mp2->stbdata; 168 + 169 + return 0; 170 + } 171 + 172 + return -ENODEV; 173 + } 174 + 175 + static ssize_t amd_mp2_stb_debugfs_read(struct file *filp, char __user *buf, size_t size, 176 + loff_t *pos) 177 + { 178 + struct amd_pmc_dev *dev = filp->f_inode->i_private; 179 + struct amd_mp2_dev *mp2 = dev->mp2; 180 + 181 + if (!mp2) 182 + return -ENODEV; 183 + 184 + if (!filp->private_data) 185 + return -EINVAL; 186 + 187 + return simple_read_from_buffer(buf, size, pos, filp->private_data, mp2->stb_len); 188 + } 189 + 190 + static const struct file_operations amd_mp2_stb_debugfs_fops = { 191 + .owner = THIS_MODULE, 192 + .open = amd_mp2_stb_debugfs_open, 193 + .read = amd_mp2_stb_debugfs_read, 194 + }; 195 + 196 + static void amd_mp2_dbgfs_register(struct amd_pmc_dev *dev) 197 + { 198 + if (!dev->dbgfs_dir) 199 + return; 200 + 201 + debugfs_create_file("stb_read_previous_boot", 0644, dev->dbgfs_dir, dev, 202 + &amd_mp2_stb_debugfs_fops); 203 + } 204 + 205 + void amd_mp2_stb_deinit(struct amd_pmc_dev *dev) 206 + { 207 + struct amd_mp2_dev *mp2 = dev->mp2; 208 + struct pci_dev *pdev; 209 + 210 + if (mp2 && mp2->pdev) { 211 + pdev = mp2->pdev; 212 + 213 + if (mp2->mmio) 214 + pci_clear_master(pdev); 215 + 216 + pci_dev_put(pdev); 217 + 218 + if (mp2->devres_gid) 219 + devres_release_group(&pdev->dev, mp2->devres_gid); 220 + 221 + dev->mp2 = NULL; 222 + } 223 + } 224 + 225 + void amd_mp2_stb_init(struct amd_pmc_dev *dev) 226 + { 227 + struct amd_mp2_dev *mp2 = NULL; 228 + struct pci_dev *pdev; 229 + int rc; 230 + 231 + mp2 = devm_kzalloc(dev->dev, sizeof(*mp2), GFP_KERNEL); 232 + if (!mp2) 233 + return; 234 + 235 + pdev = pci_get_device(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_MP2_STB, NULL); 236 + if (!pdev) 237 + return; 238 + 239 + dev->mp2 = mp2; 240 + mp2->pdev = pdev; 241 + 242 + mp2->devres_gid = devres_open_group(&pdev->dev, NULL, GFP_KERNEL); 243 + if (!mp2->devres_gid) { 244 + dev_err(&pdev->dev, "devres_open_group failed\n"); 245 + goto mp2_error; 246 + } 247 + 248 + rc = pcim_enable_device(pdev); 249 + if (rc) { 250 + dev_err(&pdev->dev, "pcim_enable_device failed\n"); 251 + goto mp2_error; 252 + } 253 + 254 + rc = pcim_iomap_regions(pdev, BIT(MP2_MMIO_BAR), "mp2 stb"); 255 + if (rc) { 256 + dev_err(&pdev->dev, "pcim_iomap_regions failed\n"); 257 + goto mp2_error; 258 + } 259 + 260 + mp2->mmio = pcim_iomap_table(pdev)[MP2_MMIO_BAR]; 261 + if (!mp2->mmio) { 262 + dev_err(&pdev->dev, "pcim_iomap_table failed\n"); 263 + goto mp2_error; 264 + } 265 + 266 + pci_set_master(pdev); 267 + 268 + rc = dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(64)); 269 + if (rc) { 270 + dev_err(&pdev->dev, "failed to set DMA mask\n"); 271 + goto mp2_error; 272 + } 273 + 274 + amd_mp2_dbgfs_register(dev); 275 + 276 + return; 277 + 278 + mp2_error: 279 + amd_mp2_stb_deinit(dev); 280 + }
+5
drivers/platform/x86/amd/pmc/pmc.c
··· 1106 1106 } 1107 1107 1108 1108 amd_pmc_dbgfs_register(dev); 1109 + if (IS_ENABLED(CONFIG_AMD_MP2_STB)) 1110 + amd_mp2_stb_init(dev); 1109 1111 pm_report_max_hw_sleep(U64_MAX); 1110 1112 return 0; 1111 1113 ··· 1124 1122 acpi_unregister_lps0_dev(&amd_pmc_s2idle_dev_ops); 1125 1123 amd_pmc_dbgfs_unregister(dev); 1126 1124 pci_dev_put(dev->rdev); 1125 + if (IS_ENABLED(CONFIG_AMD_MP2_STB)) 1126 + amd_mp2_stb_deinit(dev); 1127 1127 mutex_destroy(&dev->lock); 1128 1128 } 1129 1129 ··· 1136 1132 {"AMDI0008", 0}, 1137 1133 {"AMDI0009", 0}, 1138 1134 {"AMDI000A", 0}, 1135 + {"AMDI000B", 0}, 1139 1136 {"AMD0004", 0}, 1140 1137 {"AMD0005", 0}, 1141 1138 { }
+15
drivers/platform/x86/amd/pmc/pmc.h
··· 14 14 #include <linux/types.h> 15 15 #include <linux/mutex.h> 16 16 17 + struct amd_mp2_dev { 18 + void __iomem *mmio; 19 + void __iomem *vslbase; 20 + void *stbdata; 21 + void *devres_gid; 22 + struct pci_dev *pdev; 23 + dma_addr_t dma_addr; 24 + int stb_len; 25 + bool is_stb_data; 26 + }; 27 + 17 28 struct amd_pmc_dev { 18 29 void __iomem *regbase; 19 30 void __iomem *smu_virt_addr; ··· 49 38 struct dentry *dbgfs_dir; 50 39 struct quirk_entry *quirks; 51 40 bool disable_8042_wakeup; 41 + struct amd_mp2_dev *mp2; 52 42 }; 53 43 54 44 void amd_pmc_process_restore_quirks(struct amd_pmc_dev *dev); 55 45 void amd_pmc_quirks_init(struct amd_pmc_dev *dev); 46 + void amd_mp2_stb_init(struct amd_pmc_dev *dev); 47 + void amd_mp2_stb_deinit(struct amd_pmc_dev *dev); 56 48 57 49 /* List of supported CPU ids */ 58 50 #define AMD_CPU_ID_RV 0x15D0 ··· 67 53 #define AMD_CPU_ID_PS 0x14E8 68 54 #define AMD_CPU_ID_SP 0x14A4 69 55 #define PCI_DEVICE_ID_AMD_1AH_M20H_ROOT 0x1507 56 + #define PCI_DEVICE_ID_AMD_MP2_STB 0x172c 70 57 71 58 #endif /* PMC_H */
+1
drivers/platform/x86/amd/pmf/core.c
··· 381 381 {"AMDI0100", 0x100}, 382 382 {"AMDI0102", 0}, 383 383 {"AMDI0103", 0}, 384 + {"AMDI0105", 0}, 384 385 { } 385 386 }; 386 387 MODULE_DEVICE_TABLE(acpi, amd_pmf_acpi_ids);
+22 -22
drivers/platform/x86/asus-laptop.c
··· 852 852 * so we don't set eof to 1 853 853 */ 854 854 855 - len += sprintf(page, ASUS_LAPTOP_NAME " " ASUS_LAPTOP_VERSION "\n"); 856 - len += sprintf(page + len, "Model reference : %s\n", asus->name); 855 + len += sysfs_emit_at(page, len, ASUS_LAPTOP_NAME " " ASUS_LAPTOP_VERSION "\n"); 856 + len += sysfs_emit_at(page, len, "Model reference : %s\n", asus->name); 857 857 /* 858 858 * The SFUN method probably allows the original driver to get the list 859 859 * of features supported by a given model. For now, 0x0100 or 0x0800 ··· 862 862 */ 863 863 rv = acpi_evaluate_integer(asus->handle, "SFUN", NULL, &temp); 864 864 if (ACPI_SUCCESS(rv)) 865 - len += sprintf(page + len, "SFUN value : %#x\n", 865 + len += sysfs_emit_at(page, len, "SFUN value : %#x\n", 866 866 (uint) temp); 867 867 /* 868 868 * The HWRS method return informations about the hardware. ··· 874 874 */ 875 875 rv = acpi_evaluate_integer(asus->handle, "HWRS", NULL, &temp); 876 876 if (ACPI_SUCCESS(rv)) 877 - len += sprintf(page + len, "HWRS value : %#x\n", 877 + len += sysfs_emit_at(page, len, "HWRS value : %#x\n", 878 878 (uint) temp); 879 879 /* 880 880 * Another value for userspace: the ASYM method returns 0x02 for ··· 885 885 */ 886 886 rv = acpi_evaluate_integer(asus->handle, "ASYM", NULL, &temp); 887 887 if (ACPI_SUCCESS(rv)) 888 - len += sprintf(page + len, "ASYM value : %#x\n", 888 + len += sysfs_emit_at(page, len, "ASYM value : %#x\n", 889 889 (uint) temp); 890 890 if (asus->dsdt_info) { 891 891 snprintf(buf, 16, "%d", asus->dsdt_info->length); 892 - len += sprintf(page + len, "DSDT length : %s\n", buf); 892 + len += sysfs_emit_at(page, len, "DSDT length : %s\n", buf); 893 893 snprintf(buf, 16, "%d", asus->dsdt_info->checksum); 894 - len += sprintf(page + len, "DSDT checksum : %s\n", buf); 894 + len += sysfs_emit_at(page, len, "DSDT checksum : %s\n", buf); 895 895 snprintf(buf, 16, "%d", asus->dsdt_info->revision); 896 - len += sprintf(page + len, "DSDT revision : %s\n", buf); 896 + len += sysfs_emit_at(page, len, "DSDT revision : %s\n", buf); 897 897 snprintf(buf, 7, "%s", asus->dsdt_info->oem_id); 898 - len += sprintf(page + len, "OEM id : %s\n", buf); 898 + len += sysfs_emit_at(page, len, "OEM id : %s\n", buf); 899 899 snprintf(buf, 9, "%s", asus->dsdt_info->oem_table_id); 900 - len += sprintf(page + len, "OEM table id : %s\n", buf); 900 + len += sysfs_emit_at(page, len, "OEM table id : %s\n", buf); 901 901 snprintf(buf, 16, "%x", asus->dsdt_info->oem_revision); 902 - len += sprintf(page + len, "OEM revision : 0x%s\n", buf); 902 + len += sysfs_emit_at(page, len, "OEM revision : 0x%s\n", buf); 903 903 snprintf(buf, 5, "%s", asus->dsdt_info->asl_compiler_id); 904 - len += sprintf(page + len, "ASL comp vendor id : %s\n", buf); 904 + len += sysfs_emit_at(page, len, "ASL comp vendor id : %s\n", buf); 905 905 snprintf(buf, 16, "%x", asus->dsdt_info->asl_compiler_revision); 906 - len += sprintf(page + len, "ASL comp revision : 0x%s\n", buf); 906 + len += sysfs_emit_at(page, len, "ASL comp revision : 0x%s\n", buf); 907 907 } 908 908 909 909 return len; ··· 933 933 { 934 934 struct asus_laptop *asus = dev_get_drvdata(dev); 935 935 936 - return sprintf(buf, "0x%08x\n", asus->ledd_status); 936 + return sysfs_emit(buf, "0x%08x\n", asus->ledd_status); 937 937 } 938 938 939 939 static ssize_t ledd_store(struct device *dev, struct device_attribute *attr, ··· 993 993 { 994 994 struct asus_laptop *asus = dev_get_drvdata(dev); 995 995 996 - return sprintf(buf, "%d\n", asus_wireless_status(asus, WL_RSTS)); 996 + return sysfs_emit(buf, "%d\n", asus_wireless_status(asus, WL_RSTS)); 997 997 } 998 998 999 999 static ssize_t wlan_store(struct device *dev, struct device_attribute *attr, ··· 1022 1022 { 1023 1023 struct asus_laptop *asus = dev_get_drvdata(dev); 1024 1024 1025 - return sprintf(buf, "%d\n", asus_wireless_status(asus, BT_RSTS)); 1025 + return sysfs_emit(buf, "%d\n", asus_wireless_status(asus, BT_RSTS)); 1026 1026 } 1027 1027 1028 1028 static ssize_t bluetooth_store(struct device *dev, ··· 1052 1052 { 1053 1053 struct asus_laptop *asus = dev_get_drvdata(dev); 1054 1054 1055 - return sprintf(buf, "%d\n", asus_wireless_status(asus, WM_RSTS)); 1055 + return sysfs_emit(buf, "%d\n", asus_wireless_status(asus, WM_RSTS)); 1056 1056 } 1057 1057 1058 1058 static ssize_t wimax_store(struct device *dev, struct device_attribute *attr, ··· 1081 1081 { 1082 1082 struct asus_laptop *asus = dev_get_drvdata(dev); 1083 1083 1084 - return sprintf(buf, "%d\n", asus_wireless_status(asus, WW_RSTS)); 1084 + return sysfs_emit(buf, "%d\n", asus_wireless_status(asus, WW_RSTS)); 1085 1085 } 1086 1086 1087 1087 static ssize_t wwan_store(struct device *dev, struct device_attribute *attr, ··· 1151 1151 { 1152 1152 struct asus_laptop *asus = dev_get_drvdata(dev); 1153 1153 1154 - return sprintf(buf, "%d\n", asus->light_switch); 1154 + return sysfs_emit(buf, "%d\n", asus->light_switch); 1155 1155 } 1156 1156 1157 1157 static ssize_t ls_switch_store(struct device *dev, ··· 1182 1182 { 1183 1183 struct asus_laptop *asus = dev_get_drvdata(dev); 1184 1184 1185 - return sprintf(buf, "%d\n", asus->light_level); 1185 + return sysfs_emit(buf, "%d\n", asus->light_level); 1186 1186 } 1187 1187 1188 1188 static ssize_t ls_level_store(struct device *dev, struct device_attribute *attr, ··· 1228 1228 if (!err) 1229 1229 err = pega_int_read(asus, PEGA_READ_ALS_L, &lo); 1230 1230 if (!err) 1231 - return sprintf(buf, "%d\n", 10 * hi + lo); 1231 + return sysfs_emit(buf, "%d\n", 10 * hi + lo); 1232 1232 return err; 1233 1233 } 1234 1234 static DEVICE_ATTR_RO(ls_value); ··· 1264 1264 { 1265 1265 struct asus_laptop *asus = dev_get_drvdata(dev); 1266 1266 1267 - return sprintf(buf, "%d\n", asus_gps_status(asus)); 1267 + return sysfs_emit(buf, "%d\n", asus_gps_status(asus)); 1268 1268 } 1269 1269 1270 1270 static ssize_t gps_store(struct device *dev, struct device_attribute *attr,
+327 -90
drivers/platform/x86/asus-wmi.c
··· 126 126 #define ASUS_SCREENPAD_BRIGHT_MAX 255 127 127 #define ASUS_SCREENPAD_BRIGHT_DEFAULT 60 128 128 129 + #define ASUS_MINI_LED_MODE_MASK 0x03 130 + /* Standard modes for devices with only on/off */ 131 + #define ASUS_MINI_LED_OFF 0x00 132 + #define ASUS_MINI_LED_ON 0x01 133 + /* New mode on some devices, define here to clarify remapping later */ 134 + #define ASUS_MINI_LED_STRONG_MODE 0x02 135 + /* New modes for devices with 3 mini-led mode types */ 136 + #define ASUS_MINI_LED_2024_WEAK 0x00 137 + #define ASUS_MINI_LED_2024_STRONG 0x01 138 + #define ASUS_MINI_LED_2024_OFF 0x02 139 + 129 140 /* Controls the power state of the USB0 hub on ROG Ally which input is on */ 130 141 #define ASUS_USB0_PWR_EC0_CSEE "\\_SB.PCI0.SBRG.EC0.CSEE" 131 142 /* 300ms so far seems to produce a reliable result on AC and battery */ 132 - #define ASUS_USB0_PWR_EC0_CSEE_WAIT 300 143 + #define ASUS_USB0_PWR_EC0_CSEE_WAIT 1500 133 144 134 145 static const char * const ashs_ids[] = { "ATK4001", "ATK4002", NULL }; 135 146 ··· 254 243 u32 tablet_switch_dev_id; 255 244 bool tablet_switch_inverted; 256 245 246 + /* The ROG Ally device requires the MCU USB device be disconnected before suspend */ 247 + bool ally_mcu_usb_switch; 248 + 257 249 enum fan_type fan_type; 258 250 enum fan_type gpu_fan_type; 259 251 enum fan_type mid_fan_type; ··· 269 255 u8 fan_boost_mode_mask; 270 256 u8 fan_boost_mode; 271 257 272 - bool charge_mode_available; 273 258 bool egpu_enable_available; 274 - bool egpu_connect_available; 275 259 bool dgpu_disable_available; 276 - bool gpu_mux_mode_available; 260 + u32 gpu_mux_dev; 277 261 278 262 /* Tunables provided by ASUS for gaming laptops */ 279 - bool ppt_pl2_sppt_available; 280 - bool ppt_pl1_spl_available; 281 - bool ppt_apu_sppt_available; 282 - bool ppt_plat_sppt_available; 283 - bool ppt_fppt_available; 284 - bool nv_dyn_boost_available; 285 - bool nv_temp_tgt_available; 263 + u32 ppt_pl2_sppt; 264 + u32 ppt_pl1_spl; 265 + u32 ppt_apu_sppt; 266 + u32 ppt_platform_sppt; 267 + u32 ppt_fppt; 268 + u32 nv_dynamic_boost; 269 + u32 nv_temp_target; 286 270 287 - bool kbd_rgb_mode_available; 271 + u32 kbd_rgb_dev; 288 272 bool kbd_rgb_state_available; 289 273 290 274 bool throttle_thermal_policy_available; ··· 300 288 bool battery_rsoc_available; 301 289 302 290 bool panel_overdrive_available; 303 - bool mini_led_mode_available; 291 + u32 mini_led_dev_id; 304 292 305 293 struct hotplug_slot hotplug_slot; 306 294 struct mutex hotplug_lock; ··· 309 297 struct work_struct hotplug_work; 310 298 311 299 bool fnlock_locked; 312 - 313 - /* The ROG Ally device requires the MCU USB device be disconnected before suspend */ 314 - bool ally_mcu_usb_switch; 315 300 316 301 struct asus_wmi_debug debug; 317 302 ··· 691 682 if (disable > 1) 692 683 return -EINVAL; 693 684 694 - if (asus->gpu_mux_mode_available) { 695 - result = asus_wmi_get_devstate_simple(asus, ASUS_WMI_DEVID_GPU_MUX); 685 + if (asus->gpu_mux_dev) { 686 + result = asus_wmi_get_devstate_simple(asus, asus->gpu_mux_dev); 696 687 if (result < 0) 697 688 /* An error here may signal greater failure of GPU handling */ 698 689 return result; ··· 757 748 return err; 758 749 } 759 750 760 - if (asus->gpu_mux_mode_available) { 761 - result = asus_wmi_get_devstate_simple(asus, ASUS_WMI_DEVID_GPU_MUX); 751 + if (asus->gpu_mux_dev) { 752 + result = asus_wmi_get_devstate_simple(asus, asus->gpu_mux_dev); 762 753 if (result < 0) { 763 754 /* An error here may signal greater failure of GPU handling */ 764 755 pr_warn("Failed to get gpu mux status: %d\n", result); ··· 811 802 struct asus_wmi *asus = dev_get_drvdata(dev); 812 803 int result; 813 804 814 - result = asus_wmi_get_devstate_simple(asus, ASUS_WMI_DEVID_GPU_MUX); 805 + result = asus_wmi_get_devstate_simple(asus, asus->gpu_mux_dev); 815 806 if (result < 0) 816 807 return result; 817 808 ··· 857 848 } 858 849 } 859 850 860 - err = asus_wmi_set_devstate(ASUS_WMI_DEVID_GPU_MUX, optimus, &result); 851 + err = asus_wmi_set_devstate(asus->gpu_mux_dev, optimus, &result); 861 852 if (err) { 862 853 dev_err(dev, "Failed to set GPU MUX mode: %d\n", err); 863 854 return err; ··· 879 870 struct device_attribute *attr, 880 871 const char *buf, size_t count) 881 872 { 873 + struct asus_wmi *asus = dev_get_drvdata(dev); 882 874 u32 cmd, mode, r, g, b, speed; 883 875 int err; 884 876 ··· 916 906 speed = 0xeb; 917 907 } 918 908 919 - err = asus_wmi_evaluate_method3(ASUS_WMI_METHODID_DEVS, ASUS_WMI_DEVID_TUF_RGB_MODE, 909 + err = asus_wmi_evaluate_method3(ASUS_WMI_METHODID_DEVS, asus->kbd_rgb_dev, 920 910 cmd | (mode << 8) | (r << 16) | (g << 24), b | (speed << 8), NULL); 921 911 if (err) 922 912 return err; ··· 1006 996 struct device_attribute *attr, 1007 997 const char *buf, size_t count) 1008 998 { 999 + struct asus_wmi *asus = dev_get_drvdata(dev); 1009 1000 int result, err; 1010 1001 u32 value; 1011 - 1012 - struct asus_wmi *asus = dev_get_drvdata(dev); 1013 1002 1014 1003 result = kstrtou32(buf, 10, &value); 1015 1004 if (result) ··· 1028 1019 return -EIO; 1029 1020 } 1030 1021 1022 + asus->ppt_pl2_sppt = value; 1031 1023 sysfs_notify(&asus->platform_device->dev.kobj, NULL, "ppt_pl2_sppt"); 1032 1024 1033 1025 return count; 1034 1026 } 1035 - static DEVICE_ATTR_WO(ppt_pl2_sppt); 1027 + 1028 + static ssize_t ppt_pl2_sppt_show(struct device *dev, 1029 + struct device_attribute *attr, 1030 + char *buf) 1031 + { 1032 + struct asus_wmi *asus = dev_get_drvdata(dev); 1033 + 1034 + return sysfs_emit(buf, "%u\n", asus->ppt_pl2_sppt); 1035 + } 1036 + static DEVICE_ATTR_RW(ppt_pl2_sppt); 1036 1037 1037 1038 /* Tunable: PPT, Intel=PL1, AMD=SPL ******************************************/ 1038 1039 static ssize_t ppt_pl1_spl_store(struct device *dev, 1039 1040 struct device_attribute *attr, 1040 1041 const char *buf, size_t count) 1041 1042 { 1043 + struct asus_wmi *asus = dev_get_drvdata(dev); 1042 1044 int result, err; 1043 1045 u32 value; 1044 - 1045 - struct asus_wmi *asus = dev_get_drvdata(dev); 1046 1046 1047 1047 result = kstrtou32(buf, 10, &value); 1048 1048 if (result) ··· 1071 1053 return -EIO; 1072 1054 } 1073 1055 1056 + asus->ppt_pl1_spl = value; 1074 1057 sysfs_notify(&asus->platform_device->dev.kobj, NULL, "ppt_pl1_spl"); 1075 1058 1076 1059 return count; 1077 1060 } 1078 - static DEVICE_ATTR_WO(ppt_pl1_spl); 1061 + static ssize_t ppt_pl1_spl_show(struct device *dev, 1062 + struct device_attribute *attr, 1063 + char *buf) 1064 + { 1065 + struct asus_wmi *asus = dev_get_drvdata(dev); 1066 + 1067 + return sysfs_emit(buf, "%u\n", asus->ppt_pl1_spl); 1068 + } 1069 + static DEVICE_ATTR_RW(ppt_pl1_spl); 1079 1070 1080 1071 /* Tunable: PPT APU FPPT ******************************************************/ 1081 1072 static ssize_t ppt_fppt_store(struct device *dev, 1082 1073 struct device_attribute *attr, 1083 1074 const char *buf, size_t count) 1084 1075 { 1076 + struct asus_wmi *asus = dev_get_drvdata(dev); 1085 1077 int result, err; 1086 1078 u32 value; 1087 - 1088 - struct asus_wmi *asus = dev_get_drvdata(dev); 1089 1079 1090 1080 result = kstrtou32(buf, 10, &value); 1091 1081 if (result) ··· 1113 1087 return -EIO; 1114 1088 } 1115 1089 1090 + asus->ppt_fppt = value; 1116 1091 sysfs_notify(&asus->platform_device->dev.kobj, NULL, "ppt_fpu_sppt"); 1117 1092 1118 1093 return count; 1119 1094 } 1120 - static DEVICE_ATTR_WO(ppt_fppt); 1095 + 1096 + static ssize_t ppt_fppt_show(struct device *dev, 1097 + struct device_attribute *attr, 1098 + char *buf) 1099 + { 1100 + struct asus_wmi *asus = dev_get_drvdata(dev); 1101 + 1102 + return sysfs_emit(buf, "%u\n", asus->ppt_fppt); 1103 + } 1104 + static DEVICE_ATTR_RW(ppt_fppt); 1121 1105 1122 1106 /* Tunable: PPT APU SPPT *****************************************************/ 1123 1107 static ssize_t ppt_apu_sppt_store(struct device *dev, 1124 1108 struct device_attribute *attr, 1125 1109 const char *buf, size_t count) 1126 1110 { 1111 + struct asus_wmi *asus = dev_get_drvdata(dev); 1127 1112 int result, err; 1128 1113 u32 value; 1129 - 1130 - struct asus_wmi *asus = dev_get_drvdata(dev); 1131 1114 1132 1115 result = kstrtou32(buf, 10, &value); 1133 1116 if (result) ··· 1156 1121 return -EIO; 1157 1122 } 1158 1123 1124 + asus->ppt_apu_sppt = value; 1159 1125 sysfs_notify(&asus->platform_device->dev.kobj, NULL, "ppt_apu_sppt"); 1160 1126 1161 1127 return count; 1162 1128 } 1163 - static DEVICE_ATTR_WO(ppt_apu_sppt); 1129 + 1130 + static ssize_t ppt_apu_sppt_show(struct device *dev, 1131 + struct device_attribute *attr, 1132 + char *buf) 1133 + { 1134 + struct asus_wmi *asus = dev_get_drvdata(dev); 1135 + 1136 + return sysfs_emit(buf, "%u\n", asus->ppt_apu_sppt); 1137 + } 1138 + static DEVICE_ATTR_RW(ppt_apu_sppt); 1164 1139 1165 1140 /* Tunable: PPT platform SPPT ************************************************/ 1166 1141 static ssize_t ppt_platform_sppt_store(struct device *dev, 1167 1142 struct device_attribute *attr, 1168 1143 const char *buf, size_t count) 1169 1144 { 1145 + struct asus_wmi *asus = dev_get_drvdata(dev); 1170 1146 int result, err; 1171 1147 u32 value; 1172 - 1173 - struct asus_wmi *asus = dev_get_drvdata(dev); 1174 1148 1175 1149 result = kstrtou32(buf, 10, &value); 1176 1150 if (result) ··· 1199 1155 return -EIO; 1200 1156 } 1201 1157 1158 + asus->ppt_platform_sppt = value; 1202 1159 sysfs_notify(&asus->platform_device->dev.kobj, NULL, "ppt_platform_sppt"); 1203 1160 1204 1161 return count; 1205 1162 } 1206 - static DEVICE_ATTR_WO(ppt_platform_sppt); 1163 + 1164 + static ssize_t ppt_platform_sppt_show(struct device *dev, 1165 + struct device_attribute *attr, 1166 + char *buf) 1167 + { 1168 + struct asus_wmi *asus = dev_get_drvdata(dev); 1169 + 1170 + return sysfs_emit(buf, "%u\n", asus->ppt_platform_sppt); 1171 + } 1172 + static DEVICE_ATTR_RW(ppt_platform_sppt); 1207 1173 1208 1174 /* Tunable: NVIDIA dynamic boost *********************************************/ 1209 1175 static ssize_t nv_dynamic_boost_store(struct device *dev, 1210 1176 struct device_attribute *attr, 1211 1177 const char *buf, size_t count) 1212 1178 { 1179 + struct asus_wmi *asus = dev_get_drvdata(dev); 1213 1180 int result, err; 1214 1181 u32 value; 1215 - 1216 - struct asus_wmi *asus = dev_get_drvdata(dev); 1217 1182 1218 1183 result = kstrtou32(buf, 10, &value); 1219 1184 if (result) ··· 1242 1189 return -EIO; 1243 1190 } 1244 1191 1192 + asus->nv_dynamic_boost = value; 1245 1193 sysfs_notify(&asus->platform_device->dev.kobj, NULL, "nv_dynamic_boost"); 1246 1194 1247 1195 return count; 1248 1196 } 1249 - static DEVICE_ATTR_WO(nv_dynamic_boost); 1197 + 1198 + static ssize_t nv_dynamic_boost_show(struct device *dev, 1199 + struct device_attribute *attr, 1200 + char *buf) 1201 + { 1202 + struct asus_wmi *asus = dev_get_drvdata(dev); 1203 + 1204 + return sysfs_emit(buf, "%u\n", asus->nv_dynamic_boost); 1205 + } 1206 + static DEVICE_ATTR_RW(nv_dynamic_boost); 1250 1207 1251 1208 /* Tunable: NVIDIA temperature target ****************************************/ 1252 1209 static ssize_t nv_temp_target_store(struct device *dev, 1253 1210 struct device_attribute *attr, 1254 1211 const char *buf, size_t count) 1255 1212 { 1213 + struct asus_wmi *asus = dev_get_drvdata(dev); 1256 1214 int result, err; 1257 1215 u32 value; 1258 - 1259 - struct asus_wmi *asus = dev_get_drvdata(dev); 1260 1216 1261 1217 result = kstrtou32(buf, 10, &value); 1262 1218 if (result) ··· 1285 1223 return -EIO; 1286 1224 } 1287 1225 1226 + asus->nv_temp_target = value; 1288 1227 sysfs_notify(&asus->platform_device->dev.kobj, NULL, "nv_temp_target"); 1289 1228 1290 1229 return count; 1291 1230 } 1292 - static DEVICE_ATTR_WO(nv_temp_target); 1231 + 1232 + static ssize_t nv_temp_target_show(struct device *dev, 1233 + struct device_attribute *attr, 1234 + char *buf) 1235 + { 1236 + struct asus_wmi *asus = dev_get_drvdata(dev); 1237 + 1238 + return sysfs_emit(buf, "%u\n", asus->nv_temp_target); 1239 + } 1240 + static DEVICE_ATTR_RW(nv_temp_target); 1241 + 1242 + /* Ally MCU Powersave ********************************************************/ 1243 + static ssize_t mcu_powersave_show(struct device *dev, 1244 + struct device_attribute *attr, char *buf) 1245 + { 1246 + struct asus_wmi *asus = dev_get_drvdata(dev); 1247 + int result; 1248 + 1249 + result = asus_wmi_get_devstate_simple(asus, ASUS_WMI_DEVID_MCU_POWERSAVE); 1250 + if (result < 0) 1251 + return result; 1252 + 1253 + return sysfs_emit(buf, "%d\n", result); 1254 + } 1255 + 1256 + static ssize_t mcu_powersave_store(struct device *dev, 1257 + struct device_attribute *attr, 1258 + const char *buf, size_t count) 1259 + { 1260 + int result, err; 1261 + u32 enable; 1262 + 1263 + struct asus_wmi *asus = dev_get_drvdata(dev); 1264 + 1265 + result = kstrtou32(buf, 10, &enable); 1266 + if (result) 1267 + return result; 1268 + 1269 + if (enable > 1) 1270 + return -EINVAL; 1271 + 1272 + err = asus_wmi_set_devstate(ASUS_WMI_DEVID_MCU_POWERSAVE, enable, &result); 1273 + if (err) { 1274 + pr_warn("Failed to set MCU powersave: %d\n", err); 1275 + return err; 1276 + } 1277 + 1278 + if (result > 1) { 1279 + pr_warn("Failed to set MCU powersave (result): 0x%x\n", result); 1280 + return -EIO; 1281 + } 1282 + 1283 + sysfs_notify(&asus->platform_device->dev.kobj, NULL, "mcu_powersave"); 1284 + 1285 + return count; 1286 + } 1287 + static DEVICE_ATTR_RW(mcu_powersave); 1293 1288 1294 1289 /* Battery ********************************************************************/ 1295 1290 ··· 1668 1549 { 1669 1550 int rv = 0, num_rgb_groups = 0, led_val; 1670 1551 1671 - if (asus->kbd_rgb_mode_available) 1552 + if (asus->kbd_rgb_dev) 1672 1553 kbd_rgb_mode_groups[num_rgb_groups++] = &kbd_rgb_mode_group; 1673 1554 if (asus->kbd_rgb_state_available) 1674 1555 kbd_rgb_mode_groups[num_rgb_groups++] = &kbd_rgb_state_group; ··· 2222 2103 } 2223 2104 static DEVICE_ATTR_RW(panel_od); 2224 2105 2106 + /* Bootup sound ***************************************************************/ 2107 + 2108 + static ssize_t boot_sound_show(struct device *dev, 2109 + struct device_attribute *attr, char *buf) 2110 + { 2111 + struct asus_wmi *asus = dev_get_drvdata(dev); 2112 + int result; 2113 + 2114 + result = asus_wmi_get_devstate_simple(asus, ASUS_WMI_DEVID_BOOT_SOUND); 2115 + if (result < 0) 2116 + return result; 2117 + 2118 + return sysfs_emit(buf, "%d\n", result); 2119 + } 2120 + 2121 + static ssize_t boot_sound_store(struct device *dev, 2122 + struct device_attribute *attr, 2123 + const char *buf, size_t count) 2124 + { 2125 + int result, err; 2126 + u32 snd; 2127 + 2128 + struct asus_wmi *asus = dev_get_drvdata(dev); 2129 + 2130 + result = kstrtou32(buf, 10, &snd); 2131 + if (result) 2132 + return result; 2133 + 2134 + if (snd > 1) 2135 + return -EINVAL; 2136 + 2137 + err = asus_wmi_set_devstate(ASUS_WMI_DEVID_BOOT_SOUND, snd, &result); 2138 + if (err) { 2139 + pr_warn("Failed to set boot sound: %d\n", err); 2140 + return err; 2141 + } 2142 + 2143 + if (result > 1) { 2144 + pr_warn("Failed to set panel boot sound (result): 0x%x\n", result); 2145 + return -EIO; 2146 + } 2147 + 2148 + sysfs_notify(&asus->platform_device->dev.kobj, NULL, "boot_sound"); 2149 + 2150 + return count; 2151 + } 2152 + static DEVICE_ATTR_RW(boot_sound); 2153 + 2225 2154 /* Mini-LED mode **************************************************************/ 2226 2155 static ssize_t mini_led_mode_show(struct device *dev, 2227 2156 struct device_attribute *attr, char *buf) 2228 2157 { 2229 2158 struct asus_wmi *asus = dev_get_drvdata(dev); 2230 - int result; 2159 + u32 value; 2160 + int err; 2231 2161 2232 - result = asus_wmi_get_devstate_simple(asus, ASUS_WMI_DEVID_MINI_LED_MODE); 2233 - if (result < 0) 2234 - return result; 2162 + err = asus_wmi_get_devstate(asus, asus->mini_led_dev_id, &value); 2163 + if (err < 0) 2164 + return err; 2165 + value = value & ASUS_MINI_LED_MODE_MASK; 2235 2166 2236 - return sysfs_emit(buf, "%d\n", result); 2167 + /* 2168 + * Remap the mode values to match previous generation mini-led. The last gen 2169 + * WMI 0 == off, while on this version WMI 2 ==off (flipped). 2170 + */ 2171 + if (asus->mini_led_dev_id == ASUS_WMI_DEVID_MINI_LED_MODE2) { 2172 + switch (value) { 2173 + case ASUS_MINI_LED_2024_WEAK: 2174 + value = ASUS_MINI_LED_ON; 2175 + break; 2176 + case ASUS_MINI_LED_2024_STRONG: 2177 + value = ASUS_MINI_LED_STRONG_MODE; 2178 + break; 2179 + case ASUS_MINI_LED_2024_OFF: 2180 + value = ASUS_MINI_LED_OFF; 2181 + break; 2182 + } 2183 + } 2184 + 2185 + return sysfs_emit(buf, "%d\n", value); 2237 2186 } 2238 2187 2239 2188 static ssize_t mini_led_mode_store(struct device *dev, ··· 2317 2130 if (result) 2318 2131 return result; 2319 2132 2320 - if (mode > 1) 2133 + if (asus->mini_led_dev_id == ASUS_WMI_DEVID_MINI_LED_MODE && 2134 + mode > ASUS_MINI_LED_ON) 2135 + return -EINVAL; 2136 + if (asus->mini_led_dev_id == ASUS_WMI_DEVID_MINI_LED_MODE2 && 2137 + mode > ASUS_MINI_LED_STRONG_MODE) 2321 2138 return -EINVAL; 2322 2139 2323 - err = asus_wmi_set_devstate(ASUS_WMI_DEVID_MINI_LED_MODE, mode, &result); 2140 + /* 2141 + * Remap the mode values so expected behaviour is the same as the last 2142 + * generation of mini-LED with 0 == off, 1 == on. 2143 + */ 2144 + if (asus->mini_led_dev_id == ASUS_WMI_DEVID_MINI_LED_MODE2) { 2145 + switch (mode) { 2146 + case ASUS_MINI_LED_OFF: 2147 + mode = ASUS_MINI_LED_2024_OFF; 2148 + break; 2149 + case ASUS_MINI_LED_ON: 2150 + mode = ASUS_MINI_LED_2024_WEAK; 2151 + break; 2152 + case ASUS_MINI_LED_STRONG_MODE: 2153 + mode = ASUS_MINI_LED_2024_STRONG; 2154 + break; 2155 + } 2156 + } 2324 2157 2158 + err = asus_wmi_set_devstate(asus->mini_led_dev_id, mode, &result); 2325 2159 if (err) { 2326 2160 pr_warn("Failed to set mini-LED: %d\n", err); 2327 2161 return err; ··· 2358 2150 return count; 2359 2151 } 2360 2152 static DEVICE_ATTR_RW(mini_led_mode); 2153 + 2154 + static ssize_t available_mini_led_mode_show(struct device *dev, 2155 + struct device_attribute *attr, char *buf) 2156 + { 2157 + struct asus_wmi *asus = dev_get_drvdata(dev); 2158 + 2159 + switch (asus->mini_led_dev_id) { 2160 + case ASUS_WMI_DEVID_MINI_LED_MODE: 2161 + return sysfs_emit(buf, "0 1\n"); 2162 + case ASUS_WMI_DEVID_MINI_LED_MODE2: 2163 + return sysfs_emit(buf, "0 1 2\n"); 2164 + } 2165 + 2166 + return sysfs_emit(buf, "0\n"); 2167 + } 2168 + 2169 + static DEVICE_ATTR_RO(available_mini_led_mode); 2361 2170 2362 2171 /* Quirks *********************************************************************/ 2363 2172 ··· 2551 2326 2552 2327 /* If we already set a value then just return it */ 2553 2328 if (asus->agfn_pwm >= 0) 2554 - return sprintf(buf, "%d\n", asus->agfn_pwm); 2329 + return sysfs_emit(buf, "%d\n", asus->agfn_pwm); 2555 2330 2556 2331 /* 2557 2332 * If we haven't set already set a value through the AGFN interface, ··· 2737 2512 if (err < 0) 2738 2513 return err; 2739 2514 2740 - return sprintf(buf, "%ld\n", 2741 - deci_kelvin_to_millicelsius(value & 0xFFFF)); 2515 + return sysfs_emit(buf, "%ld\n", 2516 + deci_kelvin_to_millicelsius(value & 0xFFFF)); 2742 2517 } 2743 2518 2744 2519 /* GPU fan on modern ROG laptops */ ··· 4286 4061 if (value < 0) 4287 4062 return value; 4288 4063 4289 - return sprintf(buf, "%d\n", value); 4064 + return sysfs_emit(buf, "%d\n", value); 4290 4065 } 4291 4066 4292 4067 #define ASUS_WMI_CREATE_DEVICE_ATTR(_name, _mode, _cm) \ ··· 4362 4137 &dev_attr_ppt_platform_sppt.attr, 4363 4138 &dev_attr_nv_dynamic_boost.attr, 4364 4139 &dev_attr_nv_temp_target.attr, 4140 + &dev_attr_mcu_powersave.attr, 4141 + &dev_attr_boot_sound.attr, 4365 4142 &dev_attr_panel_od.attr, 4366 4143 &dev_attr_mini_led_mode.attr, 4144 + &dev_attr_available_mini_led_mode.attr, 4367 4145 NULL 4368 4146 }; 4369 4147 ··· 4389 4161 else if (attr == &dev_attr_als_enable.attr) 4390 4162 devid = ASUS_WMI_DEVID_ALS_ENABLE; 4391 4163 else if (attr == &dev_attr_charge_mode.attr) 4392 - ok = asus->charge_mode_available; 4164 + devid = ASUS_WMI_DEVID_CHARGE_MODE; 4393 4165 else if (attr == &dev_attr_egpu_enable.attr) 4394 4166 ok = asus->egpu_enable_available; 4395 4167 else if (attr == &dev_attr_egpu_connected.attr) 4396 - ok = asus->egpu_connect_available; 4168 + devid = ASUS_WMI_DEVID_EGPU_CONNECTED; 4397 4169 else if (attr == &dev_attr_dgpu_disable.attr) 4398 4170 ok = asus->dgpu_disable_available; 4399 4171 else if (attr == &dev_attr_gpu_mux_mode.attr) 4400 - ok = asus->gpu_mux_mode_available; 4172 + ok = asus->gpu_mux_dev != 0; 4401 4173 else if (attr == &dev_attr_fan_boost_mode.attr) 4402 4174 ok = asus->fan_boost_mode_available; 4403 4175 else if (attr == &dev_attr_throttle_thermal_policy.attr) 4404 4176 ok = asus->throttle_thermal_policy_available; 4405 4177 else if (attr == &dev_attr_ppt_pl2_sppt.attr) 4406 - ok = asus->ppt_pl2_sppt_available; 4178 + devid = ASUS_WMI_DEVID_PPT_PL2_SPPT; 4407 4179 else if (attr == &dev_attr_ppt_pl1_spl.attr) 4408 - ok = asus->ppt_pl1_spl_available; 4180 + devid = ASUS_WMI_DEVID_PPT_PL1_SPL; 4409 4181 else if (attr == &dev_attr_ppt_fppt.attr) 4410 - ok = asus->ppt_fppt_available; 4182 + devid = ASUS_WMI_DEVID_PPT_FPPT; 4411 4183 else if (attr == &dev_attr_ppt_apu_sppt.attr) 4412 - ok = asus->ppt_apu_sppt_available; 4184 + devid = ASUS_WMI_DEVID_PPT_APU_SPPT; 4413 4185 else if (attr == &dev_attr_ppt_platform_sppt.attr) 4414 - ok = asus->ppt_plat_sppt_available; 4186 + devid = ASUS_WMI_DEVID_PPT_PLAT_SPPT; 4415 4187 else if (attr == &dev_attr_nv_dynamic_boost.attr) 4416 - ok = asus->nv_dyn_boost_available; 4188 + devid = ASUS_WMI_DEVID_NV_DYN_BOOST; 4417 4189 else if (attr == &dev_attr_nv_temp_target.attr) 4418 - ok = asus->nv_temp_tgt_available; 4190 + devid = ASUS_WMI_DEVID_NV_THERM_TARGET; 4191 + else if (attr == &dev_attr_mcu_powersave.attr) 4192 + devid = ASUS_WMI_DEVID_MCU_POWERSAVE; 4193 + else if (attr == &dev_attr_boot_sound.attr) 4194 + devid = ASUS_WMI_DEVID_BOOT_SOUND; 4419 4195 else if (attr == &dev_attr_panel_od.attr) 4420 - ok = asus->panel_overdrive_available; 4196 + devid = ASUS_WMI_DEVID_PANEL_OD; 4421 4197 else if (attr == &dev_attr_mini_led_mode.attr) 4422 - ok = asus->mini_led_mode_available; 4198 + ok = asus->mini_led_dev_id != 0; 4199 + else if (attr == &dev_attr_available_mini_led_mode.attr) 4200 + ok = asus->mini_led_dev_id != 0; 4423 4201 4424 4202 if (devid != -1) 4425 4203 ok = !(asus_wmi_get_devstate_simple(asus, devid) < 0); ··· 4663 4429 if (err) 4664 4430 goto fail_platform; 4665 4431 4666 - asus->charge_mode_available = asus_wmi_dev_is_present(asus, ASUS_WMI_DEVID_CHARGE_MODE); 4432 + /* ensure defaults for tunables */ 4433 + asus->ppt_pl2_sppt = 5; 4434 + asus->ppt_pl1_spl = 5; 4435 + asus->ppt_apu_sppt = 5; 4436 + asus->ppt_platform_sppt = 5; 4437 + asus->ppt_fppt = 5; 4438 + asus->nv_dynamic_boost = 5; 4439 + asus->nv_temp_target = 75; 4440 + 4667 4441 asus->egpu_enable_available = asus_wmi_dev_is_present(asus, ASUS_WMI_DEVID_EGPU); 4668 - asus->egpu_connect_available = asus_wmi_dev_is_present(asus, ASUS_WMI_DEVID_EGPU_CONNECTED); 4669 4442 asus->dgpu_disable_available = asus_wmi_dev_is_present(asus, ASUS_WMI_DEVID_DGPU); 4670 - asus->gpu_mux_mode_available = asus_wmi_dev_is_present(asus, ASUS_WMI_DEVID_GPU_MUX); 4671 - asus->kbd_rgb_mode_available = asus_wmi_dev_is_present(asus, ASUS_WMI_DEVID_TUF_RGB_MODE); 4672 4443 asus->kbd_rgb_state_available = asus_wmi_dev_is_present(asus, ASUS_WMI_DEVID_TUF_RGB_STATE); 4673 - asus->ppt_pl2_sppt_available = asus_wmi_dev_is_present(asus, ASUS_WMI_DEVID_PPT_PL2_SPPT); 4674 - asus->ppt_pl1_spl_available = asus_wmi_dev_is_present(asus, ASUS_WMI_DEVID_PPT_PL1_SPL); 4675 - asus->ppt_fppt_available = asus_wmi_dev_is_present(asus, ASUS_WMI_DEVID_PPT_FPPT); 4676 - asus->ppt_apu_sppt_available = asus_wmi_dev_is_present(asus, ASUS_WMI_DEVID_PPT_APU_SPPT); 4677 - asus->ppt_plat_sppt_available = asus_wmi_dev_is_present(asus, ASUS_WMI_DEVID_PPT_PLAT_SPPT); 4678 - asus->nv_dyn_boost_available = asus_wmi_dev_is_present(asus, ASUS_WMI_DEVID_NV_DYN_BOOST); 4679 - asus->nv_temp_tgt_available = asus_wmi_dev_is_present(asus, ASUS_WMI_DEVID_NV_THERM_TARGET); 4680 - asus->panel_overdrive_available = asus_wmi_dev_is_present(asus, ASUS_WMI_DEVID_PANEL_OD); 4681 - asus->mini_led_mode_available = asus_wmi_dev_is_present(asus, ASUS_WMI_DEVID_MINI_LED_MODE); 4682 4444 asus->ally_mcu_usb_switch = acpi_has_method(NULL, ASUS_USB0_PWR_EC0_CSEE) 4683 4445 && dmi_match(DMI_BOARD_NAME, "RC71L"); 4446 + 4447 + if (asus_wmi_dev_is_present(asus, ASUS_WMI_DEVID_MINI_LED_MODE)) 4448 + asus->mini_led_dev_id = ASUS_WMI_DEVID_MINI_LED_MODE; 4449 + else if (asus_wmi_dev_is_present(asus, ASUS_WMI_DEVID_MINI_LED_MODE2)) 4450 + asus->mini_led_dev_id = ASUS_WMI_DEVID_MINI_LED_MODE2; 4451 + 4452 + if (asus_wmi_dev_is_present(asus, ASUS_WMI_DEVID_GPU_MUX)) 4453 + asus->gpu_mux_dev = ASUS_WMI_DEVID_GPU_MUX; 4454 + else if (asus_wmi_dev_is_present(asus, ASUS_WMI_DEVID_GPU_MUX_VIVO)) 4455 + asus->gpu_mux_dev = ASUS_WMI_DEVID_GPU_MUX_VIVO; 4456 + 4457 + if (asus_wmi_dev_is_present(asus, ASUS_WMI_DEVID_TUF_RGB_MODE)) 4458 + asus->kbd_rgb_dev = ASUS_WMI_DEVID_TUF_RGB_MODE; 4459 + else if (asus_wmi_dev_is_present(asus, ASUS_WMI_DEVID_TUF_RGB_MODE2)) 4460 + asus->kbd_rgb_dev = ASUS_WMI_DEVID_TUF_RGB_MODE2; 4684 4461 4685 4462 err = fan_boost_mode_check_present(asus); 4686 4463 if (err) ··· 4874 4629 struct asus_wmi *asus = dev_get_drvdata(device); 4875 4630 4876 4631 if (asus->ally_mcu_usb_switch) { 4632 + /* sleep required to prevent USB0 being yanked then reappearing rapidly */ 4877 4633 if (ACPI_FAILURE(acpi_execute_simple_method(NULL, ASUS_USB0_PWR_EC0_CSEE, 0xB8))) 4878 4634 dev_err(device, "ROG Ally MCU failed to connect USB dev\n"); 4879 4635 else ··· 4886 4640 static int asus_hotk_prepare(struct device *device) 4887 4641 { 4888 4642 struct asus_wmi *asus = dev_get_drvdata(device); 4889 - int result, err; 4890 4643 4891 4644 if (asus->ally_mcu_usb_switch) { 4892 - /* When powersave is enabled it causes many issues with resume of USB hub */ 4893 - result = asus_wmi_get_devstate_simple(asus, ASUS_WMI_DEVID_MCU_POWERSAVE); 4894 - if (result == 1) { 4895 - dev_warn(device, "MCU powersave enabled, disabling to prevent resume issues"); 4896 - err = asus_wmi_set_devstate(ASUS_WMI_DEVID_MCU_POWERSAVE, 0, &result); 4897 - if (err || result != 1) 4898 - dev_err(device, "Failed to set MCU powersave mode: %d\n", err); 4899 - } 4900 4645 /* sleep required to ensure USB0 is disabled before sleep continues */ 4901 4646 if (ACPI_FAILURE(acpi_execute_simple_method(NULL, ASUS_USB0_PWR_EC0_CSEE, 0xB7))) 4902 4647 dev_err(device, "ROG Ally MCU failed to disconnect USB dev\n");
+2 -2
drivers/platform/x86/classmate-laptop.c
··· 13 13 #include <linux/input.h> 14 14 #include <linux/rfkill.h> 15 15 16 - MODULE_LICENSE("GPL"); 17 - 18 16 struct cmpc_accel { 19 17 int sensitivity; 20 18 int g_select; ··· 1137 1139 }; 1138 1140 1139 1141 MODULE_DEVICE_TABLE(acpi, cmpc_device_ids); 1142 + MODULE_DESCRIPTION("Support for Intel Classmate PC ACPI devices"); 1143 + MODULE_LICENSE("GPL");
+15
drivers/platform/x86/dell/Kconfig
··· 145 145 To compile this driver as a module, choose M here: the module will 146 146 be called dell-smo8800. 147 147 148 + config DELL_UART_BACKLIGHT 149 + tristate "Dell AIO UART Backlight driver" 150 + depends on ACPI 151 + depends on BACKLIGHT_CLASS_DEVICE 152 + depends on SERIAL_DEV_BUS 153 + help 154 + Say Y here if you want to support Dell AIO UART backlight interface. 155 + The Dell AIO machines released after 2017 come with a UART interface 156 + to communicate with the backlight scalar board. This driver creates 157 + a standard backlight interface and talks to the scalar board through 158 + UART to adjust the AIO screen brightness. 159 + 160 + To compile this driver as a module, choose M here: the module will 161 + be called dell_uart_backlight. 162 + 148 163 config DELL_WMI 149 164 tristate "Dell WMI notifications" 150 165 default m
+1
drivers/platform/x86/dell/Makefile
··· 14 14 dell-smbios-$(CONFIG_DELL_SMBIOS_WMI) += dell-smbios-wmi.o 15 15 dell-smbios-$(CONFIG_DELL_SMBIOS_SMM) += dell-smbios-smm.o 16 16 obj-$(CONFIG_DELL_SMO8800) += dell-smo8800.o 17 + obj-$(CONFIG_DELL_UART_BACKLIGHT) += dell-uart-backlight.o 17 18 obj-$(CONFIG_DELL_WMI) += dell-wmi.o 18 19 dell-wmi-objs := dell-wmi-base.o 19 20 dell-wmi-$(CONFIG_DELL_WMI_PRIVACY) += dell-wmi-privacy.o
+398
drivers/platform/x86/dell/dell-uart-backlight.c
··· 1 + // SPDX-License-Identifier: GPL-2.0-or-later 2 + /* 3 + * Dell AIO Serial Backlight Driver 4 + * 5 + * Copyright (C) 2024 Hans de Goede <hansg@kernel.org> 6 + * Copyright (C) 2017 AceLan Kao <acelan.kao@canonical.com> 7 + */ 8 + 9 + #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt 10 + 11 + #include <linux/acpi.h> 12 + #include <linux/backlight.h> 13 + #include <linux/delay.h> 14 + #include <linux/device.h> 15 + #include <linux/err.h> 16 + #include <linux/module.h> 17 + #include <linux/mutex.h> 18 + #include <linux/platform_device.h> 19 + #include <linux/serdev.h> 20 + #include <linux/string.h> 21 + #include <linux/types.h> 22 + #include <linux/wait.h> 23 + #include "../serdev_helpers.h" 24 + 25 + /* The backlight controller must respond within 1 second */ 26 + #define DELL_BL_TIMEOUT msecs_to_jiffies(1000) 27 + #define DELL_BL_MAX_BRIGHTNESS 100 28 + 29 + /* Defines for the commands send to the controller */ 30 + 31 + /* 1st byte Start Of Frame 3 MSB bits: cmd-len + 01010 SOF marker */ 32 + #define DELL_SOF(len) (((len) << 5) | 0x0a) 33 + #define GET_CMD_LEN 3 34 + #define SET_CMD_LEN 4 35 + 36 + /* 2nd byte command */ 37 + #define CMD_GET_VERSION 0x06 38 + #define CMD_SET_BRIGHTNESS 0x0b 39 + #define CMD_GET_BRIGHTNESS 0x0c 40 + #define CMD_SET_BL_POWER 0x0e 41 + 42 + /* Indexes and other defines for response received from the controller */ 43 + #define RESP_LEN 0 44 + #define RESP_CMD 1 /* Echo of CMD byte from command */ 45 + #define RESP_DATA 2 /* Start of received data */ 46 + 47 + #define SET_RESP_LEN 3 48 + #define GET_RESP_LEN 4 49 + #define MIN_RESP_LEN 3 50 + #define MAX_RESP_LEN 80 51 + 52 + struct dell_uart_backlight { 53 + struct mutex mutex; 54 + wait_queue_head_t wait_queue; 55 + struct device *dev; 56 + struct backlight_device *bl; 57 + u8 *resp; 58 + u8 resp_idx; 59 + u8 resp_len; 60 + u8 resp_max_len; 61 + u8 pending_cmd; 62 + int status; 63 + int power; 64 + }; 65 + 66 + /* Checksum: SUM(Length and Cmd and Data) xor 0xFF */ 67 + static u8 dell_uart_checksum(u8 *buf, int len) 68 + { 69 + u8 val = 0; 70 + 71 + while (len-- > 0) 72 + val += buf[len]; 73 + 74 + return val ^ 0xff; 75 + } 76 + 77 + static int dell_uart_bl_command(struct dell_uart_backlight *dell_bl, 78 + const u8 *cmd, int cmd_len, 79 + u8 *resp, int resp_max_len) 80 + { 81 + int ret; 82 + 83 + ret = mutex_lock_killable(&dell_bl->mutex); 84 + if (ret) 85 + return ret; 86 + 87 + dell_bl->status = -EBUSY; 88 + dell_bl->resp = resp; 89 + dell_bl->resp_idx = 0; 90 + dell_bl->resp_len = -1; /* Invalid / unset */ 91 + dell_bl->resp_max_len = resp_max_len; 92 + dell_bl->pending_cmd = cmd[1]; 93 + 94 + /* The TTY buffer should be big enough to take the entire cmd in one go */ 95 + ret = serdev_device_write_buf(to_serdev_device(dell_bl->dev), cmd, cmd_len); 96 + if (ret != cmd_len) { 97 + dev_err(dell_bl->dev, "Error writing command: %d\n", ret); 98 + dell_bl->status = (ret < 0) ? ret : -EIO; 99 + goto out; 100 + } 101 + 102 + ret = wait_event_timeout(dell_bl->wait_queue, dell_bl->status != -EBUSY, 103 + DELL_BL_TIMEOUT); 104 + if (ret == 0) { 105 + dev_err(dell_bl->dev, "Timed out waiting for response.\n"); 106 + /* Clear busy status to discard bytes received after this */ 107 + dell_bl->status = -ETIMEDOUT; 108 + } 109 + 110 + out: 111 + mutex_unlock(&dell_bl->mutex); 112 + return dell_bl->status; 113 + } 114 + 115 + static int dell_uart_set_brightness(struct dell_uart_backlight *dell_bl, int brightness) 116 + { 117 + u8 set_brightness[SET_CMD_LEN], resp[SET_RESP_LEN]; 118 + 119 + set_brightness[0] = DELL_SOF(SET_CMD_LEN); 120 + set_brightness[1] = CMD_SET_BRIGHTNESS; 121 + set_brightness[2] = brightness; 122 + set_brightness[3] = dell_uart_checksum(set_brightness, 3); 123 + 124 + return dell_uart_bl_command(dell_bl, set_brightness, SET_CMD_LEN, resp, SET_RESP_LEN); 125 + } 126 + 127 + static int dell_uart_get_brightness(struct dell_uart_backlight *dell_bl) 128 + { 129 + struct device *dev = dell_bl->dev; 130 + u8 get_brightness[GET_CMD_LEN], resp[GET_RESP_LEN]; 131 + int ret; 132 + 133 + get_brightness[0] = DELL_SOF(GET_CMD_LEN); 134 + get_brightness[1] = CMD_GET_BRIGHTNESS; 135 + get_brightness[2] = dell_uart_checksum(get_brightness, 2); 136 + 137 + ret = dell_uart_bl_command(dell_bl, get_brightness, GET_CMD_LEN, resp, GET_RESP_LEN); 138 + if (ret) 139 + return ret; 140 + 141 + if (resp[RESP_LEN] != GET_RESP_LEN) { 142 + dev_err(dev, "Unexpected get brightness response length: %d\n", resp[RESP_LEN]); 143 + return -EIO; 144 + } 145 + 146 + if (resp[RESP_DATA] > DELL_BL_MAX_BRIGHTNESS) { 147 + dev_err(dev, "Unexpected get brightness response: %d\n", resp[RESP_DATA]); 148 + return -EIO; 149 + } 150 + 151 + return resp[RESP_DATA]; 152 + } 153 + 154 + static int dell_uart_set_bl_power(struct dell_uart_backlight *dell_bl, int power) 155 + { 156 + u8 set_power[SET_CMD_LEN], resp[SET_RESP_LEN]; 157 + int ret; 158 + 159 + set_power[0] = DELL_SOF(SET_CMD_LEN); 160 + set_power[1] = CMD_SET_BL_POWER; 161 + set_power[2] = (power == FB_BLANK_UNBLANK) ? 1 : 0; 162 + set_power[3] = dell_uart_checksum(set_power, 3); 163 + 164 + ret = dell_uart_bl_command(dell_bl, set_power, SET_CMD_LEN, resp, SET_RESP_LEN); 165 + if (ret) 166 + return ret; 167 + 168 + dell_bl->power = power; 169 + return 0; 170 + } 171 + 172 + /* 173 + * There is no command to get backlight power status, 174 + * so we set the backlight power to "on" while initializing, 175 + * and then track and report its status by power variable. 176 + */ 177 + static int dell_uart_get_bl_power(struct dell_uart_backlight *dell_bl) 178 + { 179 + return dell_bl->power; 180 + } 181 + 182 + static int dell_uart_update_status(struct backlight_device *bd) 183 + { 184 + struct dell_uart_backlight *dell_bl = bl_get_data(bd); 185 + int ret; 186 + 187 + ret = dell_uart_set_brightness(dell_bl, bd->props.brightness); 188 + if (ret) 189 + return ret; 190 + 191 + if (bd->props.power != dell_uart_get_bl_power(dell_bl)) 192 + return dell_uart_set_bl_power(dell_bl, bd->props.power); 193 + 194 + return 0; 195 + } 196 + 197 + static int dell_uart_get_brightness_op(struct backlight_device *bd) 198 + { 199 + return dell_uart_get_brightness(bl_get_data(bd)); 200 + } 201 + 202 + static const struct backlight_ops dell_uart_backlight_ops = { 203 + .update_status = dell_uart_update_status, 204 + .get_brightness = dell_uart_get_brightness_op, 205 + }; 206 + 207 + static size_t dell_uart_bl_receive(struct serdev_device *serdev, const u8 *data, size_t len) 208 + { 209 + struct dell_uart_backlight *dell_bl = serdev_device_get_drvdata(serdev); 210 + size_t i; 211 + u8 csum; 212 + 213 + dev_dbg(dell_bl->dev, "Recv: %*ph\n", (int)len, data); 214 + 215 + /* Throw away unexpected bytes / remainder of response after an error */ 216 + if (dell_bl->status != -EBUSY) { 217 + dev_warn(dell_bl->dev, "Bytes received out of band, dropping them.\n"); 218 + return len; 219 + } 220 + 221 + i = 0; 222 + while (i < len && dell_bl->resp_idx != dell_bl->resp_len) { 223 + dell_bl->resp[dell_bl->resp_idx] = data[i++]; 224 + 225 + switch (dell_bl->resp_idx) { 226 + case RESP_LEN: /* Length byte */ 227 + dell_bl->resp_len = dell_bl->resp[RESP_LEN]; 228 + if (dell_bl->resp_len < MIN_RESP_LEN || 229 + dell_bl->resp_len > dell_bl->resp_max_len) { 230 + dev_err(dell_bl->dev, "Response length %d out if range %d - %d\n", 231 + dell_bl->resp_len, MIN_RESP_LEN, dell_bl->resp_max_len); 232 + dell_bl->status = -EIO; 233 + goto wakeup; 234 + } 235 + break; 236 + case RESP_CMD: /* CMD byte */ 237 + if (dell_bl->resp[RESP_CMD] != dell_bl->pending_cmd) { 238 + dev_err(dell_bl->dev, "Response cmd 0x%02x != pending 0x%02x\n", 239 + dell_bl->resp[RESP_CMD], dell_bl->pending_cmd); 240 + dell_bl->status = -EIO; 241 + goto wakeup; 242 + } 243 + break; 244 + } 245 + dell_bl->resp_idx++; 246 + } 247 + 248 + if (dell_bl->resp_idx != dell_bl->resp_len) 249 + return len; /* Response not complete yet */ 250 + 251 + csum = dell_uart_checksum(dell_bl->resp, dell_bl->resp_len - 1); 252 + if (dell_bl->resp[dell_bl->resp_len - 1] == csum) { 253 + dell_bl->status = 0; /* Success */ 254 + } else { 255 + dev_err(dell_bl->dev, "Checksum mismatch got 0x%02x expected 0x%02x\n", 256 + dell_bl->resp[dell_bl->resp_len - 1], csum); 257 + dell_bl->status = -EIO; 258 + } 259 + wakeup: 260 + wake_up(&dell_bl->wait_queue); 261 + return i; 262 + } 263 + 264 + static const struct serdev_device_ops dell_uart_bl_serdev_ops = { 265 + .receive_buf = dell_uart_bl_receive, 266 + .write_wakeup = serdev_device_write_wakeup, 267 + }; 268 + 269 + static int dell_uart_bl_serdev_probe(struct serdev_device *serdev) 270 + { 271 + u8 get_version[GET_CMD_LEN], resp[MAX_RESP_LEN]; 272 + struct backlight_properties props = {}; 273 + struct dell_uart_backlight *dell_bl; 274 + struct device *dev = &serdev->dev; 275 + int ret; 276 + 277 + dell_bl = devm_kzalloc(dev, sizeof(*dell_bl), GFP_KERNEL); 278 + if (!dell_bl) 279 + return -ENOMEM; 280 + 281 + mutex_init(&dell_bl->mutex); 282 + init_waitqueue_head(&dell_bl->wait_queue); 283 + dell_bl->dev = dev; 284 + 285 + ret = devm_serdev_device_open(dev, serdev); 286 + if (ret) 287 + return dev_err_probe(dev, ret, "opening UART device\n"); 288 + 289 + /* 9600 bps, no flow control, these are the default but set them to be sure */ 290 + serdev_device_set_baudrate(serdev, 9600); 291 + serdev_device_set_flow_control(serdev, false); 292 + serdev_device_set_drvdata(serdev, dell_bl); 293 + serdev_device_set_client_ops(serdev, &dell_uart_bl_serdev_ops); 294 + 295 + get_version[0] = DELL_SOF(GET_CMD_LEN); 296 + get_version[1] = CMD_GET_VERSION; 297 + get_version[2] = dell_uart_checksum(get_version, 2); 298 + 299 + ret = dell_uart_bl_command(dell_bl, get_version, GET_CMD_LEN, resp, MAX_RESP_LEN); 300 + if (ret) 301 + return dev_err_probe(dev, ret, "getting firmware version\n"); 302 + 303 + dev_dbg(dev, "Firmware version: %.*s\n", resp[RESP_LEN] - 3, resp + RESP_DATA); 304 + 305 + /* Initialize bl_power to a known value */ 306 + ret = dell_uart_set_bl_power(dell_bl, FB_BLANK_UNBLANK); 307 + if (ret) 308 + return ret; 309 + 310 + ret = dell_uart_get_brightness(dell_bl); 311 + if (ret < 0) 312 + return ret; 313 + 314 + props.type = BACKLIGHT_PLATFORM; 315 + props.brightness = ret; 316 + props.max_brightness = DELL_BL_MAX_BRIGHTNESS; 317 + props.power = dell_bl->power; 318 + 319 + dell_bl->bl = devm_backlight_device_register(dev, "dell_uart_backlight", 320 + dev, dell_bl, 321 + &dell_uart_backlight_ops, 322 + &props); 323 + return PTR_ERR_OR_ZERO(dell_bl->bl); 324 + } 325 + 326 + struct serdev_device_driver dell_uart_bl_serdev_driver = { 327 + .probe = dell_uart_bl_serdev_probe, 328 + .driver = { 329 + .name = KBUILD_MODNAME, 330 + }, 331 + }; 332 + 333 + static int dell_uart_bl_pdev_probe(struct platform_device *pdev) 334 + { 335 + struct serdev_device *serdev; 336 + struct device *ctrl_dev; 337 + int ret; 338 + 339 + ctrl_dev = get_serdev_controller("DELL0501", NULL, 0, "serial0"); 340 + if (IS_ERR(ctrl_dev)) 341 + return PTR_ERR(ctrl_dev); 342 + 343 + serdev = serdev_device_alloc(to_serdev_controller(ctrl_dev)); 344 + put_device(ctrl_dev); 345 + if (!serdev) 346 + return -ENOMEM; 347 + 348 + ret = serdev_device_add(serdev); 349 + if (ret) { 350 + dev_err(&pdev->dev, "error %d adding serdev\n", ret); 351 + serdev_device_put(serdev); 352 + return ret; 353 + } 354 + 355 + ret = serdev_device_driver_register(&dell_uart_bl_serdev_driver); 356 + if (ret) 357 + goto err_remove_serdev; 358 + 359 + /* 360 + * serdev device <-> driver matching relies on OF or ACPI matches and 361 + * neither is available here, manually bind the driver. 362 + */ 363 + ret = device_driver_attach(&dell_uart_bl_serdev_driver.driver, &serdev->dev); 364 + if (ret) 365 + goto err_unregister_serdev_driver; 366 + 367 + /* So that dell_uart_bl_pdev_remove() can remove the serdev */ 368 + platform_set_drvdata(pdev, serdev); 369 + return 0; 370 + 371 + err_unregister_serdev_driver: 372 + serdev_device_driver_unregister(&dell_uart_bl_serdev_driver); 373 + err_remove_serdev: 374 + serdev_device_remove(serdev); 375 + return ret; 376 + } 377 + 378 + static void dell_uart_bl_pdev_remove(struct platform_device *pdev) 379 + { 380 + struct serdev_device *serdev = platform_get_drvdata(pdev); 381 + 382 + serdev_device_driver_unregister(&dell_uart_bl_serdev_driver); 383 + serdev_device_remove(serdev); 384 + } 385 + 386 + static struct platform_driver dell_uart_bl_pdev_driver = { 387 + .probe = dell_uart_bl_pdev_probe, 388 + .remove_new = dell_uart_bl_pdev_remove, 389 + .driver = { 390 + .name = "dell-uart-backlight", 391 + }, 392 + }; 393 + module_platform_driver(dell_uart_bl_pdev_driver); 394 + 395 + MODULE_ALIAS("platform:dell-uart-backlight"); 396 + MODULE_DESCRIPTION("Dell AIO Serial Backlight driver"); 397 + MODULE_AUTHOR("Hans de Goede <hansg@kernel.org>"); 398 + MODULE_LICENSE("GPL");
+9 -9
drivers/platform/x86/fujitsu-laptop.c
··· 386 386 struct fujitsu_laptop *priv = dev_get_drvdata(dev); 387 387 388 388 if (!(priv->flags_supported & FLAG_LID)) 389 - return sprintf(buf, "unknown\n"); 389 + return sysfs_emit(buf, "unknown\n"); 390 390 if (priv->flags_state & FLAG_LID) 391 - return sprintf(buf, "open\n"); 391 + return sysfs_emit(buf, "open\n"); 392 392 else 393 - return sprintf(buf, "closed\n"); 393 + return sysfs_emit(buf, "closed\n"); 394 394 } 395 395 396 396 static ssize_t dock_show(struct device *dev, struct device_attribute *attr, ··· 399 399 struct fujitsu_laptop *priv = dev_get_drvdata(dev); 400 400 401 401 if (!(priv->flags_supported & FLAG_DOCK)) 402 - return sprintf(buf, "unknown\n"); 402 + return sysfs_emit(buf, "unknown\n"); 403 403 if (priv->flags_state & FLAG_DOCK) 404 - return sprintf(buf, "docked\n"); 404 + return sysfs_emit(buf, "docked\n"); 405 405 else 406 - return sprintf(buf, "undocked\n"); 406 + return sysfs_emit(buf, "undocked\n"); 407 407 } 408 408 409 409 static ssize_t radios_show(struct device *dev, struct device_attribute *attr, ··· 412 412 struct fujitsu_laptop *priv = dev_get_drvdata(dev); 413 413 414 414 if (!(priv->flags_supported & FLAG_RFKILL)) 415 - return sprintf(buf, "unknown\n"); 415 + return sysfs_emit(buf, "unknown\n"); 416 416 if (priv->flags_state & FLAG_RFKILL) 417 - return sprintf(buf, "on\n"); 417 + return sysfs_emit(buf, "on\n"); 418 418 else 419 - return sprintf(buf, "killed\n"); 419 + return sysfs_emit(buf, "killed\n"); 420 420 } 421 421 422 422 static DEVICE_ATTR_RO(lid);
+6 -6
drivers/platform/x86/hp/hp-wmi.c
··· 681 681 682 682 if (value < 0) 683 683 return value; 684 - return sprintf(buf, "%d\n", value); 684 + return sysfs_emit(buf, "%d\n", value); 685 685 } 686 686 687 687 static ssize_t hddtemp_show(struct device *dev, struct device_attribute *attr, ··· 691 691 692 692 if (value < 0) 693 693 return value; 694 - return sprintf(buf, "%d\n", value); 694 + return sysfs_emit(buf, "%d\n", value); 695 695 } 696 696 697 697 static ssize_t als_show(struct device *dev, struct device_attribute *attr, ··· 701 701 702 702 if (value < 0) 703 703 return value; 704 - return sprintf(buf, "%d\n", value); 704 + return sysfs_emit(buf, "%d\n", value); 705 705 } 706 706 707 707 static ssize_t dock_show(struct device *dev, struct device_attribute *attr, ··· 711 711 712 712 if (value < 0) 713 713 return value; 714 - return sprintf(buf, "%d\n", value); 714 + return sysfs_emit(buf, "%d\n", value); 715 715 } 716 716 717 717 static ssize_t tablet_show(struct device *dev, struct device_attribute *attr, ··· 721 721 722 722 if (value < 0) 723 723 return value; 724 - return sprintf(buf, "%d\n", value); 724 + return sysfs_emit(buf, "%d\n", value); 725 725 } 726 726 727 727 static ssize_t postcode_show(struct device *dev, struct device_attribute *attr, ··· 732 732 733 733 if (value < 0) 734 734 return value; 735 - return sprintf(buf, "0x%x\n", value); 735 + return sysfs_emit(buf, "0x%x\n", value); 736 736 } 737 737 738 738 static ssize_t als_store(struct device *dev, struct device_attribute *attr,
+4 -4
drivers/platform/x86/huawei-wmi.c
··· 379 379 if (err) 380 380 return err; 381 381 382 - return sprintf(buf, "%d\n", start); 382 + return sysfs_emit(buf, "%d\n", start); 383 383 } 384 384 385 385 static ssize_t charge_control_end_threshold_show(struct device *dev, ··· 392 392 if (err) 393 393 return err; 394 394 395 - return sprintf(buf, "%d\n", end); 395 + return sysfs_emit(buf, "%d\n", end); 396 396 } 397 397 398 398 static ssize_t charge_control_thresholds_show(struct device *dev, ··· 405 405 if (err) 406 406 return err; 407 407 408 - return sprintf(buf, "%d %d\n", start, end); 408 + return sysfs_emit(buf, "%d %d\n", start, end); 409 409 } 410 410 411 411 static ssize_t charge_control_start_threshold_store(struct device *dev, ··· 562 562 if (err) 563 563 return err; 564 564 565 - return sprintf(buf, "%d\n", on); 565 + return sysfs_emit(buf, "%d\n", on); 566 566 } 567 567 568 568 static ssize_t fn_lock_state_store(struct device *dev,
+127 -13
drivers/platform/x86/ideapad-laptop.c
··· 152 152 struct led_classdev led; 153 153 unsigned int last_brightness; 154 154 } kbd_bl; 155 + struct { 156 + bool initialized; 157 + struct led_classdev led; 158 + unsigned int last_brightness; 159 + } fn_lock; 155 160 }; 156 161 157 162 static bool no_bt_rfkill; ··· 518 513 519 514 static DEVICE_ATTR_RW(fan_mode); 520 515 521 - static ssize_t fn_lock_show(struct device *dev, 522 - struct device_attribute *attr, 523 - char *buf) 516 + static int ideapad_fn_lock_get(struct ideapad_private *priv) 524 517 { 525 - struct ideapad_private *priv = dev_get_drvdata(dev); 526 518 unsigned long hals; 527 519 int err; 528 520 ··· 527 525 if (err) 528 526 return err; 529 527 530 - return sysfs_emit(buf, "%d\n", !!test_bit(HALS_FNLOCK_STATE_BIT, &hals)); 528 + return !!test_bit(HALS_FNLOCK_STATE_BIT, &hals); 529 + } 530 + 531 + static int ideapad_fn_lock_set(struct ideapad_private *priv, bool state) 532 + { 533 + return exec_sals(priv->adev->handle, 534 + state ? SALS_FNLOCK_ON : SALS_FNLOCK_OFF); 535 + } 536 + 537 + static void ideapad_fn_lock_led_notify(struct ideapad_private *priv, int brightness) 538 + { 539 + if (!priv->fn_lock.initialized) 540 + return; 541 + 542 + if (brightness == priv->fn_lock.last_brightness) 543 + return; 544 + 545 + priv->fn_lock.last_brightness = brightness; 546 + 547 + led_classdev_notify_brightness_hw_changed(&priv->fn_lock.led, brightness); 548 + } 549 + 550 + static ssize_t fn_lock_show(struct device *dev, 551 + struct device_attribute *attr, 552 + char *buf) 553 + { 554 + struct ideapad_private *priv = dev_get_drvdata(dev); 555 + int brightness; 556 + 557 + brightness = ideapad_fn_lock_get(priv); 558 + if (brightness < 0) 559 + return brightness; 560 + 561 + return sysfs_emit(buf, "%d\n", brightness); 531 562 } 532 563 533 564 static ssize_t fn_lock_store(struct device *dev, ··· 575 540 if (err) 576 541 return err; 577 542 578 - err = exec_sals(priv->adev->handle, state ? SALS_FNLOCK_ON : SALS_FNLOCK_OFF); 543 + err = ideapad_fn_lock_set(priv, state); 579 544 if (err) 580 545 return err; 546 + 547 + ideapad_fn_lock_led_notify(priv, state); 581 548 582 549 return count; 583 550 } ··· 1218 1181 switch (bit) { 1219 1182 case 6: /* Z570 */ 1220 1183 case 0: /* Z580 */ 1221 - /* Thermal Management button */ 1222 - ideapad_input_report(priv, 65); 1184 + /* Thermal Management / Performance Mode button */ 1185 + if (priv->dytc) 1186 + platform_profile_cycle(); 1187 + else 1188 + ideapad_input_report(priv, 65); 1223 1189 break; 1224 1190 case 1: 1225 1191 /* OneKey Theater button */ ··· 1503 1463 } 1504 1464 1505 1465 /* 1466 + * FnLock LED 1467 + */ 1468 + static enum led_brightness ideapad_fn_lock_led_cdev_get(struct led_classdev *led_cdev) 1469 + { 1470 + struct ideapad_private *priv = container_of(led_cdev, struct ideapad_private, fn_lock.led); 1471 + 1472 + return ideapad_fn_lock_get(priv); 1473 + } 1474 + 1475 + static int ideapad_fn_lock_led_cdev_set(struct led_classdev *led_cdev, 1476 + enum led_brightness brightness) 1477 + { 1478 + struct ideapad_private *priv = container_of(led_cdev, struct ideapad_private, fn_lock.led); 1479 + 1480 + return ideapad_fn_lock_set(priv, brightness); 1481 + } 1482 + 1483 + static int ideapad_fn_lock_led_init(struct ideapad_private *priv) 1484 + { 1485 + int brightness, err; 1486 + 1487 + if (!priv->features.fn_lock) 1488 + return -ENODEV; 1489 + 1490 + if (WARN_ON(priv->fn_lock.initialized)) 1491 + return -EEXIST; 1492 + 1493 + priv->fn_lock.led.max_brightness = 1; 1494 + 1495 + brightness = ideapad_fn_lock_get(priv); 1496 + if (brightness < 0) 1497 + return brightness; 1498 + 1499 + priv->fn_lock.last_brightness = brightness; 1500 + priv->fn_lock.led.name = "platform::" LED_FUNCTION_FNLOCK; 1501 + priv->fn_lock.led.brightness_get = ideapad_fn_lock_led_cdev_get; 1502 + priv->fn_lock.led.brightness_set_blocking = ideapad_fn_lock_led_cdev_set; 1503 + priv->fn_lock.led.flags = LED_BRIGHT_HW_CHANGED; 1504 + 1505 + err = led_classdev_register(&priv->platform_device->dev, &priv->fn_lock.led); 1506 + if (err) 1507 + return err; 1508 + 1509 + priv->fn_lock.initialized = true; 1510 + 1511 + return 0; 1512 + } 1513 + 1514 + static void ideapad_fn_lock_led_exit(struct ideapad_private *priv) 1515 + { 1516 + if (!priv->fn_lock.initialized) 1517 + return; 1518 + 1519 + priv->fn_lock.initialized = false; 1520 + 1521 + led_classdev_unregister(&priv->fn_lock.led); 1522 + } 1523 + 1524 + /* 1506 1525 * module init/exit 1507 1526 */ 1508 1527 static void ideapad_sync_touchpad_state(struct ideapad_private *priv, bool send_events) ··· 1808 1709 { 1809 1710 struct ideapad_wmi_private *wpriv = dev_get_drvdata(&wdev->dev); 1810 1711 struct ideapad_private *priv; 1811 - unsigned long result; 1812 1712 1813 1713 mutex_lock(&ideapad_shared_mutex); 1814 1714 ··· 1820 1722 ideapad_input_report(priv, 128); 1821 1723 break; 1822 1724 case IDEAPAD_WMI_EVENT_FN_KEYS: 1823 - if (priv->features.set_fn_lock_led && 1824 - !eval_hals(priv->adev->handle, &result)) { 1825 - bool state = test_bit(HALS_FNLOCK_STATE_BIT, &result); 1725 + if (priv->features.set_fn_lock_led) { 1726 + int brightness = ideapad_fn_lock_get(priv); 1826 1727 1827 - exec_sals(priv->adev->handle, state ? SALS_FNLOCK_ON : SALS_FNLOCK_OFF); 1728 + if (brightness >= 0) { 1729 + ideapad_fn_lock_set(priv, brightness); 1730 + ideapad_fn_lock_led_notify(priv, brightness); 1731 + } 1828 1732 } 1829 1733 1830 1734 if (data->type != ACPI_TYPE_INTEGER) { ··· 1837 1737 1838 1738 dev_dbg(&wdev->dev, "WMI fn-key event: 0x%llx\n", 1839 1739 data->integer.value); 1740 + 1741 + /* 0x02 FnLock, 0x03 Esc */ 1742 + if (data->integer.value == 0x02 || data->integer.value == 0x03) 1743 + ideapad_fn_lock_led_notify(priv, data->integer.value == 0x02); 1840 1744 1841 1745 ideapad_input_report(priv, 1842 1746 data->integer.value | IDEAPAD_WMI_KEY); ··· 1935 1831 dev_info(&pdev->dev, "Keyboard backlight control not available\n"); 1936 1832 } 1937 1833 1834 + err = ideapad_fn_lock_led_init(priv); 1835 + if (err) { 1836 + if (err != -ENODEV) 1837 + dev_warn(&pdev->dev, "Could not set up FnLock LED: %d\n", err); 1838 + else 1839 + dev_info(&pdev->dev, "FnLock control not available\n"); 1840 + } 1841 + 1938 1842 /* 1939 1843 * On some models without a hw-switch (the yoga 2 13 at least) 1940 1844 * VPCCMD_W_RF must be explicitly set to 1 for the wifi to work. ··· 1999 1887 for (i = 0; i < IDEAPAD_RFKILL_DEV_NUM; i++) 2000 1888 ideapad_unregister_rfkill(priv, i); 2001 1889 1890 + ideapad_fn_lock_led_exit(priv); 2002 1891 ideapad_kbd_bl_exit(priv); 2003 1892 ideapad_input_exit(priv); 2004 1893 ··· 2027 1914 for (i = 0; i < IDEAPAD_RFKILL_DEV_NUM; i++) 2028 1915 ideapad_unregister_rfkill(priv, i); 2029 1916 1917 + ideapad_fn_lock_led_exit(priv); 2030 1918 ideapad_kbd_bl_exit(priv); 2031 1919 ideapad_input_exit(priv); 2032 1920 ideapad_debugfs_exit(priv);
+1
drivers/platform/x86/inspur_platform_profile.c
··· 207 207 .id_table = inspur_wmi_id_table, 208 208 .probe = inspur_wmi_probe, 209 209 .remove = inspur_wmi_remove, 210 + .no_singleton = true, 210 211 }; 211 212 212 213 module_wmi_driver(inspur_wmi_driver);
+2
drivers/platform/x86/intel/ifs/load.c
··· 233 233 chunk_table[0] = starting_chunk_nr + i; 234 234 chunk_table[1] = linear_addr; 235 235 do { 236 + local_irq_disable(); 236 237 wrmsrl(MSR_AUTHENTICATE_AND_COPY_CHUNK, (u64)chunk_table); 238 + local_irq_enable(); 237 239 rdmsrl(MSR_CHUNKS_AUTHENTICATION_STATUS, chunk_status.data); 238 240 err_code = chunk_status.error_code; 239 241 } while (err_code == AUTH_INTERRUPTED_ERROR && --retry_count);
+15 -12
drivers/platform/x86/intel/ifs/runtest.c
··· 69 69 70 70 static void message_not_tested(struct device *dev, int cpu, union ifs_status status) 71 71 { 72 + struct ifs_data *ifsd = ifs_get_data(dev); 73 + 74 + /* 75 + * control_error is set when the microcode runs into a problem 76 + * loading the image from the reserved BIOS memory, or it has 77 + * been corrupted. Reloading the image may fix this issue. 78 + */ 79 + if (status.control_error) { 80 + dev_warn(dev, "CPU(s) %*pbl: Scan controller error. Batch: %02x version: 0x%x\n", 81 + cpumask_pr_args(cpu_smt_mask(cpu)), ifsd->cur_batch, ifsd->loaded_version); 82 + return; 83 + } 84 + 72 85 if (status.error_code < ARRAY_SIZE(scan_test_status)) { 73 86 dev_info(dev, "CPU(s) %*pbl: SCAN operation did not start. %s\n", 74 87 cpumask_pr_args(cpu_smt_mask(cpu)), ··· 102 89 static void message_fail(struct device *dev, int cpu, union ifs_status status) 103 90 { 104 91 struct ifs_data *ifsd = ifs_get_data(dev); 105 - 106 - /* 107 - * control_error is set when the microcode runs into a problem 108 - * loading the image from the reserved BIOS memory, or it has 109 - * been corrupted. Reloading the image may fix this issue. 110 - */ 111 - if (status.control_error) { 112 - dev_err(dev, "CPU(s) %*pbl: could not execute from loaded scan image. Batch: %02x version: 0x%x\n", 113 - cpumask_pr_args(cpu_smt_mask(cpu)), ifsd->cur_batch, ifsd->loaded_version); 114 - } 115 92 116 93 /* 117 94 * signature_error is set when the output from the scan chains does not ··· 288 285 /* Update status for this core */ 289 286 ifsd->scan_details = status.data; 290 287 291 - if (status.control_error || status.signature_error) { 288 + if (status.signature_error) { 292 289 ifsd->status = SCAN_TEST_FAIL; 293 290 message_fail(dev, cpu, status); 294 - } else if (status.error_code) { 291 + } else if (status.control_error || status.error_code) { 295 292 ifsd->status = SCAN_NOT_TESTED; 296 293 message_not_tested(dev, cpu, status); 297 294 } else {
+1 -1
drivers/platform/x86/intel/pmc/arl.c
··· 1 1 // SPDX-License-Identifier: GPL-2.0 2 2 /* 3 3 * This file contains platform specific structure definitions 4 - * and init function used by Meteor Lake PCH. 4 + * and init function used by Arrow Lake PCH. 5 5 * 6 6 * Copyright (c) 2022, Intel Corporation. 7 7 * All Rights Reserved.
+38
drivers/platform/x86/intel/pmc/core.c
··· 678 678 } 679 679 DEFINE_SHOW_ATTRIBUTE(pmc_core_ltr); 680 680 681 + static int pmc_core_s0ix_blocker_show(struct seq_file *s, void *unused) 682 + { 683 + struct pmc_dev *pmcdev = s->private; 684 + unsigned int pmcidx; 685 + 686 + for (pmcidx = 0; pmcidx < ARRAY_SIZE(pmcdev->pmcs); pmcidx++) { 687 + const struct pmc_bit_map **maps; 688 + unsigned int arr_size, r_idx; 689 + u32 offset, counter; 690 + struct pmc *pmc; 691 + 692 + pmc = pmcdev->pmcs[pmcidx]; 693 + if (!pmc) 694 + continue; 695 + maps = pmc->map->s0ix_blocker_maps; 696 + offset = pmc->map->s0ix_blocker_offset; 697 + arr_size = pmc_core_lpm_get_arr_size(maps); 698 + 699 + for (r_idx = 0; r_idx < arr_size; r_idx++) { 700 + const struct pmc_bit_map *map; 701 + 702 + for (map = maps[r_idx]; map->name; map++) { 703 + if (!map->blk) 704 + continue; 705 + counter = pmc_core_reg_read(pmc, offset); 706 + seq_printf(s, "PMC%d:%-30s %-30d\n", pmcidx, 707 + map->name, counter); 708 + offset += map->blk * S0IX_BLK_SIZE; 709 + } 710 + } 711 + } 712 + return 0; 713 + } 714 + DEFINE_SHOW_ATTRIBUTE(pmc_core_s0ix_blocker); 715 + 681 716 static inline u64 adjust_lpm_residency(struct pmc *pmc, u32 offset, 682 717 const int lpm_adj_x2) 683 718 { ··· 1231 1196 &pmc_core_ltr_ignore_ops); 1232 1197 1233 1198 debugfs_create_file("ltr_show", 0444, dir, pmcdev, &pmc_core_ltr_fops); 1199 + 1200 + if (primary_pmc->map->s0ix_blocker_maps) 1201 + debugfs_create_file("s0ix_blocker", 0444, dir, pmcdev, &pmc_core_s0ix_blocker_fops); 1234 1202 1235 1203 debugfs_create_file("package_cstate_show", 0444, dir, primary_pmc, 1236 1204 &pmc_core_pkgc_fops);
+9
drivers/platform/x86/intel/pmc/core.h
··· 22 22 23 23 #define PMC_BASE_ADDR_DEFAULT 0xFE000000 24 24 #define MAX_NUM_PMC 3 25 + #define S0IX_BLK_SIZE 4 25 26 26 27 /* Sunrise Point Power Management Controller PCI Device ID */ 27 28 #define SPT_PMC_PCI_DEVICE_ID 0x9d21 ··· 283 282 #define LNL_PMC_LTR_OSSE 0x1B88 284 283 #define LNL_NUM_IP_IGN_ALLOWED 27 285 284 #define LNL_PPFEAR_NUM_ENTRIES 12 285 + #define LNL_S0IX_BLOCKER_OFFSET 0x2004 286 286 287 287 extern const char *pmc_lpm_modes[]; 288 288 289 289 struct pmc_bit_map { 290 290 const char *name; 291 291 u32 bit_mask; 292 + u8 blk; 292 293 }; 293 294 294 295 /** ··· 301 298 * @pll_sts: Maps name of PLL to corresponding bit status 302 299 * @slps0_dbg_maps: Array of SLP_S0_DBG* registers containing debug info 303 300 * @ltr_show_sts: Maps PCH IP Names to their MMIO register offsets 301 + * @s0ix_blocker_maps: Maps name of IP block to S0ix blocker counter 304 302 * @slp_s0_offset: PWRMBASE offset to read SLP_S0 residency 305 303 * @ltr_ignore_offset: PWRMBASE offset to read/write LTR ignore bit 306 304 * @regmap_length: Length of memory to map from PWRMBASE address to access ··· 311 307 * @pm_cfg_offset: PWRMBASE offset to PM_CFG register 312 308 * @pm_read_disable_bit: Bit index to read PMC_READ_DISABLE 313 309 * @slps0_dbg_offset: PWRMBASE offset to SLP_S0_DEBUG_REG* 310 + * @s0ix_blocker_offset PWRMBASE offset to S0ix blocker counter 314 311 * 315 312 * Each PCH has unique set of register offsets and bit indexes. This structure 316 313 * captures them to have a common implementation. ··· 324 319 const struct pmc_bit_map *ltr_show_sts; 325 320 const struct pmc_bit_map *msr_sts; 326 321 const struct pmc_bit_map **lpm_sts; 322 + const struct pmc_bit_map **s0ix_blocker_maps; 327 323 const u32 slp_s0_offset; 328 324 const int slp_s0_res_counter_step; 329 325 const u32 ltr_ignore_offset; ··· 336 330 const u32 slps0_dbg_offset; 337 331 const u32 ltr_ignore_max; 338 332 const u32 pm_vric1_offset; 333 + const u32 s0ix_blocker_offset; 339 334 /* Low Power Mode registers */ 340 335 const int lpm_num_maps; 341 336 const int lpm_num_modes; ··· 542 535 extern const struct pmc_bit_map lnl_vnn_req_status_3_map[]; 543 536 extern const struct pmc_bit_map lnl_vnn_misc_status_map[]; 544 537 extern const struct pmc_bit_map *lnl_lpm_maps[]; 538 + extern const struct pmc_bit_map *lnl_blk_maps[]; 545 539 extern const struct pmc_bit_map lnl_pfear_map[]; 546 540 extern const struct pmc_bit_map *ext_lnl_pfear_map[]; 541 + extern const struct pmc_bit_map lnl_signal_status_map[]; 547 542 548 543 /* ARL */ 549 544 extern const struct pmc_bit_map arl_socs_ltr_show_map[];
+265 -212
drivers/platform/x86/intel/pmc/lnl.c
··· 1 1 // SPDX-License-Identifier: GPL-2.0 2 2 /* 3 3 * This file contains platform specific structure definitions 4 - * and init function used by Meteor Lake PCH. 4 + * and init function used by Lunar Lake PCH. 5 5 * 6 6 * Copyright (c) 2022, Intel Corporation. 7 7 * All Rights Reserved. ··· 56 56 }; 57 57 58 58 const struct pmc_bit_map lnl_power_gating_status_0_map[] = { 59 - {"PMC_PGD0_PG_STS", BIT(0)}, 60 - {"FUSE_OSSE_PGD0_PG_STS", BIT(1)}, 61 - {"ESPISPI_PGD0_PG_STS", BIT(2)}, 62 - {"XHCI_PGD0_PG_STS", BIT(3)}, 63 - {"SPA_PGD0_PG_STS", BIT(4)}, 64 - {"SPB_PGD0_PG_STS", BIT(5)}, 65 - {"SPR16B0_PGD0_PG_STS", BIT(6)}, 66 - {"GBE_PGD0_PG_STS", BIT(7)}, 67 - {"SBR8B7_PGD0_PG_STS", BIT(8)}, 68 - {"SBR8B6_PGD0_PG_STS", BIT(9)}, 69 - {"SBR16B1_PGD0_PG_STS", BIT(10)}, 70 - {"SBR8B8_PGD0_PG_STS", BIT(11)}, 71 - {"ESE_PGD3_PG_STS", BIT(12)}, 72 - {"D2D_DISP_PGD0_PG_STS", BIT(13)}, 73 - {"LPSS_PGD0_PG_STS", BIT(14)}, 74 - {"LPC_PGD0_PG_STS", BIT(15)}, 75 - {"SMB_PGD0_PG_STS", BIT(16)}, 76 - {"ISH_PGD0_PG_STS", BIT(17)}, 77 - {"SBR8B2_PGD0_PG_STS", BIT(18)}, 78 - {"NPK_PGD0_PG_STS", BIT(19)}, 79 - {"D2D_NOC_PGD0_PG_STS", BIT(20)}, 80 - {"SAFSS_PGD0_PG_STS", BIT(21)}, 81 - {"FUSE_PGD0_PG_STS", BIT(22)}, 82 - {"D2D_DISP_PGD1_PG_STS", BIT(23)}, 83 - {"MPFPW1_PGD0_PG_STS", BIT(24)}, 84 - {"XDCI_PGD0_PG_STS", BIT(25)}, 85 - {"EXI_PGD0_PG_STS", BIT(26)}, 86 - {"CSE_PGD0_PG_STS", BIT(27)}, 87 - {"KVMCC_PGD0_PG_STS", BIT(28)}, 88 - {"PMT_PGD0_PG_STS", BIT(29)}, 89 - {"CLINK_PGD0_PG_STS", BIT(30)}, 90 - {"PTIO_PGD0_PG_STS", BIT(31)}, 59 + {"PMC_PGD0_PG_STS", BIT(0), 0}, 60 + {"FUSE_OSSE_PGD0_PG_STS", BIT(1), 0}, 61 + {"ESPISPI_PGD0_PG_STS", BIT(2), 0}, 62 + {"XHCI_PGD0_PG_STS", BIT(3), 1}, 63 + {"SPA_PGD0_PG_STS", BIT(4), 1}, 64 + {"SPB_PGD0_PG_STS", BIT(5), 1}, 65 + {"SPR16B0_PGD0_PG_STS", BIT(6), 0}, 66 + {"GBE_PGD0_PG_STS", BIT(7), 1}, 67 + {"SBR8B7_PGD0_PG_STS", BIT(8), 0}, 68 + {"SBR8B6_PGD0_PG_STS", BIT(9), 0}, 69 + {"SBR16B1_PGD0_PG_STS", BIT(10), 0}, 70 + {"SBR8B8_PGD0_PG_STS", BIT(11), 0}, 71 + {"ESE_PGD3_PG_STS", BIT(12), 1}, 72 + {"D2D_DISP_PGD0_PG_STS", BIT(13), 1}, 73 + {"LPSS_PGD0_PG_STS", BIT(14), 1}, 74 + {"LPC_PGD0_PG_STS", BIT(15), 0}, 75 + {"SMB_PGD0_PG_STS", BIT(16), 0}, 76 + {"ISH_PGD0_PG_STS", BIT(17), 0}, 77 + {"SBR8B2_PGD0_PG_STS", BIT(18), 0}, 78 + {"NPK_PGD0_PG_STS", BIT(19), 0}, 79 + {"D2D_NOC_PGD0_PG_STS", BIT(20), 0}, 80 + {"SAFSS_PGD0_PG_STS", BIT(21), 0}, 81 + {"FUSE_PGD0_PG_STS", BIT(22), 0}, 82 + {"D2D_DISP_PGD1_PG_STS", BIT(23), 1}, 83 + {"MPFPW1_PGD0_PG_STS", BIT(24), 0}, 84 + {"XDCI_PGD0_PG_STS", BIT(25), 1}, 85 + {"EXI_PGD0_PG_STS", BIT(26), 0}, 86 + {"CSE_PGD0_PG_STS", BIT(27), 1}, 87 + {"KVMCC_PGD0_PG_STS", BIT(28), 1}, 88 + {"PMT_PGD0_PG_STS", BIT(29), 1}, 89 + {"CLINK_PGD0_PG_STS", BIT(30), 1}, 90 + {"PTIO_PGD0_PG_STS", BIT(31), 1}, 91 91 {} 92 92 }; 93 93 94 94 const struct pmc_bit_map lnl_power_gating_status_1_map[] = { 95 - {"USBR0_PGD0_PG_STS", BIT(0)}, 96 - {"SUSRAM_PGD0_PG_STS", BIT(1)}, 97 - {"SMT1_PGD0_PG_STS", BIT(2)}, 98 - {"U3FPW1_PGD0_PG_STS", BIT(3)}, 99 - {"SMS2_PGD0_PG_STS", BIT(4)}, 100 - {"SMS1_PGD0_PG_STS", BIT(5)}, 101 - {"CSMERTC_PGD0_PG_STS", BIT(6)}, 102 - {"CSMEPSF_PGD0_PG_STS", BIT(7)}, 103 - {"FIA_PG_PGD0_PG_STS", BIT(8)}, 104 - {"SBR16B4_PGD0_PG_STS", BIT(9)}, 105 - {"P2SB8B_PGD0_PG_STS", BIT(10)}, 106 - {"DBG_SBR_PGD0_PG_STS", BIT(11)}, 107 - {"SBR8B9_PGD0_PG_STS", BIT(12)}, 108 - {"OSSE_SMT1_PGD0_PG_STS", BIT(13)}, 109 - {"SBR8B10_PGD0_PG_STS", BIT(14)}, 110 - {"SBR16B3_PGD0_PG_STS", BIT(15)}, 111 - {"G5FPW1_PGD0_PG_STS", BIT(16)}, 112 - {"SBRG_PGD0_PG_STS", BIT(17)}, 113 - {"PSF4_PGD0_PG_STS", BIT(18)}, 114 - {"CNVI_PGD0_PG_STS", BIT(19)}, 115 - {"USFX2_PGD0_PG_STS", BIT(20)}, 116 - {"ENDBG_PGD0_PG_STS", BIT(21)}, 117 - {"FIACPCB_P5X4_PGD0_PG_STS", BIT(22)}, 118 - {"SBR8B3_PGD0_PG_STS", BIT(23)}, 119 - {"SBR8B0_PGD0_PG_STS", BIT(24)}, 120 - {"NPK_PGD1_PG_STS", BIT(25)}, 121 - {"OSSE_HOTHAM_PGD0_PG_STS", BIT(26)}, 122 - {"D2D_NOC_PGD2_PG_STS", BIT(27)}, 123 - {"SBR8B1_PGD0_PG_STS", BIT(28)}, 124 - {"PSF6_PGD0_PG_STS", BIT(29)}, 125 - {"PSF7_PGD0_PG_STS", BIT(30)}, 126 - {"FIA_U_PGD0_PG_STS", BIT(31)}, 95 + {"USBR0_PGD0_PG_STS", BIT(0), 1}, 96 + {"SUSRAM_PGD0_PG_STS", BIT(1), 1}, 97 + {"SMT1_PGD0_PG_STS", BIT(2), 1}, 98 + {"U3FPW1_PGD0_PG_STS", BIT(3), 0}, 99 + {"SMS2_PGD0_PG_STS", BIT(4), 1}, 100 + {"SMS1_PGD0_PG_STS", BIT(5), 1}, 101 + {"CSMERTC_PGD0_PG_STS", BIT(6), 0}, 102 + {"CSMEPSF_PGD0_PG_STS", BIT(7), 0}, 103 + {"FIA_PG_PGD0_PG_STS", BIT(8), 0}, 104 + {"SBR16B4_PGD0_PG_STS", BIT(9), 0}, 105 + {"P2SB8B_PGD0_PG_STS", BIT(10), 1}, 106 + {"DBG_SBR_PGD0_PG_STS", BIT(11), 0}, 107 + {"SBR8B9_PGD0_PG_STS", BIT(12), 0}, 108 + {"OSSE_SMT1_PGD0_PG_STS", BIT(13), 1}, 109 + {"SBR8B10_PGD0_PG_STS", BIT(14), 0}, 110 + {"SBR16B3_PGD0_PG_STS", BIT(15), 0}, 111 + {"G5FPW1_PGD0_PG_STS", BIT(16), 0}, 112 + {"SBRG_PGD0_PG_STS", BIT(17), 0}, 113 + {"PSF4_PGD0_PG_STS", BIT(18), 0}, 114 + {"CNVI_PGD0_PG_STS", BIT(19), 0}, 115 + {"USFX2_PGD0_PG_STS", BIT(20), 1}, 116 + {"ENDBG_PGD0_PG_STS", BIT(21), 0}, 117 + {"FIACPCB_P5X4_PGD0_PG_STS", BIT(22), 0}, 118 + {"SBR8B3_PGD0_PG_STS", BIT(23), 0}, 119 + {"SBR8B0_PGD0_PG_STS", BIT(24), 0}, 120 + {"NPK_PGD1_PG_STS", BIT(25), 0}, 121 + {"OSSE_HOTHAM_PGD0_PG_STS", BIT(26), 1}, 122 + {"D2D_NOC_PGD2_PG_STS", BIT(27), 1}, 123 + {"SBR8B1_PGD0_PG_STS", BIT(28), 0}, 124 + {"PSF6_PGD0_PG_STS", BIT(29), 0}, 125 + {"PSF7_PGD0_PG_STS", BIT(30), 0}, 126 + {"FIA_U_PGD0_PG_STS", BIT(31), 0}, 127 127 {} 128 128 }; 129 129 130 130 const struct pmc_bit_map lnl_power_gating_status_2_map[] = { 131 - {"PSF8_PGD0_PG_STS", BIT(0)}, 132 - {"SBR16B2_PGD0_PG_STS", BIT(1)}, 133 - {"D2D_IPU_PGD0_PG_STS", BIT(2)}, 134 - {"FIACPCB_U_PGD0_PG_STS", BIT(3)}, 135 - {"TAM_PGD0_PG_STS", BIT(4)}, 136 - {"D2D_NOC_PGD1_PG_STS", BIT(5)}, 137 - {"TBTLSX_PGD0_PG_STS", BIT(6)}, 138 - {"THC0_PGD0_PG_STS", BIT(7)}, 139 - {"THC1_PGD0_PG_STS", BIT(8)}, 140 - {"PMC_PGD0_PG_STS", BIT(9)}, 141 - {"SBR8B5_PGD0_PG_STS", BIT(10)}, 142 - {"UFSPW1_PGD0_PG_STS", BIT(11)}, 143 - {"DBC_PGD0_PG_STS", BIT(12)}, 144 - {"TCSS_PGD0_PG_STS", BIT(13)}, 145 - {"FIA_P5X4_PGD0_PG_STS", BIT(14)}, 146 - {"DISP_PGA_PGD0_PG_STS", BIT(15)}, 147 - {"DISP_PSF_PGD0_PG_STS", BIT(16)}, 148 - {"PSF0_PGD0_PG_STS", BIT(17)}, 149 - {"P2SB16B_PGD0_PG_STS", BIT(18)}, 150 - {"ACE_PGD0_PG_STS", BIT(19)}, 151 - {"ACE_PGD1_PG_STS", BIT(20)}, 152 - {"ACE_PGD2_PG_STS", BIT(21)}, 153 - {"ACE_PGD3_PG_STS", BIT(22)}, 154 - {"ACE_PGD4_PG_STS", BIT(23)}, 155 - {"ACE_PGD5_PG_STS", BIT(24)}, 156 - {"ACE_PGD6_PG_STS", BIT(25)}, 157 - {"ACE_PGD7_PG_STS", BIT(26)}, 158 - {"ACE_PGD8_PG_STS", BIT(27)}, 159 - {"ACE_PGD9_PG_STS", BIT(28)}, 160 - {"ACE_PGD10_PG_STS", BIT(29)}, 161 - {"FIACPCB_PG_PGD0_PG_STS", BIT(30)}, 162 - {"OSSE_PGD0_PG_STS", BIT(31)}, 131 + {"PSF8_PGD0_PG_STS", BIT(0), 0}, 132 + {"SBR16B2_PGD0_PG_STS", BIT(1), 0}, 133 + {"D2D_IPU_PGD0_PG_STS", BIT(2), 1}, 134 + {"FIACPCB_U_PGD0_PG_STS", BIT(3), 0}, 135 + {"TAM_PGD0_PG_STS", BIT(4), 1}, 136 + {"D2D_NOC_PGD1_PG_STS", BIT(5), 1}, 137 + {"TBTLSX_PGD0_PG_STS", BIT(6), 1}, 138 + {"THC0_PGD0_PG_STS", BIT(7), 1}, 139 + {"THC1_PGD0_PG_STS", BIT(8), 1}, 140 + {"PMC_PGD0_PG_STS", BIT(9), 0}, 141 + {"SBR8B5_PGD0_PG_STS", BIT(10), 0}, 142 + {"UFSPW1_PGD0_PG_STS", BIT(11), 0}, 143 + {"DBC_PGD0_PG_STS", BIT(12), 0}, 144 + {"TCSS_PGD0_PG_STS", BIT(13), 0}, 145 + {"FIA_P5X4_PGD0_PG_STS", BIT(14), 0}, 146 + {"DISP_PGA_PGD0_PG_STS", BIT(15), 0}, 147 + {"DISP_PSF_PGD0_PG_STS", BIT(16), 0}, 148 + {"PSF0_PGD0_PG_STS", BIT(17), 0}, 149 + {"P2SB16B_PGD0_PG_STS", BIT(18), 1}, 150 + {"ACE_PGD0_PG_STS", BIT(19), 0}, 151 + {"ACE_PGD1_PG_STS", BIT(20), 0}, 152 + {"ACE_PGD2_PG_STS", BIT(21), 0}, 153 + {"ACE_PGD3_PG_STS", BIT(22), 0}, 154 + {"ACE_PGD4_PG_STS", BIT(23), 0}, 155 + {"ACE_PGD5_PG_STS", BIT(24), 0}, 156 + {"ACE_PGD6_PG_STS", BIT(25), 0}, 157 + {"ACE_PGD7_PG_STS", BIT(26), 0}, 158 + {"ACE_PGD8_PG_STS", BIT(27), 0}, 159 + {"ACE_PGD9_PG_STS", BIT(28), 0}, 160 + {"ACE_PGD10_PG_STS", BIT(29), 0}, 161 + {"FIACPCB_PG_PGD0_PG_STS", BIT(30), 0}, 162 + {"OSSE_PGD0_PG_STS", BIT(31), 1}, 163 163 {} 164 164 }; 165 165 166 166 const struct pmc_bit_map lnl_d3_status_0_map[] = { 167 - {"LPSS_D3_STS", BIT(3)}, 168 - {"XDCI_D3_STS", BIT(4)}, 169 - {"XHCI_D3_STS", BIT(5)}, 170 - {"SPA_D3_STS", BIT(12)}, 171 - {"SPB_D3_STS", BIT(13)}, 172 - {"OSSE_D3_STS", BIT(15)}, 173 - {"ESPISPI_D3_STS", BIT(18)}, 174 - {"PSTH_D3_STS", BIT(21)}, 167 + {"LPSS_D3_STS", BIT(3), 1}, 168 + {"XDCI_D3_STS", BIT(4), 1}, 169 + {"XHCI_D3_STS", BIT(5), 1}, 170 + {"SPA_D3_STS", BIT(12), 0}, 171 + {"SPB_D3_STS", BIT(13), 0}, 172 + {"OSSE_D3_STS", BIT(15), 0}, 173 + {"ESPISPI_D3_STS", BIT(18), 0}, 174 + {"PSTH_D3_STS", BIT(21), 0}, 175 175 {} 176 176 }; 177 177 178 178 const struct pmc_bit_map lnl_d3_status_1_map[] = { 179 - {"OSSE_SMT1_D3_STS", BIT(7)}, 180 - {"GBE_D3_STS", BIT(19)}, 181 - {"ITSS_D3_STS", BIT(23)}, 182 - {"CNVI_D3_STS", BIT(27)}, 183 - {"UFSX2_D3_STS", BIT(28)}, 184 - {"OSSE_HOTHAM_D3_STS", BIT(31)}, 179 + {"OSSE_SMT1_D3_STS", BIT(7), 0}, 180 + {"GBE_D3_STS", BIT(19), 0}, 181 + {"ITSS_D3_STS", BIT(23), 0}, 182 + {"CNVI_D3_STS", BIT(27), 0}, 183 + {"UFSX2_D3_STS", BIT(28), 1}, 184 + {"OSSE_HOTHAM_D3_STS", BIT(31), 0}, 185 185 {} 186 186 }; 187 187 188 188 const struct pmc_bit_map lnl_d3_status_2_map[] = { 189 - {"ESE_D3_STS", BIT(0)}, 190 - {"CSMERTC_D3_STS", BIT(1)}, 191 - {"SUSRAM_D3_STS", BIT(2)}, 192 - {"CSE_D3_STS", BIT(4)}, 193 - {"KVMCC_D3_STS", BIT(5)}, 194 - {"USBR0_D3_STS", BIT(6)}, 195 - {"ISH_D3_STS", BIT(7)}, 196 - {"SMT1_D3_STS", BIT(8)}, 197 - {"SMT2_D3_STS", BIT(9)}, 198 - {"SMT3_D3_STS", BIT(10)}, 199 - {"OSSE_SMT2_D3_STS", BIT(13)}, 200 - {"CLINK_D3_STS", BIT(14)}, 201 - {"PTIO_D3_STS", BIT(16)}, 202 - {"PMT_D3_STS", BIT(17)}, 203 - {"SMS1_D3_STS", BIT(18)}, 204 - {"SMS2_D3_STS", BIT(19)}, 189 + {"ESE_D3_STS", BIT(0), 0}, 190 + {"CSMERTC_D3_STS", BIT(1), 0}, 191 + {"SUSRAM_D3_STS", BIT(2), 0}, 192 + {"CSE_D3_STS", BIT(4), 0}, 193 + {"KVMCC_D3_STS", BIT(5), 0}, 194 + {"USBR0_D3_STS", BIT(6), 0}, 195 + {"ISH_D3_STS", BIT(7), 0}, 196 + {"SMT1_D3_STS", BIT(8), 0}, 197 + {"SMT2_D3_STS", BIT(9), 0}, 198 + {"SMT3_D3_STS", BIT(10), 0}, 199 + {"OSSE_SMT2_D3_STS", BIT(13), 0}, 200 + {"CLINK_D3_STS", BIT(14), 0}, 201 + {"PTIO_D3_STS", BIT(16), 0}, 202 + {"PMT_D3_STS", BIT(17), 0}, 203 + {"SMS1_D3_STS", BIT(18), 0}, 204 + {"SMS2_D3_STS", BIT(19), 0}, 205 205 {} 206 206 }; 207 207 208 208 const struct pmc_bit_map lnl_d3_status_3_map[] = { 209 - {"THC0_D3_STS", BIT(14)}, 210 - {"THC1_D3_STS", BIT(15)}, 211 - {"OSSE_SMT3_D3_STS", BIT(21)}, 212 - {"ACE_D3_STS", BIT(23)}, 209 + {"THC0_D3_STS", BIT(14), 1}, 210 + {"THC1_D3_STS", BIT(15), 1}, 211 + {"OSSE_SMT3_D3_STS", BIT(21), 0}, 212 + {"ACE_D3_STS", BIT(23), 0}, 213 213 {} 214 214 }; 215 215 216 216 const struct pmc_bit_map lnl_vnn_req_status_0_map[] = { 217 - {"LPSS_VNN_REQ_STS", BIT(3)}, 218 - {"OSSE_VNN_REQ_STS", BIT(15)}, 219 - {"ESPISPI_VNN_REQ_STS", BIT(18)}, 217 + {"LPSS_VNN_REQ_STS", BIT(3), 1}, 218 + {"OSSE_VNN_REQ_STS", BIT(15), 1}, 219 + {"ESPISPI_VNN_REQ_STS", BIT(18), 1}, 220 220 {} 221 221 }; 222 222 223 223 const struct pmc_bit_map lnl_vnn_req_status_1_map[] = { 224 - {"NPK_VNN_REQ_STS", BIT(4)}, 225 - {"OSSE_SMT1_VNN_REQ_STS", BIT(7)}, 226 - {"DFXAGG_VNN_REQ_STS", BIT(8)}, 227 - {"EXI_VNN_REQ_STS", BIT(9)}, 228 - {"P2D_VNN_REQ_STS", BIT(18)}, 229 - {"GBE_VNN_REQ_STS", BIT(19)}, 230 - {"SMB_VNN_REQ_STS", BIT(25)}, 231 - {"LPC_VNN_REQ_STS", BIT(26)}, 224 + {"NPK_VNN_REQ_STS", BIT(4), 1}, 225 + {"OSSE_SMT1_VNN_REQ_STS", BIT(7), 1}, 226 + {"DFXAGG_VNN_REQ_STS", BIT(8), 0}, 227 + {"EXI_VNN_REQ_STS", BIT(9), 1}, 228 + {"P2D_VNN_REQ_STS", BIT(18), 1}, 229 + {"GBE_VNN_REQ_STS", BIT(19), 1}, 230 + {"SMB_VNN_REQ_STS", BIT(25), 1}, 231 + {"LPC_VNN_REQ_STS", BIT(26), 0}, 232 232 {} 233 233 }; 234 234 235 235 const struct pmc_bit_map lnl_vnn_req_status_2_map[] = { 236 - {"eSE_VNN_REQ_STS", BIT(0)}, 237 - {"CSMERTC_VNN_REQ_STS", BIT(1)}, 238 - {"CSE_VNN_REQ_STS", BIT(4)}, 239 - {"ISH_VNN_REQ_STS", BIT(7)}, 240 - {"SMT1_VNN_REQ_STS", BIT(8)}, 241 - {"CLINK_VNN_REQ_STS", BIT(14)}, 242 - {"SMS1_VNN_REQ_STS", BIT(18)}, 243 - {"SMS2_VNN_REQ_STS", BIT(19)}, 244 - {"GPIOCOM4_VNN_REQ_STS", BIT(20)}, 245 - {"GPIOCOM3_VNN_REQ_STS", BIT(21)}, 246 - {"GPIOCOM2_VNN_REQ_STS", BIT(22)}, 247 - {"GPIOCOM1_VNN_REQ_STS", BIT(23)}, 248 - {"GPIOCOM0_VNN_REQ_STS", BIT(24)}, 236 + {"eSE_VNN_REQ_STS", BIT(0), 1}, 237 + {"CSMERTC_VNN_REQ_STS", BIT(1), 1}, 238 + {"CSE_VNN_REQ_STS", BIT(4), 1}, 239 + {"ISH_VNN_REQ_STS", BIT(7), 1}, 240 + {"SMT1_VNN_REQ_STS", BIT(8), 1}, 241 + {"CLINK_VNN_REQ_STS", BIT(14), 1}, 242 + {"SMS1_VNN_REQ_STS", BIT(18), 1}, 243 + {"SMS2_VNN_REQ_STS", BIT(19), 1}, 244 + {"GPIOCOM4_VNN_REQ_STS", BIT(20), 1}, 245 + {"GPIOCOM3_VNN_REQ_STS", BIT(21), 1}, 246 + {"GPIOCOM2_VNN_REQ_STS", BIT(22), 0}, 247 + {"GPIOCOM1_VNN_REQ_STS", BIT(23), 1}, 248 + {"GPIOCOM0_VNN_REQ_STS", BIT(24), 1}, 249 249 {} 250 250 }; 251 251 252 252 const struct pmc_bit_map lnl_vnn_req_status_3_map[] = { 253 - {"DISP_SHIM_VNN_REQ_STS", BIT(2)}, 254 - {"DTS0_VNN_REQ_STS", BIT(7)}, 255 - {"GPIOCOM5_VNN_REQ_STS", BIT(11)}, 253 + {"DISP_SHIM_VNN_REQ_STS", BIT(2), 0}, 254 + {"DTS0_VNN_REQ_STS", BIT(7), 0}, 255 + {"GPIOCOM5_VNN_REQ_STS", BIT(11), 2}, 256 256 {} 257 257 }; 258 258 259 259 const struct pmc_bit_map lnl_vnn_misc_status_map[] = { 260 - {"CPU_C10_REQ_STS", BIT(0)}, 261 - {"TS_OFF_REQ_STS", BIT(1)}, 262 - {"PNDE_MET_REQ_STS", BIT(2)}, 263 - {"PCIE_DEEP_PM_REQ_STS", BIT(3)}, 264 - {"PMC_CLK_THROTTLE_EN_REQ_STS", BIT(4)}, 265 - {"NPK_VNNAON_REQ_STS", BIT(5)}, 266 - {"VNN_SOC_REQ_STS", BIT(6)}, 267 - {"ISH_VNNAON_REQ_STS", BIT(7)}, 268 - {"D2D_NOC_CFI_QACTIVE_REQ_STS", BIT(8)}, 269 - {"D2D_NOC_GPSB_QACTIVE_REQ_STS", BIT(9)}, 270 - {"D2D_NOC_IPU_QACTIVE_REQ_STS", BIT(10)}, 271 - {"PLT_GREATER_REQ_STS", BIT(11)}, 272 - {"PCIE_CLKREQ_REQ_STS", BIT(12)}, 273 - {"PMC_IDLE_FB_OCP_REQ_STS", BIT(13)}, 274 - {"PM_SYNC_STATES_REQ_STS", BIT(14)}, 275 - {"EA_REQ_STS", BIT(15)}, 276 - {"MPHY_CORE_OFF_REQ_STS", BIT(16)}, 277 - {"BRK_EV_EN_REQ_STS", BIT(17)}, 278 - {"AUTO_DEMO_EN_REQ_STS", BIT(18)}, 279 - {"ITSS_CLK_SRC_REQ_STS", BIT(19)}, 280 - {"LPC_CLK_SRC_REQ_STS", BIT(20)}, 281 - {"ARC_IDLE_REQ_STS", BIT(21)}, 282 - {"MPHY_SUS_REQ_STS", BIT(22)}, 283 - {"FIA_DEEP_PM_REQ_STS", BIT(23)}, 284 - {"UXD_CONNECTED_REQ_STS", BIT(24)}, 285 - {"ARC_INTERRUPT_WAKE_REQ_STS", BIT(25)}, 286 - {"D2D_NOC_DISP_DDI_QACTIVE_REQ_STS", BIT(26)}, 287 - {"PRE_WAKE0_REQ_STS", BIT(27)}, 288 - {"PRE_WAKE1_REQ_STS", BIT(28)}, 289 - {"PRE_WAKE2_EN_REQ_STS", BIT(29)}, 290 - {"WOV_REQ_STS", BIT(30)}, 291 - {"D2D_NOC_DISP_EDP_QACTIVE_REQ_STS_31", BIT(31)}, 260 + {"CPU_C10_REQ_STS", BIT(0), 0}, 261 + {"TS_OFF_REQ_STS", BIT(1), 0}, 262 + {"PNDE_MET_REQ_STS", BIT(2), 1}, 263 + {"PCIE_DEEP_PM_REQ_STS", BIT(3), 0}, 264 + {"PMC_CLK_THROTTLE_EN_REQ_STS", BIT(4), 0}, 265 + {"NPK_VNNAON_REQ_STS", BIT(5), 0}, 266 + {"VNN_SOC_REQ_STS", BIT(6), 1}, 267 + {"ISH_VNNAON_REQ_STS", BIT(7), 0}, 268 + {"D2D_NOC_CFI_QACTIVE_REQ_STS", BIT(8), 1}, 269 + {"D2D_NOC_GPSB_QACTIVE_REQ_STS", BIT(9), 1}, 270 + {"D2D_NOC_IPU_QACTIVE_REQ_STS", BIT(10), 1}, 271 + {"PLT_GREATER_REQ_STS", BIT(11), 1}, 272 + {"PCIE_CLKREQ_REQ_STS", BIT(12), 0}, 273 + {"PMC_IDLE_FB_OCP_REQ_STS", BIT(13), 0}, 274 + {"PM_SYNC_STATES_REQ_STS", BIT(14), 0}, 275 + {"EA_REQ_STS", BIT(15), 0}, 276 + {"MPHY_CORE_OFF_REQ_STS", BIT(16), 0}, 277 + {"BRK_EV_EN_REQ_STS", BIT(17), 0}, 278 + {"AUTO_DEMO_EN_REQ_STS", BIT(18), 0}, 279 + {"ITSS_CLK_SRC_REQ_STS", BIT(19), 1}, 280 + {"LPC_CLK_SRC_REQ_STS", BIT(20), 0}, 281 + {"ARC_IDLE_REQ_STS", BIT(21), 0}, 282 + {"MPHY_SUS_REQ_STS", BIT(22), 0}, 283 + {"FIA_DEEP_PM_REQ_STS", BIT(23), 0}, 284 + {"UXD_CONNECTED_REQ_STS", BIT(24), 1}, 285 + {"ARC_INTERRUPT_WAKE_REQ_STS", BIT(25), 0}, 286 + {"D2D_NOC_DISP_DDI_QACTIVE_REQ_STS", BIT(26), 1}, 287 + {"PRE_WAKE0_REQ_STS", BIT(27), 1}, 288 + {"PRE_WAKE1_REQ_STS", BIT(28), 1}, 289 + {"PRE_WAKE2_EN_REQ_STS", BIT(29), 1}, 290 + {"WOV_REQ_STS", BIT(30), 0}, 291 + {"D2D_NOC_DISP_EDP_QACTIVE_REQ_STS_31", BIT(31), 1}, 292 292 {} 293 293 }; 294 294 295 295 const struct pmc_bit_map lnl_clocksource_status_map[] = { 296 - {"AON2_OFF_STS", BIT(0)}, 297 - {"AON3_OFF_STS", BIT(1)}, 298 - {"AON4_OFF_STS", BIT(2)}, 299 - {"AON5_OFF_STS", BIT(3)}, 300 - {"AON1_OFF_STS", BIT(4)}, 301 - {"MPFPW1_0_PLL_OFF_STS", BIT(6)}, 302 - {"USB3_PLL_OFF_STS", BIT(8)}, 303 - {"AON3_SPL_OFF_STS", BIT(9)}, 304 - {"G5FPW1_PLL_OFF_STS", BIT(15)}, 305 - {"XTAL_AGGR_OFF_STS", BIT(17)}, 306 - {"USB2_PLL_OFF_STS", BIT(18)}, 307 - {"SAF_PLL_OFF_STS", BIT(19)}, 308 - {"SE_TCSS_PLL_OFF_STS", BIT(20)}, 309 - {"DDI_PLL_OFF_STS", BIT(21)}, 310 - {"FILTER_PLL_OFF_STS", BIT(22)}, 311 - {"ACE_PLL_OFF_STS", BIT(24)}, 312 - {"FABRIC_PLL_OFF_STS", BIT(25)}, 313 - {"SOC_PLL_OFF_STS", BIT(26)}, 314 - {"REF_OFF_STS", BIT(28)}, 315 - {"IMG_OFF_STS", BIT(29)}, 316 - {"RTC_PLL_OFF_STS", BIT(31)}, 296 + {"AON2_OFF_STS", BIT(0), 0}, 297 + {"AON3_OFF_STS", BIT(1), 1}, 298 + {"AON4_OFF_STS", BIT(2), 1}, 299 + {"AON5_OFF_STS", BIT(3), 1}, 300 + {"AON1_OFF_STS", BIT(4), 0}, 301 + {"MPFPW1_0_PLL_OFF_STS", BIT(6), 1}, 302 + {"USB3_PLL_OFF_STS", BIT(8), 1}, 303 + {"AON3_SPL_OFF_STS", BIT(9), 1}, 304 + {"G5FPW1_PLL_OFF_STS", BIT(15), 1}, 305 + {"XTAL_AGGR_OFF_STS", BIT(17), 1}, 306 + {"USB2_PLL_OFF_STS", BIT(18), 0}, 307 + {"SAF_PLL_OFF_STS", BIT(19), 1}, 308 + {"SE_TCSS_PLL_OFF_STS", BIT(20), 1}, 309 + {"DDI_PLL_OFF_STS", BIT(21), 1}, 310 + {"FILTER_PLL_OFF_STS", BIT(22), 1}, 311 + {"ACE_PLL_OFF_STS", BIT(24), 0}, 312 + {"FABRIC_PLL_OFF_STS", BIT(25), 1}, 313 + {"SOC_PLL_OFF_STS", BIT(26), 1}, 314 + {"REF_OFF_STS", BIT(28), 1}, 315 + {"IMG_OFF_STS", BIT(29), 1}, 316 + {"RTC_PLL_OFF_STS", BIT(31), 0}, 317 + {} 318 + }; 319 + 320 + const struct pmc_bit_map lnl_signal_status_map[] = { 321 + {"LSX_Wake0_STS", BIT(0), 0}, 322 + {"LSX_Wake1_STS", BIT(1), 0}, 323 + {"LSX_Wake2_STS", BIT(2), 0}, 324 + {"LSX_Wake3_STS", BIT(3), 0}, 325 + {"LSX_Wake4_STS", BIT(4), 0}, 326 + {"LSX_Wake5_STS", BIT(5), 0}, 327 + {"LSX_Wake6_STS", BIT(6), 0}, 328 + {"LSX_Wake7_STS", BIT(7), 0}, 329 + {"LPSS_Wake0_STS", BIT(8), 1}, 330 + {"LPSS_Wake1_STS", BIT(9), 1}, 331 + {"Int_Timer_SS_Wake0_STS", BIT(10), 1}, 332 + {"Int_Timer_SS_Wake1_STS", BIT(11), 1}, 333 + {"Int_Timer_SS_Wake2_STS", BIT(12), 1}, 334 + {"Int_Timer_SS_Wake3_STS", BIT(13), 1}, 335 + {"Int_Timer_SS_Wake4_STS", BIT(14), 1}, 336 + {"Int_Timer_SS_Wake5_STS", BIT(15), 1}, 337 + {} 338 + }; 339 + 340 + const struct pmc_bit_map lnl_rsc_status_map[] = { 341 + {"Memory", 0, 1}, 342 + {"PSF0", 0, 1}, 343 + {"PSF4", 0, 1}, 344 + {"PSF6", 0, 1}, 345 + {"PSF7", 0, 1}, 346 + {"PSF8", 0, 1}, 347 + {"SAF_CFI_LINK", 0, 1}, 348 + {"SBR", 0, 1}, 317 349 {} 318 350 }; 319 351 ··· 363 331 lnl_vnn_req_status_2_map, 364 332 lnl_vnn_req_status_3_map, 365 333 lnl_vnn_misc_status_map, 366 - mtl_socm_signal_status_map, 334 + lnl_signal_status_map, 335 + NULL 336 + }; 337 + 338 + const struct pmc_bit_map *lnl_blk_maps[] = { 339 + lnl_power_gating_status_0_map, 340 + lnl_power_gating_status_1_map, 341 + lnl_power_gating_status_2_map, 342 + lnl_rsc_status_map, 343 + lnl_vnn_req_status_0_map, 344 + lnl_vnn_req_status_1_map, 345 + lnl_vnn_req_status_2_map, 346 + lnl_vnn_req_status_3_map, 347 + lnl_d3_status_0_map, 348 + lnl_d3_status_1_map, 349 + lnl_d3_status_2_map, 350 + lnl_d3_status_3_map, 351 + lnl_clocksource_status_map, 352 + lnl_vnn_misc_status_map, 353 + lnl_signal_status_map, 367 354 NULL 368 355 }; 369 356 ··· 526 475 .lpm_sts = lnl_lpm_maps, 527 476 .lpm_status_offset = MTL_LPM_STATUS_OFFSET, 528 477 .lpm_live_status_offset = MTL_LPM_LIVE_STATUS_OFFSET, 478 + .s0ix_blocker_maps = lnl_blk_maps, 479 + .s0ix_blocker_offset = LNL_S0IX_BLOCKER_OFFSET, 529 480 }; 530 481 531 482 #define LNL_NPU_PCI_DEV 0x643e
+78 -40
drivers/platform/x86/intel/sdsi.c
··· 15 15 #include <linux/iopoll.h> 16 16 #include <linux/kernel.h> 17 17 #include <linux/module.h> 18 + #include <linux/overflow.h> 18 19 #include <linux/pci.h> 19 20 #include <linux/slab.h> 20 21 #include <linux/sysfs.h> ··· 67 66 #define CTRL_OWNER GENMASK(5, 4) 68 67 #define CTRL_COMPLETE BIT(6) 69 68 #define CTRL_READY BIT(7) 69 + #define CTRL_INBAND_LOCK BIT(32) 70 + #define CTRL_METER_ENABLE_DRAM BIT(33) 70 71 #define CTRL_STATUS GENMASK(15, 8) 71 72 #define CTRL_PACKET_SIZE GENMASK(31, 16) 72 73 #define CTRL_MSG_SIZE GENMASK(63, 48) ··· 96 93 struct sdsi_mbox_info { 97 94 u64 *payload; 98 95 void *buffer; 96 + u64 control_flags; 99 97 int size; 100 98 }; 101 99 ··· 160 156 } 161 157 } 162 158 163 - static int sdsi_mbox_cmd_read(struct sdsi_priv *priv, struct sdsi_mbox_info *info, 164 - size_t *data_size) 159 + static int sdsi_mbox_poll(struct sdsi_priv *priv, struct sdsi_mbox_info *info, 160 + size_t *data_size) 165 161 { 166 162 struct device *dev = priv->dev; 167 163 u32 total, loop, eom, status, message_size; ··· 170 166 171 167 lockdep_assert_held(&priv->mb_lock); 172 168 173 - /* Format and send the read command */ 174 - control = FIELD_PREP(CTRL_EOM, 1) | 175 - FIELD_PREP(CTRL_SOM, 1) | 176 - FIELD_PREP(CTRL_RUN_BUSY, 1) | 177 - FIELD_PREP(CTRL_PACKET_SIZE, info->size); 178 - writeq(control, priv->control_addr); 179 - 180 169 /* For reads, data sizes that are larger than the mailbox size are read in packets. */ 181 170 total = 0; 182 171 loop = 0; 183 172 do { 184 - void *buf = info->buffer + (SDSI_SIZE_MAILBOX * loop); 185 173 u32 packet_size; 186 174 187 175 /* Poll on ready bit */ ··· 191 195 if (ret) 192 196 break; 193 197 198 + if (!packet_size) { 199 + sdsi_complete_transaction(priv); 200 + break; 201 + } 202 + 194 203 /* Only the last packet can be less than the mailbox size. */ 195 204 if (!eom && packet_size != SDSI_SIZE_MAILBOX) { 196 205 dev_err(dev, "Invalid packet size\n"); ··· 209 208 break; 210 209 } 211 210 212 - sdsi_memcpy64_fromio(buf, priv->mbox_addr, round_up(packet_size, SDSI_SIZE_CMD)); 211 + if (info->buffer) { 212 + void *buf = info->buffer + array_size(SDSI_SIZE_MAILBOX, loop); 213 213 214 - total += packet_size; 214 + sdsi_memcpy64_fromio(buf, priv->mbox_addr, 215 + round_up(packet_size, SDSI_SIZE_CMD)); 216 + total += packet_size; 217 + } 215 218 216 219 sdsi_complete_transaction(priv); 217 220 } while (!eom && ++loop < MBOX_MAX_PACKETS); ··· 235 230 dev_warn(dev, "Read count %u differs from expected count %u\n", 236 231 total, message_size); 237 232 238 - *data_size = total; 233 + if (data_size) 234 + *data_size = total; 239 235 240 236 return 0; 241 237 } 242 238 243 - static int sdsi_mbox_cmd_write(struct sdsi_priv *priv, struct sdsi_mbox_info *info) 239 + static int sdsi_mbox_cmd_read(struct sdsi_priv *priv, struct sdsi_mbox_info *info, 240 + size_t *data_size) 244 241 { 245 242 u64 control; 246 - u32 status; 247 - int ret; 243 + 244 + lockdep_assert_held(&priv->mb_lock); 245 + 246 + /* Format and send the read command */ 247 + control = FIELD_PREP(CTRL_EOM, 1) | 248 + FIELD_PREP(CTRL_SOM, 1) | 249 + FIELD_PREP(CTRL_RUN_BUSY, 1) | 250 + FIELD_PREP(CTRL_PACKET_SIZE, info->size) | 251 + info->control_flags; 252 + writeq(control, priv->control_addr); 253 + 254 + return sdsi_mbox_poll(priv, info, data_size); 255 + } 256 + 257 + static int sdsi_mbox_cmd_write(struct sdsi_priv *priv, struct sdsi_mbox_info *info, 258 + size_t *data_size) 259 + { 260 + u64 control; 248 261 249 262 lockdep_assert_held(&priv->mb_lock); 250 263 ··· 275 252 FIELD_PREP(CTRL_SOM, 1) | 276 253 FIELD_PREP(CTRL_RUN_BUSY, 1) | 277 254 FIELD_PREP(CTRL_READ_WRITE, 1) | 255 + FIELD_PREP(CTRL_MSG_SIZE, info->size) | 278 256 FIELD_PREP(CTRL_PACKET_SIZE, info->size); 279 257 writeq(control, priv->control_addr); 280 258 281 - /* Poll on ready bit */ 282 - ret = readq_poll_timeout(priv->control_addr, control, control & CTRL_READY, 283 - MBOX_POLLING_PERIOD_US, MBOX_TIMEOUT_US); 284 - 285 - if (ret) 286 - goto release_mbox; 287 - 288 - status = FIELD_GET(CTRL_STATUS, control); 289 - ret = sdsi_status_to_errno(status); 290 - 291 - release_mbox: 292 - sdsi_complete_transaction(priv); 293 - 294 - return ret; 259 + return sdsi_mbox_poll(priv, info, data_size); 295 260 } 296 261 297 262 static int sdsi_mbox_acquire(struct sdsi_priv *priv, struct sdsi_mbox_info *info) ··· 323 312 return ret; 324 313 } 325 314 326 - static int sdsi_mbox_write(struct sdsi_priv *priv, struct sdsi_mbox_info *info) 315 + static int sdsi_mbox_write(struct sdsi_priv *priv, struct sdsi_mbox_info *info, 316 + size_t *data_size) 327 317 { 328 318 int ret; 329 319 ··· 334 322 if (ret) 335 323 return ret; 336 324 337 - return sdsi_mbox_cmd_write(priv, info); 325 + return sdsi_mbox_cmd_write(priv, info, data_size); 338 326 } 339 327 340 328 static int sdsi_mbox_read(struct sdsi_priv *priv, struct sdsi_mbox_info *info, size_t *data_size) ··· 350 338 return sdsi_mbox_cmd_read(priv, info, data_size); 351 339 } 352 340 341 + static bool sdsi_ib_locked(struct sdsi_priv *priv) 342 + { 343 + return !!FIELD_GET(CTRL_INBAND_LOCK, readq(priv->control_addr)); 344 + } 345 + 353 346 static ssize_t sdsi_provision(struct sdsi_priv *priv, char *buf, size_t count, 354 347 enum sdsi_command command) 355 348 { 356 - struct sdsi_mbox_info info; 349 + struct sdsi_mbox_info info = {}; 357 350 int ret; 358 351 359 352 if (count > (SDSI_SIZE_WRITE_MSG - SDSI_SIZE_CMD)) 360 353 return -EOVERFLOW; 354 + 355 + /* Make sure In-band lock is not set */ 356 + if (sdsi_ib_locked(priv)) 357 + return -EPERM; 361 358 362 359 /* Qword aligned message + command qword */ 363 360 info.size = round_up(count, SDSI_SIZE_CMD) + SDSI_SIZE_CMD; ··· 384 363 ret = mutex_lock_interruptible(&priv->mb_lock); 385 364 if (ret) 386 365 goto free_payload; 387 - ret = sdsi_mbox_write(priv, &info); 366 + 367 + ret = sdsi_mbox_write(priv, &info, NULL); 368 + 388 369 mutex_unlock(&priv->mb_lock); 389 370 390 371 free_payload: ··· 427 404 static BIN_ATTR_WO(provision_cap, SDSI_SIZE_WRITE_MSG); 428 405 429 406 static ssize_t 430 - certificate_read(u64 command, struct sdsi_priv *priv, char *buf, loff_t off, 431 - size_t count) 407 + certificate_read(u64 command, u64 control_flags, struct sdsi_priv *priv, 408 + char *buf, loff_t off, size_t count) 432 409 { 433 - struct sdsi_mbox_info info; 410 + struct sdsi_mbox_info info = {}; 434 411 size_t size; 435 412 int ret; 436 413 ··· 444 421 445 422 info.payload = &command; 446 423 info.size = sizeof(command); 424 + info.control_flags = control_flags; 447 425 448 426 ret = mutex_lock_interruptible(&priv->mb_lock); 449 427 if (ret) ··· 476 452 struct device *dev = kobj_to_dev(kobj); 477 453 struct sdsi_priv *priv = dev_get_drvdata(dev); 478 454 479 - return certificate_read(SDSI_CMD_READ_STATE, priv, buf, off, count); 455 + return certificate_read(SDSI_CMD_READ_STATE, 0, priv, buf, off, count); 480 456 } 481 457 static BIN_ATTR_ADMIN_RO(state_certificate, SDSI_SIZE_READ_MSG); 482 458 ··· 488 464 struct device *dev = kobj_to_dev(kobj); 489 465 struct sdsi_priv *priv = dev_get_drvdata(dev); 490 466 491 - return certificate_read(SDSI_CMD_READ_METER, priv, buf, off, count); 467 + return certificate_read(SDSI_CMD_READ_METER, 0, priv, buf, off, count); 492 468 } 493 469 static BIN_ATTR_ADMIN_RO(meter_certificate, SDSI_SIZE_READ_MSG); 470 + 471 + static ssize_t 472 + meter_current_read(struct file *filp, struct kobject *kobj, 473 + struct bin_attribute *attr, char *buf, loff_t off, 474 + size_t count) 475 + { 476 + struct device *dev = kobj_to_dev(kobj); 477 + struct sdsi_priv *priv = dev_get_drvdata(dev); 478 + 479 + return certificate_read(SDSI_CMD_READ_METER, CTRL_METER_ENABLE_DRAM, 480 + priv, buf, off, count); 481 + } 482 + static BIN_ATTR_ADMIN_RO(meter_current, SDSI_SIZE_READ_MSG); 494 483 495 484 static ssize_t registers_read(struct file *filp, struct kobject *kobj, 496 485 struct bin_attribute *attr, char *buf, loff_t off, ··· 535 498 &bin_attr_registers, 536 499 &bin_attr_state_certificate, 537 500 &bin_attr_meter_certificate, 501 + &bin_attr_meter_current, 538 502 &bin_attr_provision_akc, 539 503 &bin_attr_provision_cap, 540 504 NULL ··· 555 517 if (!(priv->features & SDSI_FEATURE_SDSI)) 556 518 return 0; 557 519 558 - if (attr == &bin_attr_meter_certificate) 520 + if (attr == &bin_attr_meter_certificate || attr == &bin_attr_meter_current) 559 521 return (priv->features & SDSI_FEATURE_METERING) ? 560 522 attr->attr.mode : 0; 561 523
+1
drivers/platform/x86/intel/speed_select_if/isst_if_common.c
··· 839 839 } 840 840 EXPORT_SYMBOL_GPL(isst_if_cdev_unregister); 841 841 842 + MODULE_DESCRIPTION("ISST common interface module"); 842 843 MODULE_LICENSE("GPL v2");
+324 -63
drivers/platform/x86/intel/speed_select_if/isst_tpmi_core.c
··· 17 17 * the hardware mapping. 18 18 */ 19 19 20 + #define dev_fmt(fmt) "tpmi_sst: " fmt 21 + 20 22 #include <linux/auxiliary_bus.h> 21 23 #include <linux/delay.h> 22 24 #include <linux/intel_tpmi.h> 23 25 #include <linux/fs.h> 24 26 #include <linux/io.h> 25 27 #include <linux/kernel.h> 28 + #include <linux/minmax.h> 26 29 #include <linux/module.h> 27 30 #include <uapi/linux/isst_if.h> 28 31 ··· 266 263 bool write_blocked; 267 264 }; 268 265 266 + /* Supported maximum partitions */ 267 + #define SST_MAX_PARTITIONS 2 268 + 269 269 /** 270 270 * struct tpmi_sst_struct - Store sst info for a package 271 271 * @package_id: Package id for this aux device instance 272 272 * @number_of_power_domains: Number of power_domains pointed by power_domain_info pointer 273 273 * @power_domain_info: Pointer to power domains information 274 + * @cdie_mask: Mask of compute dies present in a partition from hardware. 275 + * This mask is not present in the version 1 information header. 276 + * @io_dies: Number of IO dies in a partition. This will be 0 for TPMI 277 + * version 1 information header. 278 + * @partition_mask: Mask of all partitions. 279 + * @partition_mask_current: Current partition mask as some may have been unbound. 274 280 * 275 281 * This structure is used store full SST information for a package. 276 - * Each package has a unique OOB PCI device, which enumerates TPMI. 277 - * Each Package will have multiple power_domains. 282 + * Each package has one or multiple OOB PCI devices. Each package can contain multiple 283 + * power domains. 278 284 */ 279 285 struct tpmi_sst_struct { 280 286 int package_id; 281 - int number_of_power_domains; 282 - struct tpmi_per_power_domain_info *power_domain_info; 287 + struct tpmi_per_power_domain_info *power_domain_info[SST_MAX_PARTITIONS]; 288 + u16 cdie_mask[SST_MAX_PARTITIONS]; 289 + u8 number_of_power_domains[SST_MAX_PARTITIONS]; 290 + u8 io_dies[SST_MAX_PARTITIONS]; 291 + u8 partition_mask; 292 + u8 partition_mask_current; 283 293 }; 284 294 285 295 /** ··· 329 313 struct tpmi_per_power_domain_info *pd_info, 330 314 int levels) 331 315 { 316 + struct device *dev = &auxdev->dev; 332 317 u64 perf_level_offsets; 333 318 int i; 334 319 335 - pd_info->perf_levels = devm_kcalloc(&auxdev->dev, levels, 336 - sizeof(struct perf_level), 337 - GFP_KERNEL); 320 + pd_info->perf_levels = devm_kcalloc(dev, levels, sizeof(struct perf_level), GFP_KERNEL); 338 321 if (!pd_info->perf_levels) 339 322 return 0; 340 323 ··· 364 349 365 350 static int sst_main(struct auxiliary_device *auxdev, struct tpmi_per_power_domain_info *pd_info) 366 351 { 352 + struct device *dev = &auxdev->dev; 367 353 int i, mask, levels; 368 354 369 355 *((u64 *)&pd_info->sst_header) = readq(pd_info->sst_base); ··· 375 359 return -ENODEV; 376 360 377 361 if (TPMI_MAJOR_VERSION(pd_info->sst_header.interface_version) != ISST_MAJOR_VERSION) { 378 - dev_err(&auxdev->dev, "SST: Unsupported major version:%lx\n", 362 + dev_err(dev, "SST: Unsupported major version:%lx\n", 379 363 TPMI_MAJOR_VERSION(pd_info->sst_header.interface_version)); 380 364 return -ENODEV; 381 365 } 382 366 383 367 if (TPMI_MINOR_VERSION(pd_info->sst_header.interface_version) != ISST_MINOR_VERSION) 384 - dev_info(&auxdev->dev, "SST: Ignore: Unsupported minor version:%lx\n", 368 + dev_info(dev, "SST: Ignore: Unsupported minor version:%lx\n", 385 369 TPMI_MINOR_VERSION(pd_info->sst_header.interface_version)); 386 370 387 371 /* Read SST CP Header */ ··· 403 387 return 0; 404 388 } 405 389 390 + static u8 isst_instance_count(struct tpmi_sst_struct *sst_inst) 391 + { 392 + u8 i, max_part, count = 0; 393 + 394 + /* Partition mask starts from bit 0 and contains 1s only */ 395 + max_part = hweight8(sst_inst->partition_mask); 396 + for (i = 0; i < max_part; i++) 397 + count += sst_inst->number_of_power_domains[i]; 398 + 399 + return count; 400 + } 401 + 402 + /** 403 + * map_cdies() - Map user domain ID to compute domain ID 404 + * @sst_inst: TPMI Instance 405 + * @id: User domain ID 406 + * @partition: Resolved partition 407 + * 408 + * Helper function to map_partition_power_domain_id() to resolve compute 409 + * domain ID and partition. Use hardware provided cdie_mask for a partition 410 + * as is to resolve a compute domain ID. 411 + * 412 + * Return: %-EINVAL on error, otherwise mapped domain ID >= 0. 413 + */ 414 + static int map_cdies(struct tpmi_sst_struct *sst_inst, u8 id, u8 *partition) 415 + { 416 + u8 i, max_part; 417 + 418 + max_part = hweight8(sst_inst->partition_mask); 419 + for (i = 0; i < max_part; i++) { 420 + if (!(sst_inst->cdie_mask[i] & BIT(id))) 421 + continue; 422 + 423 + *partition = i; 424 + return id - ffs(sst_inst->cdie_mask[i]) + 1; 425 + } 426 + 427 + return -EINVAL; 428 + } 429 + 430 + /** 431 + * map_partition_power_domain_id() - Map user domain ID to partition domain ID 432 + * @sst_inst: TPMI Instance 433 + * @id: User domain ID 434 + * @partition: Resolved partition 435 + * 436 + * In a partitioned system a CPU package has two separate MMIO ranges (Under 437 + * two PCI devices). But the CPU package compute die/power domain IDs are 438 + * unique in a package. User space can get compute die/power domain ID from 439 + * CPUID and MSR 0x54 for a CPU. So, those IDs need to be preserved even if 440 + * they are present in two different partitions with its own order. 441 + * 442 + * For example for command ISST_IF_COUNT_TPMI_INSTANCES, the valid_mask 443 + * is 111111b for a 4 compute and 2 IO dies system. This is presented as 444 + * provided by the hardware in a non-partitioned system with the following 445 + * order: 446 + * I1-I0-C3-C2-C1-C0 447 + * Here: "C": for compute and "I" for IO die. 448 + * Compute dies are always present first in TPMI instances, as they have 449 + * to map to the real power domain/die ID of a system. In a non-partitioned 450 + * system there is no way to identify compute and IO die boundaries from 451 + * this driver without reading each CPU's mapping. 452 + * 453 + * The same order needs to be preserved, even if those compute dies are 454 + * distributed among multiple partitions. For example: 455 + * Partition 1 can contain: I1-C1-C0 456 + * Partition 2 can contain: I2-C3-C2 457 + * 458 + * This will require a conversion of user space IDs to the actual index into 459 + * array of stored power domains for each partition. For the above example 460 + * this function will return partition and index as follows: 461 + * 462 + * ============= ========= ===== ======== 463 + * User space ID Partition Index Die type 464 + * ============= ========= ===== ======== 465 + * 0 0 0 Compute 466 + * 1 0 1 Compute 467 + * 2 1 0 Compute 468 + * 3 1 1 Compute 469 + * 4 0 2 IO 470 + * 5 1 2 IO 471 + * ============= ========= ===== ======== 472 + * 473 + * Return: %-EINVAL on error, otherwise mapped domain ID >= 0. 474 + */ 475 + static int map_partition_power_domain_id(struct tpmi_sst_struct *sst_inst, u8 id, u8 *partition) 476 + { 477 + u8 i, io_start_id, max_part; 478 + 479 + *partition = 0; 480 + 481 + /* If any PCI device for partition is unbound, treat this as failure */ 482 + if (sst_inst->partition_mask != sst_inst->partition_mask_current) 483 + return -EINVAL; 484 + 485 + max_part = hweight8(sst_inst->partition_mask); 486 + 487 + /* IO Index begin here */ 488 + io_start_id = fls(sst_inst->cdie_mask[max_part - 1]); 489 + 490 + if (id < io_start_id) 491 + return map_cdies(sst_inst, id, partition); 492 + 493 + for (i = 0; i < max_part; i++) { 494 + u8 io_id; 495 + 496 + io_id = id - io_start_id; 497 + if (io_id < sst_inst->io_dies[i]) { 498 + u8 cdie_range; 499 + 500 + cdie_range = fls(sst_inst->cdie_mask[i]) - ffs(sst_inst->cdie_mask[i]) + 1; 501 + *partition = i; 502 + return cdie_range + io_id; 503 + } 504 + io_start_id += sst_inst->io_dies[i]; 505 + } 506 + 507 + return -EINVAL; 508 + } 509 + 406 510 /* 407 511 * Map a package and power_domain id to SST information structure unique for a power_domain. 408 512 * The caller should call under isst_tpmi_dev_lock. ··· 531 395 { 532 396 struct tpmi_per_power_domain_info *power_domain_info; 533 397 struct tpmi_sst_struct *sst_inst; 398 + u8 part; 534 399 535 - if (pkg_id < 0 || pkg_id > isst_common.max_index || 536 - pkg_id >= topology_max_packages()) 400 + if (!in_range(pkg_id, 0, topology_max_packages()) || pkg_id > isst_common.max_index) 537 401 return NULL; 538 402 539 403 sst_inst = isst_common.sst_inst[pkg_id]; 540 404 if (!sst_inst) 541 405 return NULL; 542 406 543 - if (power_domain_id < 0 || power_domain_id >= sst_inst->number_of_power_domains) 407 + power_domain_id = map_partition_power_domain_id(sst_inst, power_domain_id, &part); 408 + if (power_domain_id < 0) 544 409 return NULL; 545 410 546 - power_domain_info = &sst_inst->power_domain_info[power_domain_id]; 411 + power_domain_info = &sst_inst->power_domain_info[part][power_domain_id]; 547 412 548 413 if (power_domain_info && !power_domain_info->sst_base) 549 414 return NULL; ··· 716 579 struct tpmi_sst_struct *sst_inst; 717 580 int offset, shift, cpu; 718 581 u64 val, mask, clos; 582 + u8 part; 719 583 720 584 if (copy_from_user(&clos_assoc, ptr, sizeof(clos_assoc))) 721 585 return -EFAULT; ··· 740 602 741 603 sst_inst = isst_common.sst_inst[pkg_id]; 742 604 743 - if (clos_assoc.power_domain_id > sst_inst->number_of_power_domains) 605 + punit_id = map_partition_power_domain_id(sst_inst, punit_id, &part); 606 + if (punit_id < 0) 744 607 return -EINVAL; 745 608 746 - power_domain_info = &sst_inst->power_domain_info[punit_id]; 609 + power_domain_info = &sst_inst->power_domain_info[part][punit_id]; 747 610 748 611 if (assoc_cmds.get_set && power_domain_info->write_blocked) 749 612 return -EPERM; ··· 847 708 { 848 709 struct isst_perf_level_info perf_level; 849 710 struct tpmi_per_power_domain_info *power_domain_info; 711 + unsigned long level_mask; 712 + u8 level, support; 850 713 851 714 if (copy_from_user(&perf_level, argp, sizeof(perf_level))) 852 715 return -EFAULT; ··· 868 727 SST_PP_FEATURE_STATE_START, SST_PP_FEATURE_STATE_WIDTH, SST_MUL_FACTOR_NONE) 869 728 perf_level.enabled = !!(power_domain_info->sst_header.cap_mask & BIT(1)); 870 729 871 - _read_bf_level_info("bf_support", perf_level.sst_bf_support, 0, 0, 872 - SST_BF_FEATURE_SUPPORTED_START, SST_BF_FEATURE_SUPPORTED_WIDTH, 873 - SST_MUL_FACTOR_NONE); 874 - _read_tf_level_info("tf_support", perf_level.sst_tf_support, 0, 0, 875 - SST_TF_FEATURE_SUPPORTED_START, SST_TF_FEATURE_SUPPORTED_WIDTH, 876 - SST_MUL_FACTOR_NONE); 730 + level_mask = perf_level.level_mask; 731 + perf_level.sst_bf_support = 0; 732 + for_each_set_bit(level, &level_mask, BITS_PER_BYTE) { 733 + /* 734 + * Read BF support for a level. Read output is updated 735 + * to "support" variable by the below macro. 736 + */ 737 + _read_bf_level_info("bf_support", support, level, 0, SST_BF_FEATURE_SUPPORTED_START, 738 + SST_BF_FEATURE_SUPPORTED_WIDTH, SST_MUL_FACTOR_NONE); 739 + 740 + /* If supported set the bit for the level */ 741 + if (support) 742 + perf_level.sst_bf_support |= BIT(level); 743 + } 744 + 745 + perf_level.sst_tf_support = 0; 746 + for_each_set_bit(level, &level_mask, BITS_PER_BYTE) { 747 + /* 748 + * Read TF support for a level. Read output is updated 749 + * to "support" variable by the below macro. 750 + */ 751 + _read_tf_level_info("tf_support", support, level, 0, SST_TF_FEATURE_SUPPORTED_START, 752 + SST_TF_FEATURE_SUPPORTED_WIDTH, SST_MUL_FACTOR_NONE); 753 + 754 + /* If supported set the bit for the level */ 755 + if (support) 756 + perf_level.sst_tf_support |= BIT(level); 757 + } 877 758 878 759 if (copy_to_user(argp, &perf_level, sizeof(perf_level))) 879 760 return -EFAULT; ··· 1297 1134 if (tpmi_inst.socket_id >= topology_max_packages()) 1298 1135 return -EINVAL; 1299 1136 1300 - tpmi_inst.count = isst_common.sst_inst[tpmi_inst.socket_id]->number_of_power_domains; 1301 - 1302 1137 sst_inst = isst_common.sst_inst[tpmi_inst.socket_id]; 1303 - tpmi_inst.valid_mask = 0; 1304 - for (i = 0; i < sst_inst->number_of_power_domains; ++i) { 1305 - struct tpmi_per_power_domain_info *pd_info; 1306 1138 1307 - pd_info = &sst_inst->power_domain_info[i]; 1139 + tpmi_inst.count = isst_instance_count(sst_inst); 1140 + 1141 + tpmi_inst.valid_mask = 0; 1142 + for (i = 0; i < tpmi_inst.count; i++) { 1143 + struct tpmi_per_power_domain_info *pd_info; 1144 + u8 part; 1145 + int pd; 1146 + 1147 + pd = map_partition_power_domain_id(sst_inst, i, &part); 1148 + if (pd < 0) 1149 + continue; 1150 + 1151 + pd_info = &sst_inst->power_domain_info[part][pd]; 1308 1152 if (pd_info->sst_base) 1309 1153 tpmi_inst.valid_mask |= BIT(i); 1310 1154 } 1155 + 1156 + if (!tpmi_inst.valid_mask) 1157 + tpmi_inst.count = 0; 1311 1158 1312 1159 if (copy_to_user(argp, &tpmi_inst, sizeof(tpmi_inst))) 1313 1160 return -EFAULT; ··· 1444 1271 1445 1272 int tpmi_sst_dev_add(struct auxiliary_device *auxdev) 1446 1273 { 1274 + struct tpmi_per_power_domain_info *pd_info; 1447 1275 bool read_blocked = 0, write_blocked = 0; 1448 1276 struct intel_tpmi_plat_info *plat_info; 1277 + struct device *dev = &auxdev->dev; 1449 1278 struct tpmi_sst_struct *tpmi_sst; 1450 - int i, ret, pkg = 0, inst = 0; 1451 - int num_resources; 1279 + u8 i, num_resources, io_die_cnt; 1280 + int ret, pkg = 0, inst = 0; 1281 + bool first_enum = false; 1282 + u16 cdie_mask; 1283 + u8 partition; 1452 1284 1453 1285 ret = tpmi_get_feature_status(auxdev, TPMI_ID_SST, &read_blocked, &write_blocked); 1454 1286 if (ret) 1455 - dev_info(&auxdev->dev, "Can't read feature status: ignoring read/write blocked status\n"); 1287 + dev_info(dev, "Can't read feature status: ignoring read/write blocked status\n"); 1456 1288 1457 1289 if (read_blocked) { 1458 - dev_info(&auxdev->dev, "Firmware has blocked reads, exiting\n"); 1290 + dev_info(dev, "Firmware has blocked reads, exiting\n"); 1459 1291 return -ENODEV; 1460 1292 } 1461 1293 1462 1294 plat_info = tpmi_get_platform_data(auxdev); 1463 1295 if (!plat_info) { 1464 - dev_err(&auxdev->dev, "No platform info\n"); 1296 + dev_err(dev, "No platform info\n"); 1465 1297 return -EINVAL; 1466 1298 } 1467 1299 1468 1300 pkg = plat_info->package_id; 1469 1301 if (pkg >= topology_max_packages()) { 1470 - dev_err(&auxdev->dev, "Invalid package id :%x\n", pkg); 1302 + dev_err(dev, "Invalid package id :%x\n", pkg); 1471 1303 return -EINVAL; 1472 1304 } 1473 1305 1474 - if (isst_common.sst_inst[pkg]) 1475 - return -EEXIST; 1306 + partition = plat_info->partition; 1307 + if (partition >= SST_MAX_PARTITIONS) { 1308 + dev_err(&auxdev->dev, "Invalid partition :%x\n", partition); 1309 + return -EINVAL; 1310 + } 1476 1311 1477 1312 num_resources = tpmi_get_resource_count(auxdev); 1478 1313 1479 1314 if (!num_resources) 1480 1315 return -EINVAL; 1481 1316 1482 - tpmi_sst = devm_kzalloc(&auxdev->dev, sizeof(*tpmi_sst), GFP_KERNEL); 1483 - if (!tpmi_sst) 1484 - return -ENOMEM; 1317 + mutex_lock(&isst_tpmi_dev_lock); 1485 1318 1486 - tpmi_sst->power_domain_info = devm_kcalloc(&auxdev->dev, num_resources, 1487 - sizeof(*tpmi_sst->power_domain_info), 1488 - GFP_KERNEL); 1489 - if (!tpmi_sst->power_domain_info) 1490 - return -ENOMEM; 1319 + if (isst_common.sst_inst[pkg]) { 1320 + tpmi_sst = isst_common.sst_inst[pkg]; 1321 + } else { 1322 + /* 1323 + * tpmi_sst instance is for a package. So needs to be 1324 + * allocated only once for both partitions. We can't use 1325 + * devm_* allocation here as each partition is a 1326 + * different device, which can be unbound. 1327 + */ 1328 + tpmi_sst = kzalloc(sizeof(*tpmi_sst), GFP_KERNEL); 1329 + if (!tpmi_sst) { 1330 + ret = -ENOMEM; 1331 + goto unlock_exit; 1332 + } 1333 + first_enum = true; 1334 + } 1491 1335 1492 - tpmi_sst->number_of_power_domains = num_resources; 1336 + ret = 0; 1337 + 1338 + pd_info = devm_kcalloc(dev, num_resources, sizeof(*pd_info), GFP_KERNEL); 1339 + if (!pd_info) { 1340 + ret = -ENOMEM; 1341 + goto unlock_free; 1342 + } 1343 + 1344 + /* Get the IO die count, if cdie_mask is present */ 1345 + if (plat_info->cdie_mask) { 1346 + u8 cdie_range; 1347 + 1348 + cdie_mask = plat_info->cdie_mask; 1349 + cdie_range = fls(cdie_mask) - ffs(cdie_mask) + 1; 1350 + io_die_cnt = num_resources - cdie_range; 1351 + } else { 1352 + /* 1353 + * This is a synthetic mask, careful when assuming that 1354 + * they are compute dies only. 1355 + */ 1356 + cdie_mask = (1 << num_resources) - 1; 1357 + io_die_cnt = 0; 1358 + } 1493 1359 1494 1360 for (i = 0; i < num_resources; ++i) { 1495 1361 struct resource *res; 1496 1362 1497 1363 res = tpmi_get_resource_at_index(auxdev, i); 1498 1364 if (!res) { 1499 - tpmi_sst->power_domain_info[i].sst_base = NULL; 1365 + pd_info[i].sst_base = NULL; 1500 1366 continue; 1501 1367 } 1502 1368 1503 - tpmi_sst->power_domain_info[i].package_id = pkg; 1504 - tpmi_sst->power_domain_info[i].power_domain_id = i; 1505 - tpmi_sst->power_domain_info[i].auxdev = auxdev; 1506 - tpmi_sst->power_domain_info[i].write_blocked = write_blocked; 1507 - tpmi_sst->power_domain_info[i].sst_base = devm_ioremap_resource(&auxdev->dev, res); 1508 - if (IS_ERR(tpmi_sst->power_domain_info[i].sst_base)) 1509 - return PTR_ERR(tpmi_sst->power_domain_info[i].sst_base); 1369 + pd_info[i].package_id = pkg; 1370 + pd_info[i].power_domain_id = i; 1371 + pd_info[i].auxdev = auxdev; 1372 + pd_info[i].write_blocked = write_blocked; 1373 + pd_info[i].sst_base = devm_ioremap_resource(dev, res); 1374 + if (IS_ERR(pd_info[i].sst_base)) { 1375 + ret = PTR_ERR(pd_info[i].sst_base); 1376 + goto unlock_free; 1377 + } 1510 1378 1511 - ret = sst_main(auxdev, &tpmi_sst->power_domain_info[i]); 1379 + ret = sst_main(auxdev, &pd_info[i]); 1512 1380 if (ret) { 1513 - devm_iounmap(&auxdev->dev, tpmi_sst->power_domain_info[i].sst_base); 1514 - tpmi_sst->power_domain_info[i].sst_base = NULL; 1381 + /* 1382 + * This entry is not valid, hardware can partially 1383 + * populate dies. In this case MMIO will have 0xFFs. 1384 + * Also possible some pre-production hardware has 1385 + * invalid data. But don't fail and continue to use 1386 + * other dies with valid data. 1387 + */ 1388 + devm_iounmap(dev, pd_info[i].sst_base); 1389 + pd_info[i].sst_base = NULL; 1515 1390 continue; 1516 1391 } 1517 1392 1518 1393 ++inst; 1519 1394 } 1520 1395 1521 - if (!inst) 1522 - return -ENODEV; 1396 + if (!inst) { 1397 + ret = -ENODEV; 1398 + goto unlock_free; 1399 + } 1523 1400 1524 1401 tpmi_sst->package_id = pkg; 1402 + 1403 + tpmi_sst->power_domain_info[partition] = pd_info; 1404 + tpmi_sst->number_of_power_domains[partition] = num_resources; 1405 + tpmi_sst->cdie_mask[partition] = cdie_mask; 1406 + tpmi_sst->io_dies[partition] = io_die_cnt; 1407 + tpmi_sst->partition_mask |= BIT(partition); 1408 + tpmi_sst->partition_mask_current |= BIT(partition); 1409 + 1525 1410 auxiliary_set_drvdata(auxdev, tpmi_sst); 1526 1411 1527 - mutex_lock(&isst_tpmi_dev_lock); 1528 1412 if (isst_common.max_index < pkg) 1529 1413 isst_common.max_index = pkg; 1530 1414 isst_common.sst_inst[pkg] = tpmi_sst; 1415 + 1416 + unlock_free: 1417 + if (ret && first_enum) 1418 + kfree(tpmi_sst); 1419 + unlock_exit: 1531 1420 mutex_unlock(&isst_tpmi_dev_lock); 1532 1421 1533 - return 0; 1422 + return ret; 1534 1423 } 1535 1424 EXPORT_SYMBOL_NS_GPL(tpmi_sst_dev_add, INTEL_TPMI_SST); 1536 1425 1537 1426 void tpmi_sst_dev_remove(struct auxiliary_device *auxdev) 1538 1427 { 1539 1428 struct tpmi_sst_struct *tpmi_sst = auxiliary_get_drvdata(auxdev); 1429 + struct intel_tpmi_plat_info *plat_info; 1430 + 1431 + plat_info = tpmi_get_platform_data(auxdev); 1432 + if (!plat_info) 1433 + return; 1540 1434 1541 1435 mutex_lock(&isst_tpmi_dev_lock); 1542 - isst_common.sst_inst[tpmi_sst->package_id] = NULL; 1436 + tpmi_sst->power_domain_info[plat_info->partition] = NULL; 1437 + tpmi_sst->partition_mask_current &= ~BIT(plat_info->partition); 1438 + /* Free the package instance when the all partitions are removed */ 1439 + if (!tpmi_sst->partition_mask_current) { 1440 + kfree(tpmi_sst); 1441 + isst_common.sst_inst[tpmi_sst->package_id] = NULL; 1442 + } 1543 1443 mutex_unlock(&isst_tpmi_dev_lock); 1544 1444 } 1545 1445 EXPORT_SYMBOL_NS_GPL(tpmi_sst_dev_remove, INTEL_TPMI_SST); ··· 1620 1374 void tpmi_sst_dev_suspend(struct auxiliary_device *auxdev) 1621 1375 { 1622 1376 struct tpmi_sst_struct *tpmi_sst = auxiliary_get_drvdata(auxdev); 1623 - struct tpmi_per_power_domain_info *power_domain_info = tpmi_sst->power_domain_info; 1377 + struct tpmi_per_power_domain_info *power_domain_info; 1378 + struct intel_tpmi_plat_info *plat_info; 1624 1379 void __iomem *cp_base; 1380 + 1381 + plat_info = tpmi_get_platform_data(auxdev); 1382 + if (!plat_info) 1383 + return; 1384 + 1385 + power_domain_info = tpmi_sst->power_domain_info[plat_info->partition]; 1625 1386 1626 1387 cp_base = power_domain_info->sst_base + power_domain_info->sst_header.cp_offset; 1627 1388 power_domain_info->saved_sst_cp_control = readq(cp_base + SST_CP_CONTROL_OFFSET); ··· 1648 1395 void tpmi_sst_dev_resume(struct auxiliary_device *auxdev) 1649 1396 { 1650 1397 struct tpmi_sst_struct *tpmi_sst = auxiliary_get_drvdata(auxdev); 1651 - struct tpmi_per_power_domain_info *power_domain_info = tpmi_sst->power_domain_info; 1398 + struct tpmi_per_power_domain_info *power_domain_info; 1399 + struct intel_tpmi_plat_info *plat_info; 1652 1400 void __iomem *cp_base; 1401 + 1402 + plat_info = tpmi_get_platform_data(auxdev); 1403 + if (!plat_info) 1404 + return; 1405 + 1406 + power_domain_info = tpmi_sst->power_domain_info[plat_info->partition]; 1653 1407 1654 1408 cp_base = power_domain_info->sst_base + power_domain_info->sst_header.cp_offset; 1655 1409 writeq(power_domain_info->saved_sst_cp_control, cp_base + SST_CP_CONTROL_OFFSET); ··· 1672 1412 } 1673 1413 EXPORT_SYMBOL_NS_GPL(tpmi_sst_dev_resume, INTEL_TPMI_SST); 1674 1414 1675 - #define ISST_TPMI_API_VERSION 0x02 1415 + #define ISST_TPMI_API_VERSION 0x03 1676 1416 1677 1417 int tpmi_sst_init(void) 1678 1418 { ··· 1729 1469 MODULE_IMPORT_NS(INTEL_TPMI); 1730 1470 MODULE_IMPORT_NS(INTEL_TPMI_POWER_DOMAIN); 1731 1471 1472 + MODULE_DESCRIPTION("ISST TPMI interface module"); 1732 1473 MODULE_LICENSE("GPL");
+32 -7
drivers/platform/x86/intel/tpmi.c
··· 128 128 * @dev: PCI device number 129 129 * @bus: PCI bus number 130 130 * @pkg: CPU Package id 131 + * @segment: PCI segment id 132 + * @partition: Package Partition id 133 + * @cdie_mask: Bitmap of compute dies in the current partition 131 134 * @reserved: Reserved for future use 132 135 * @lock: When set to 1 the register is locked and becomes read-only 133 136 * until next reset. Not for use by the OS driver. ··· 142 139 u64 dev:5; 143 140 u64 bus:8; 144 141 u64 pkg:8; 145 - u64 reserved:39; 142 + u64 segment:8; 143 + u64 partition:2; 144 + u64 cdie_mask:16; 145 + u64 reserved:13; 146 146 u64 lock:1; 147 147 } __packed; 148 148 ··· 672 666 } 673 667 674 668 #define TPMI_INFO_BUS_INFO_OFFSET 0x08 669 + #define TPMI_INFO_MAJOR_VERSION 0x00 670 + #define TPMI_INFO_MINOR_VERSION 0x02 675 671 676 672 static int tpmi_process_info(struct intel_tpmi_info *tpmi_info, 677 673 struct intel_tpmi_pm_feature *pfs) 678 674 { 679 675 struct tpmi_info_header header; 680 676 void __iomem *info_mem; 677 + u64 feature_header; 678 + int ret = 0; 681 679 682 - info_mem = ioremap(pfs->vsec_offset + TPMI_INFO_BUS_INFO_OFFSET, 683 - pfs->pfs_header.entry_size * sizeof(u32) - TPMI_INFO_BUS_INFO_OFFSET); 680 + info_mem = ioremap(pfs->vsec_offset, pfs->pfs_header.entry_size * sizeof(u32)); 684 681 if (!info_mem) 685 682 return -ENOMEM; 686 683 687 - memcpy_fromio(&header, info_mem, sizeof(header)); 684 + feature_header = readq(info_mem); 685 + if (TPMI_MAJOR_VERSION(feature_header) != TPMI_INFO_MAJOR_VERSION) { 686 + ret = -ENODEV; 687 + goto error_info_header; 688 + } 689 + 690 + memcpy_fromio(&header, info_mem + TPMI_INFO_BUS_INFO_OFFSET, sizeof(header)); 688 691 689 692 tpmi_info->plat_info.package_id = header.pkg; 690 693 tpmi_info->plat_info.bus_number = header.bus; 691 694 tpmi_info->plat_info.device_number = header.dev; 692 695 tpmi_info->plat_info.function_number = header.fn; 693 696 697 + if (TPMI_MINOR_VERSION(feature_header) >= TPMI_INFO_MINOR_VERSION) { 698 + tpmi_info->plat_info.cdie_mask = header.cdie_mask; 699 + tpmi_info->plat_info.partition = header.partition; 700 + tpmi_info->plat_info.segment = header.segment; 701 + } 702 + 703 + error_info_header: 694 704 iounmap(info_mem); 695 705 696 - return 0; 706 + return ret; 697 707 } 698 708 699 709 static int tpmi_fetch_pfs_header(struct intel_tpmi_pm_feature *pfs, u64 start, int size) ··· 785 763 * when actual device nodes created outside this 786 764 * loop via tpmi_create_devices(). 787 765 */ 788 - if (pfs->pfs_header.tpmi_id == TPMI_INFO_ID) 789 - tpmi_process_info(tpmi_info, pfs); 766 + if (pfs->pfs_header.tpmi_id == TPMI_INFO_ID) { 767 + ret = tpmi_process_info(tpmi_info, pfs); 768 + if (ret) 769 + return ret; 770 + } 790 771 791 772 if (pfs->pfs_header.tpmi_id == TPMI_CONTROL_ID) 792 773 tpmi_set_control_base(auxdev, tpmi_info, pfs);
+7
drivers/platform/x86/intel/uncore-frequency/uncore-frequency-tpmi.c
··· 240 240 bool read_blocked = 0, write_blocked = 0; 241 241 struct intel_tpmi_plat_info *plat_info; 242 242 struct tpmi_uncore_struct *tpmi_uncore; 243 + bool uncore_sysfs_added = false; 243 244 int ret, i, pkg = 0; 244 245 int num_resources; 245 246 ··· 385 384 } 386 385 /* Point to next cluster offset */ 387 386 cluster_offset >>= UNCORE_MAX_CLUSTER_PER_DOMAIN; 387 + uncore_sysfs_added = true; 388 388 } 389 + } 390 + 391 + if (!uncore_sysfs_added) { 392 + ret = -ENODEV; 393 + goto remove_clusters; 389 394 } 390 395 391 396 auxiliary_set_drvdata(auxdev, tpmi_uncore);
+2 -1
drivers/platform/x86/intel/vbtn.c
··· 156 156 157 157 if ((ke = sparse_keymap_entry_from_scancode(priv->buttons_dev, event))) { 158 158 if (!priv->has_buttons) { 159 - dev_warn(&device->dev, "Warning: received a button event on a device without buttons, please report this.\n"); 159 + dev_warn(&device->dev, "Warning: received 0x%02x button event on a device without buttons, please report this.\n", 160 + event); 160 161 return; 161 162 } 162 163 input_dev = priv->buttons_dev;
+127
drivers/platform/x86/lenovo-wmi-camera.c
··· 1 + // SPDX-License-Identifier: GPL-2.0 2 + /* 3 + * Lenovo WMI Camera Button Driver 4 + * 5 + * Author: Ai Chao <aichao@kylinos.cn> 6 + * Copyright (C) 2024 KylinSoft Corporation. 7 + */ 8 + 9 + #include <linux/acpi.h> 10 + #include <linux/device.h> 11 + #include <linux/input.h> 12 + #include <linux/types.h> 13 + #include <linux/module.h> 14 + #include <linux/mutex.h> 15 + #include <linux/wmi.h> 16 + 17 + #define WMI_LENOVO_CAMERABUTTON_EVENT_GUID "50C76F1F-D8E4-D895-0A3D-62F4EA400013" 18 + 19 + struct lenovo_wmi_priv { 20 + struct input_dev *idev; 21 + struct mutex notify_lock; /* lenovo WMI camera button notify lock */ 22 + }; 23 + 24 + enum { 25 + SW_CAMERA_OFF = 0, 26 + SW_CAMERA_ON = 1, 27 + }; 28 + 29 + static void lenovo_wmi_notify(struct wmi_device *wdev, union acpi_object *obj) 30 + { 31 + struct lenovo_wmi_priv *priv = dev_get_drvdata(&wdev->dev); 32 + unsigned int keycode; 33 + u8 camera_mode; 34 + 35 + if (obj->type != ACPI_TYPE_BUFFER) { 36 + dev_err(&wdev->dev, "Bad response type %u\n", obj->type); 37 + return; 38 + } 39 + 40 + if (obj->buffer.length != 1) { 41 + dev_err(&wdev->dev, "Invalid buffer length %u\n", obj->buffer.length); 42 + return; 43 + } 44 + 45 + /* 46 + * obj->buffer.pointer[0] is camera mode: 47 + * 0 camera close 48 + * 1 camera open 49 + */ 50 + camera_mode = obj->buffer.pointer[0]; 51 + if (camera_mode > SW_CAMERA_ON) { 52 + dev_err(&wdev->dev, "Unknown camera mode %u\n", camera_mode); 53 + return; 54 + } 55 + 56 + mutex_lock(&priv->notify_lock); 57 + 58 + keycode = camera_mode == SW_CAMERA_ON ? 59 + KEY_CAMERA_ACCESS_ENABLE : KEY_CAMERA_ACCESS_DISABLE; 60 + input_report_key(priv->idev, keycode, 1); 61 + input_sync(priv->idev); 62 + input_report_key(priv->idev, keycode, 0); 63 + input_sync(priv->idev); 64 + 65 + mutex_unlock(&priv->notify_lock); 66 + } 67 + 68 + static int lenovo_wmi_probe(struct wmi_device *wdev, const void *context) 69 + { 70 + struct lenovo_wmi_priv *priv; 71 + int ret; 72 + 73 + priv = devm_kzalloc(&wdev->dev, sizeof(*priv), GFP_KERNEL); 74 + if (!priv) 75 + return -ENOMEM; 76 + 77 + dev_set_drvdata(&wdev->dev, priv); 78 + 79 + priv->idev = devm_input_allocate_device(&wdev->dev); 80 + if (!priv->idev) 81 + return -ENOMEM; 82 + 83 + priv->idev->name = "Lenovo WMI Camera Button"; 84 + priv->idev->phys = "wmi/input0"; 85 + priv->idev->id.bustype = BUS_HOST; 86 + priv->idev->dev.parent = &wdev->dev; 87 + input_set_capability(priv->idev, EV_KEY, KEY_CAMERA_ACCESS_ENABLE); 88 + input_set_capability(priv->idev, EV_KEY, KEY_CAMERA_ACCESS_DISABLE); 89 + 90 + ret = input_register_device(priv->idev); 91 + if (ret) 92 + return ret; 93 + 94 + mutex_init(&priv->notify_lock); 95 + 96 + return 0; 97 + } 98 + 99 + static void lenovo_wmi_remove(struct wmi_device *wdev) 100 + { 101 + struct lenovo_wmi_priv *priv = dev_get_drvdata(&wdev->dev); 102 + 103 + mutex_destroy(&priv->notify_lock); 104 + } 105 + 106 + static const struct wmi_device_id lenovo_wmi_id_table[] = { 107 + { .guid_string = WMI_LENOVO_CAMERABUTTON_EVENT_GUID }, 108 + { } 109 + }; 110 + MODULE_DEVICE_TABLE(wmi, lenovo_wmi_id_table); 111 + 112 + static struct wmi_driver lenovo_wmi_driver = { 113 + .driver = { 114 + .name = "lenovo-wmi-camera", 115 + .probe_type = PROBE_PREFER_ASYNCHRONOUS, 116 + }, 117 + .id_table = lenovo_wmi_id_table, 118 + .no_singleton = true, 119 + .probe = lenovo_wmi_probe, 120 + .notify = lenovo_wmi_notify, 121 + .remove = lenovo_wmi_remove, 122 + }; 123 + module_wmi_driver(lenovo_wmi_driver); 124 + 125 + MODULE_AUTHOR("Ai Chao <aichao@kylinos.cn>"); 126 + MODULE_DESCRIPTION("Lenovo WMI Camera Button Driver"); 127 + MODULE_LICENSE("GPL");
+338
drivers/platform/x86/lenovo-yoga-tab2-pro-1380-fastcharger.c
··· 1 + // SPDX-License-Identifier: GPL-2.0-or-later 2 + /* 3 + * Support for the custom fast charging protocol found on the Lenovo Yoga 4 + * Tablet 2 1380F / 1380L models. 5 + * 6 + * Copyright (C) 2024 Hans de Goede <hansg@kernel.org> 7 + */ 8 + #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt 9 + 10 + #include <linux/delay.h> 11 + #include <linux/err.h> 12 + #include <linux/errno.h> 13 + #include <linux/extcon.h> 14 + #include <linux/gpio/consumer.h> 15 + #include <linux/module.h> 16 + #include <linux/notifier.h> 17 + #include <linux/pinctrl/consumer.h> 18 + #include <linux/pinctrl/machine.h> 19 + #include <linux/platform_device.h> 20 + #include <linux/serdev.h> 21 + #include <linux/time.h> 22 + #include <linux/types.h> 23 + #include <linux/workqueue.h> 24 + #include "serdev_helpers.h" 25 + 26 + #define YT2_1380_FC_PDEV_NAME "lenovo-yoga-tab2-pro-1380-fastcharger" 27 + #define YT2_1380_FC_SERDEV_CTRL "serial0" 28 + #define YT2_1380_FC_SERDEV_NAME "serial0-0" 29 + #define YT2_1380_FC_EXTCON_NAME "i2c-lc824206xa" 30 + 31 + #define YT2_1380_FC_MAX_TRIES 5 32 + #define YT2_1380_FC_PIN_SW_DELAY_US (10 * USEC_PER_MSEC) 33 + #define YT2_1380_FC_UART_DRAIN_DELAY_US (50 * USEC_PER_MSEC) 34 + #define YT2_1380_FC_VOLT_SW_DELAY_US (1000 * USEC_PER_MSEC) 35 + 36 + struct yt2_1380_fc { 37 + struct device *dev; 38 + struct pinctrl *pinctrl; 39 + struct pinctrl_state *gpio_state; 40 + struct pinctrl_state *uart_state; 41 + struct gpio_desc *uart3_txd; 42 + struct gpio_desc *uart3_rxd; 43 + struct extcon_dev *extcon; 44 + struct notifier_block nb; 45 + struct work_struct work; 46 + bool fast_charging; 47 + }; 48 + 49 + static int yt2_1380_fc_set_gpio_mode(struct yt2_1380_fc *fc, bool enable) 50 + { 51 + struct pinctrl_state *state = enable ? fc->gpio_state : fc->uart_state; 52 + int ret; 53 + 54 + ret = pinctrl_select_state(fc->pinctrl, state); 55 + if (ret) { 56 + dev_err(fc->dev, "Error %d setting pinctrl state\n", ret); 57 + return ret; 58 + } 59 + 60 + fsleep(YT2_1380_FC_PIN_SW_DELAY_US); 61 + return 0; 62 + } 63 + 64 + static bool yt2_1380_fc_dedicated_charger_connected(struct yt2_1380_fc *fc) 65 + { 66 + return extcon_get_state(fc->extcon, EXTCON_CHG_USB_DCP) > 0; 67 + } 68 + 69 + static bool yt2_1380_fc_fast_charger_connected(struct yt2_1380_fc *fc) 70 + { 71 + return extcon_get_state(fc->extcon, EXTCON_CHG_USB_FAST) > 0; 72 + } 73 + 74 + static void yt2_1380_fc_worker(struct work_struct *work) 75 + { 76 + struct yt2_1380_fc *fc = container_of(work, struct yt2_1380_fc, work); 77 + int i, ret; 78 + 79 + /* Do nothing if already fast charging */ 80 + if (yt2_1380_fc_fast_charger_connected(fc)) 81 + return; 82 + 83 + for (i = 0; i < YT2_1380_FC_MAX_TRIES; i++) { 84 + /* Set pins to UART mode (for charger disconnect and retries) */ 85 + ret = yt2_1380_fc_set_gpio_mode(fc, false); 86 + if (ret) 87 + return; 88 + 89 + /* Only try 12V charging if a dedicated charger is detected */ 90 + if (!yt2_1380_fc_dedicated_charger_connected(fc)) 91 + return; 92 + 93 + /* Send the command to switch to 12V charging */ 94 + ret = serdev_device_write_buf(to_serdev_device(fc->dev), "SC", strlen("SC")); 95 + if (ret != strlen("SC")) { 96 + dev_err(fc->dev, "Error %d writing to uart\n", ret); 97 + return; 98 + } 99 + 100 + fsleep(YT2_1380_FC_UART_DRAIN_DELAY_US); 101 + 102 + /* Re-check a charger is still connected */ 103 + if (!yt2_1380_fc_dedicated_charger_connected(fc)) 104 + return; 105 + 106 + /* 107 + * Now switch the lines to GPIO (output, high). The charger 108 + * expects the lines being driven high after the command. 109 + * Presumably this is used to detect the tablet getting 110 + * unplugged (to switch back to 5V output on unplug). 111 + */ 112 + ret = yt2_1380_fc_set_gpio_mode(fc, true); 113 + if (ret) 114 + return; 115 + 116 + fsleep(YT2_1380_FC_VOLT_SW_DELAY_US); 117 + 118 + if (yt2_1380_fc_fast_charger_connected(fc)) 119 + return; /* Success */ 120 + } 121 + 122 + dev_dbg(fc->dev, "Failed to switch to 12V charging (not the original charger?)\n"); 123 + /* Failed to enable 12V fast charging, reset pins to default UART mode */ 124 + yt2_1380_fc_set_gpio_mode(fc, false); 125 + } 126 + 127 + static int yt2_1380_fc_extcon_evt(struct notifier_block *nb, 128 + unsigned long event, void *param) 129 + { 130 + struct yt2_1380_fc *fc = container_of(nb, struct yt2_1380_fc, nb); 131 + 132 + schedule_work(&fc->work); 133 + return NOTIFY_OK; 134 + } 135 + 136 + static size_t yt2_1380_fc_receive(struct serdev_device *serdev, const u8 *data, size_t len) 137 + { 138 + /* 139 + * Since the USB data lines are shorted for DCP detection, echos of 140 + * the "SC" command send in yt2_1380_fc_worker() will be received. 141 + */ 142 + dev_dbg(&serdev->dev, "recv: %*ph\n", (int)len, data); 143 + return len; 144 + } 145 + 146 + static const struct serdev_device_ops yt2_1380_fc_serdev_ops = { 147 + .receive_buf = yt2_1380_fc_receive, 148 + .write_wakeup = serdev_device_write_wakeup, 149 + }; 150 + 151 + static int yt2_1380_fc_serdev_probe(struct serdev_device *serdev) 152 + { 153 + struct device *dev = &serdev->dev; 154 + struct yt2_1380_fc *fc; 155 + int ret; 156 + 157 + fc = devm_kzalloc(dev, sizeof(*fc), GFP_KERNEL); 158 + if (!fc) 159 + return -ENOMEM; 160 + 161 + fc->dev = dev; 162 + fc->nb.notifier_call = yt2_1380_fc_extcon_evt; 163 + INIT_WORK(&fc->work, yt2_1380_fc_worker); 164 + 165 + /* 166 + * Do this first since it may return -EPROBE_DEFER. 167 + * There is no extcon_put(), so there is no need to free this. 168 + */ 169 + fc->extcon = extcon_get_extcon_dev(YT2_1380_FC_EXTCON_NAME); 170 + if (IS_ERR(fc->extcon)) 171 + return dev_err_probe(dev, PTR_ERR(fc->extcon), "getting extcon\n"); 172 + 173 + fc->pinctrl = devm_pinctrl_get(dev); 174 + if (IS_ERR(fc->pinctrl)) 175 + return dev_err_probe(dev, PTR_ERR(fc->pinctrl), "getting pinctrl\n"); 176 + 177 + /* 178 + * To switch the UART3 pins connected to the USB data lines between 179 + * UART and GPIO modes. 180 + */ 181 + fc->gpio_state = pinctrl_lookup_state(fc->pinctrl, "uart3_gpio"); 182 + fc->uart_state = pinctrl_lookup_state(fc->pinctrl, "uart3_uart"); 183 + if (IS_ERR(fc->gpio_state) || IS_ERR(fc->uart_state)) 184 + return dev_err_probe(dev, -EINVAL, "getting pinctrl states\n"); 185 + 186 + ret = yt2_1380_fc_set_gpio_mode(fc, true); 187 + if (ret) 188 + return ret; 189 + 190 + fc->uart3_txd = devm_gpiod_get(dev, "uart3_txd", GPIOD_OUT_HIGH); 191 + if (IS_ERR(fc->uart3_txd)) 192 + return dev_err_probe(dev, PTR_ERR(fc->uart3_txd), "getting uart3_txd gpio\n"); 193 + 194 + fc->uart3_rxd = devm_gpiod_get(dev, "uart3_rxd", GPIOD_OUT_HIGH); 195 + if (IS_ERR(fc->uart3_rxd)) 196 + return dev_err_probe(dev, PTR_ERR(fc->uart3_rxd), "getting uart3_rxd gpio\n"); 197 + 198 + ret = yt2_1380_fc_set_gpio_mode(fc, false); 199 + if (ret) 200 + return ret; 201 + 202 + ret = devm_serdev_device_open(dev, serdev); 203 + if (ret) 204 + return dev_err_probe(dev, ret, "opening UART device\n"); 205 + 206 + serdev_device_set_baudrate(serdev, 600); 207 + serdev_device_set_flow_control(serdev, false); 208 + serdev_device_set_drvdata(serdev, fc); 209 + serdev_device_set_client_ops(serdev, &yt2_1380_fc_serdev_ops); 210 + 211 + ret = devm_extcon_register_notifier_all(dev, fc->extcon, &fc->nb); 212 + if (ret) 213 + return dev_err_probe(dev, ret, "registering extcon notifier\n"); 214 + 215 + /* In case the extcon already has detected a DCP charger */ 216 + schedule_work(&fc->work); 217 + 218 + return 0; 219 + } 220 + 221 + struct serdev_device_driver yt2_1380_fc_serdev_driver = { 222 + .probe = yt2_1380_fc_serdev_probe, 223 + .driver = { 224 + .name = KBUILD_MODNAME, 225 + }, 226 + }; 227 + 228 + static const struct pinctrl_map yt2_1380_fc_pinctrl_map[] = { 229 + PIN_MAP_MUX_GROUP(YT2_1380_FC_SERDEV_NAME, "uart3_uart", 230 + "INT33FC:00", "uart3_grp", "uart"), 231 + PIN_MAP_MUX_GROUP(YT2_1380_FC_SERDEV_NAME, "uart3_gpio", 232 + "INT33FC:00", "uart3_grp_gpio", "gpio"), 233 + }; 234 + 235 + static int yt2_1380_fc_pdev_probe(struct platform_device *pdev) 236 + { 237 + struct serdev_device *serdev; 238 + struct device *ctrl_dev; 239 + int ret; 240 + 241 + /* Register pinctrl mappings for setting the UART3 pins mode */ 242 + ret = pinctrl_register_mappings(yt2_1380_fc_pinctrl_map, 243 + ARRAY_SIZE(yt2_1380_fc_pinctrl_map)); 244 + if (ret) 245 + return ret; 246 + 247 + /* And create the serdev to talk to the charger over the UART3 pins */ 248 + ctrl_dev = get_serdev_controller("PNP0501", "1", 0, YT2_1380_FC_SERDEV_CTRL); 249 + if (IS_ERR(ctrl_dev)) { 250 + ret = PTR_ERR(ctrl_dev); 251 + goto out_pinctrl_unregister_mappings; 252 + } 253 + 254 + serdev = serdev_device_alloc(to_serdev_controller(ctrl_dev)); 255 + put_device(ctrl_dev); 256 + if (!serdev) { 257 + ret = -ENOMEM; 258 + goto out_pinctrl_unregister_mappings; 259 + } 260 + 261 + ret = serdev_device_add(serdev); 262 + if (ret) { 263 + dev_err_probe(&pdev->dev, ret, "adding serdev\n"); 264 + serdev_device_put(serdev); 265 + goto out_pinctrl_unregister_mappings; 266 + } 267 + 268 + /* 269 + * serdev device <-> driver matching relies on OF or ACPI matches and 270 + * neither is available here, manually bind the driver. 271 + */ 272 + ret = device_driver_attach(&yt2_1380_fc_serdev_driver.driver, &serdev->dev); 273 + if (ret) { 274 + /* device_driver_attach() maps EPROBE_DEFER to EAGAIN, map it back */ 275 + ret = (ret == -EAGAIN) ? -EPROBE_DEFER : ret; 276 + dev_err_probe(&pdev->dev, ret, "attaching serdev driver\n"); 277 + goto out_serdev_device_remove; 278 + } 279 + 280 + /* So that yt2_1380_fc_pdev_remove() can remove the serdev */ 281 + platform_set_drvdata(pdev, serdev); 282 + return 0; 283 + 284 + out_serdev_device_remove: 285 + serdev_device_remove(serdev); 286 + out_pinctrl_unregister_mappings: 287 + pinctrl_unregister_mappings(yt2_1380_fc_pinctrl_map); 288 + return ret; 289 + } 290 + 291 + static void yt2_1380_fc_pdev_remove(struct platform_device *pdev) 292 + { 293 + struct serdev_device *serdev = platform_get_drvdata(pdev); 294 + 295 + serdev_device_remove(serdev); 296 + pinctrl_unregister_mappings(yt2_1380_fc_pinctrl_map); 297 + } 298 + 299 + static struct platform_driver yt2_1380_fc_pdev_driver = { 300 + .probe = yt2_1380_fc_pdev_probe, 301 + .remove_new = yt2_1380_fc_pdev_remove, 302 + .driver = { 303 + .name = YT2_1380_FC_PDEV_NAME, 304 + .probe_type = PROBE_PREFER_ASYNCHRONOUS, 305 + }, 306 + }; 307 + 308 + static int __init yt2_1380_fc_module_init(void) 309 + { 310 + int ret; 311 + 312 + /* 313 + * serdev driver MUST be registered first because pdev driver calls 314 + * device_driver_attach() on the serdev, serdev-driver pair. 315 + */ 316 + ret = serdev_device_driver_register(&yt2_1380_fc_serdev_driver); 317 + if (ret) 318 + return ret; 319 + 320 + ret = platform_driver_register(&yt2_1380_fc_pdev_driver); 321 + if (ret) 322 + serdev_device_driver_unregister(&yt2_1380_fc_serdev_driver); 323 + 324 + return ret; 325 + } 326 + module_init(yt2_1380_fc_module_init); 327 + 328 + static void __exit yt2_1380_fc_module_exit(void) 329 + { 330 + platform_driver_unregister(&yt2_1380_fc_pdev_driver); 331 + serdev_device_driver_unregister(&yt2_1380_fc_serdev_driver); 332 + } 333 + module_exit(yt2_1380_fc_module_exit); 334 + 335 + MODULE_ALIAS("platform:" YT2_1380_FC_PDEV_NAME); 336 + MODULE_DESCRIPTION("Lenovo Yoga Tablet 2 1380 fast charge driver"); 337 + MODULE_AUTHOR("Hans de Goede <hansg@kernel.org>"); 338 + MODULE_LICENSE("GPL");
+150
drivers/platform/x86/meegopad_anx7428.c
··· 1 + // SPDX-License-Identifier: GPL-2.0-or-later 2 + /* 3 + * Driver to power on the Analogix ANX7428 USB Type-C crosspoint switch 4 + * on MeeGoPad top-set boxes. 5 + * 6 + * The MeeGoPad T8 and T9 are Cherry Trail top-set boxes which 7 + * use an ANX7428 to provide a Type-C port with USB3.1 Gen 1 and 8 + * DisplayPort over Type-C alternate mode support. 9 + * 10 + * The ANX7428 has a microcontroller which takes care of the PD 11 + * negotiation and automatically sets the builtin Crosspoint Switch 12 + * to send the right signal to the 4 highspeed pairs of the Type-C 13 + * connector. It also takes care of HPD and AUX channel routing for 14 + * DP alternate mode. 15 + * 16 + * IOW the ANX7428 operates fully autonomous and to the x5-Z8350 SoC 17 + * things look like there simply is a USB-3 Type-A connector and a 18 + * separate DisplayPort connector. Except that the BIOS does not 19 + * power on the ANX7428 at boot. This driver takes care of powering 20 + * on the ANX7428. 21 + * 22 + * It should be possible to tell the micro-controller which data- and/or 23 + * power-role to negotiate and to swap the role(s) after negotiation 24 + * but the MeeGoPad top-set boxes always draw their power from a separate 25 + * power-connector and they only support USB host-mode. So this functionality 26 + * is unnecessary and due to lack of documentation this is tricky to support. 27 + * 28 + * For a more complete ANX7428 driver see drivers/usb/misc/anx7418/ of 29 + * the LineageOS kernel for the LG G5 (International) aka the LG H850: 30 + * https://github.com/LineageOS/android_kernel_lge_msm8996/ 31 + * 32 + * (C) Copyright 2024 Hans de Goede <hansg@kernel.org> 33 + */ 34 + 35 + #include <linux/acpi.h> 36 + #include <linux/bits.h> 37 + #include <linux/delay.h> 38 + #include <linux/dev_printk.h> 39 + #include <linux/dmi.h> 40 + #include <linux/err.h> 41 + #include <linux/gpio/consumer.h> 42 + #include <linux/i2c.h> 43 + #include <linux/iopoll.h> 44 + #include <linux/module.h> 45 + #include <linux/types.h> 46 + 47 + /* Register addresses and fields */ 48 + #define VENDOR_ID 0x00 49 + #define DEVICE_ID 0x02 50 + 51 + #define TX_STATUS 0x16 52 + #define STATUS_SUCCESS BIT(0) 53 + #define STATUS_ERROR BIT(1) 54 + #define OCM_STARTUP BIT(7) 55 + 56 + static bool force; 57 + module_param(force, bool, 0444); 58 + MODULE_PARM_DESC(force, "Force the driver to probe on unknown boards"); 59 + 60 + static const struct acpi_gpio_params enable_gpio = { 0, 0, false }; 61 + static const struct acpi_gpio_params reset_gpio = { 1, 0, true }; 62 + 63 + static const struct acpi_gpio_mapping meegopad_anx7428_gpios[] = { 64 + { "enable-gpios", &enable_gpio, 1 }, 65 + { "reset-gpios", &reset_gpio, 1 }, 66 + { } 67 + }; 68 + 69 + static const struct dmi_system_id meegopad_anx7428_ids[] = { 70 + { 71 + /* Meegopad T08 */ 72 + .matches = { 73 + DMI_MATCH(DMI_SYS_VENDOR, "Default string"), 74 + DMI_MATCH(DMI_PRODUCT_NAME, "Default string"), 75 + DMI_MATCH(DMI_BOARD_NAME, "T3 MRD"), 76 + DMI_MATCH(DMI_BOARD_VERSION, "V1.1"), 77 + }, 78 + }, 79 + { } 80 + }; 81 + 82 + static int anx7428_probe(struct i2c_client *client) 83 + { 84 + struct device *dev = &client->dev; 85 + struct gpio_desc *gpio; 86 + int ret, val; 87 + 88 + if (!dmi_check_system(meegopad_anx7428_ids) && !force) { 89 + dev_warn(dev, "Not probing unknown board, pass meegopad_anx7428.force=1 to probe"); 90 + return -ENODEV; 91 + } 92 + 93 + ret = devm_acpi_dev_add_driver_gpios(dev, meegopad_anx7428_gpios); 94 + if (ret) 95 + return ret; 96 + 97 + /* 98 + * Set GPIOs to desired values while getting them, they are not needed 99 + * afterwards. Ordering and delays come from android_kernel_lge_msm8996. 100 + */ 101 + gpio = devm_gpiod_get(dev, "enable", GPIOD_OUT_HIGH); 102 + if (IS_ERR(gpio)) 103 + return dev_err_probe(dev, PTR_ERR(gpio), "getting enable GPIO\n"); 104 + 105 + fsleep(10000); 106 + 107 + gpio = devm_gpiod_get(dev, "reset", GPIOD_OUT_LOW); 108 + if (IS_ERR(gpio)) 109 + return dev_err_probe(dev, PTR_ERR(gpio), "getting reset GPIO\n"); 110 + 111 + /* Wait for the OCM (On Chip Microcontroller) to start */ 112 + ret = read_poll_timeout(i2c_smbus_read_byte_data, val, 113 + val >= 0 && (val & OCM_STARTUP), 114 + 5000, 50000, true, client, TX_STATUS); 115 + if (ret) 116 + return dev_err_probe(dev, ret, 117 + "On Chip Microcontroller did not start, status: 0x%02x\n", 118 + val); 119 + 120 + ret = i2c_smbus_read_word_data(client, VENDOR_ID); 121 + if (ret < 0) 122 + return dev_err_probe(dev, ret, "reading vendor-id register\n"); 123 + val = ret; 124 + 125 + ret = i2c_smbus_read_word_data(client, DEVICE_ID); 126 + if (ret < 0) 127 + return dev_err_probe(dev, ret, "reading device-id register\n"); 128 + 129 + dev_dbg(dev, "Powered on ANX7428 id %04x:%04x\n", val, ret); 130 + return 0; 131 + } 132 + 133 + static const struct acpi_device_id anx7428_acpi_match[] = { 134 + { "ANXO7418" }, /* ACPI says 7418 (max 2 DP lanes version) but HW is 7428 */ 135 + { } 136 + }; 137 + MODULE_DEVICE_TABLE(acpi, anx7428_acpi_match); 138 + 139 + static struct i2c_driver anx7428_driver = { 140 + .driver = { 141 + .name = "meegopad_anx7428", 142 + .acpi_match_table = anx7428_acpi_match, 143 + }, 144 + .probe = anx7428_probe, 145 + }; 146 + module_i2c_driver(anx7428_driver); 147 + 148 + MODULE_AUTHOR("Hans de Goede <hansg@kernel.org>"); 149 + MODULE_DESCRIPTION("MeeGoPad ANX7428 driver"); 150 + MODULE_LICENSE("GPL");
+10 -10
drivers/platform/x86/msi-laptop.c
··· 317 317 if (ret < 0) 318 318 return ret; 319 319 320 - return sprintf(buf, "%i\n", enabled); 320 + return sysfs_emit(buf, "%i\n", enabled); 321 321 } 322 322 323 323 static ssize_t store_wlan(struct device *dev, ··· 341 341 if (ret < 0) 342 342 return ret; 343 343 344 - return sprintf(buf, "%i\n", enabled); 344 + return sysfs_emit(buf, "%i\n", enabled); 345 345 } 346 346 347 347 static ssize_t store_bluetooth(struct device *dev, ··· 364 364 if (ret < 0) 365 365 return ret; 366 366 367 - return sprintf(buf, "%i\n", threeg_s); 367 + return sysfs_emit(buf, "%i\n", threeg_s); 368 368 } 369 369 370 370 static ssize_t store_threeg(struct device *dev, ··· 383 383 if (ret < 0) 384 384 return ret; 385 385 386 - return sprintf(buf, "%i\n", ret); 386 + return sysfs_emit(buf, "%i\n", ret); 387 387 } 388 388 389 389 static ssize_t store_lcd_level(struct device *dev, ··· 413 413 if (ret < 0) 414 414 return ret; 415 415 416 - return sprintf(buf, "%i\n", ret); 416 + return sysfs_emit(buf, "%i\n", ret); 417 417 } 418 418 419 419 static ssize_t store_auto_brightness(struct device *dev, ··· 443 443 if (result < 0) 444 444 return result; 445 445 446 - return sprintf(buf, "%i\n", !!(rdata & MSI_STANDARD_EC_TOUCHPAD_MASK)); 446 + return sysfs_emit(buf, "%i\n", !!(rdata & MSI_STANDARD_EC_TOUCHPAD_MASK)); 447 447 } 448 448 449 449 static ssize_t show_turbo(struct device *dev, ··· 457 457 if (result < 0) 458 458 return result; 459 459 460 - return sprintf(buf, "%i\n", !!(rdata & MSI_STANDARD_EC_TURBO_MASK)); 460 + return sysfs_emit(buf, "%i\n", !!(rdata & MSI_STANDARD_EC_TURBO_MASK)); 461 461 } 462 462 463 463 static ssize_t show_eco(struct device *dev, ··· 471 471 if (result < 0) 472 472 return result; 473 473 474 - return sprintf(buf, "%i\n", !!(rdata & MSI_STANDARD_EC_ECO_MASK)); 474 + return sysfs_emit(buf, "%i\n", !!(rdata & MSI_STANDARD_EC_ECO_MASK)); 475 475 } 476 476 477 477 static ssize_t show_turbo_cooldown(struct device *dev, ··· 485 485 if (result < 0) 486 486 return result; 487 487 488 - return sprintf(buf, "%i\n", (!!(rdata & MSI_STANDARD_EC_TURBO_MASK)) | 488 + return sysfs_emit(buf, "%i\n", (!!(rdata & MSI_STANDARD_EC_TURBO_MASK)) | 489 489 (!!(rdata & MSI_STANDARD_EC_TURBO_COOLDOWN_MASK) << 1)); 490 490 } 491 491 ··· 500 500 if (result < 0) 501 501 return result; 502 502 503 - return sprintf(buf, "%i\n", !!(rdata & MSI_STANDARD_EC_AUTOFAN_MASK)); 503 + return sysfs_emit(buf, "%i\n", !!(rdata & MSI_STANDARD_EC_AUTOFAN_MASK)); 504 504 } 505 505 506 506 static ssize_t store_auto_fan(struct device *dev,
+428
drivers/platform/x86/msi-wmi-platform.c
··· 1 + // SPDX-License-Identifier: GPL-2.0-or-later 2 + /* 3 + * Linux driver for WMI platform features on MSI notebooks. 4 + * 5 + * Copyright (C) 2024 Armin Wolf <W_Armin@gmx.de> 6 + */ 7 + 8 + #define pr_format(fmt) KBUILD_MODNAME ": " fmt 9 + 10 + #include <linux/acpi.h> 11 + #include <linux/bits.h> 12 + #include <linux/bitfield.h> 13 + #include <linux/debugfs.h> 14 + #include <linux/device.h> 15 + #include <linux/device/driver.h> 16 + #include <linux/errno.h> 17 + #include <linux/hwmon.h> 18 + #include <linux/kernel.h> 19 + #include <linux/module.h> 20 + #include <linux/printk.h> 21 + #include <linux/rwsem.h> 22 + #include <linux/types.h> 23 + #include <linux/wmi.h> 24 + 25 + #include <asm/unaligned.h> 26 + 27 + #define DRIVER_NAME "msi-wmi-platform" 28 + 29 + #define MSI_PLATFORM_GUID "ABBC0F6E-8EA1-11d1-00A0-C90629100000" 30 + 31 + #define MSI_WMI_PLATFORM_INTERFACE_VERSION 2 32 + 33 + #define MSI_PLATFORM_WMI_MAJOR_OFFSET 1 34 + #define MSI_PLATFORM_WMI_MINOR_OFFSET 2 35 + 36 + #define MSI_PLATFORM_EC_FLAGS_OFFSET 1 37 + #define MSI_PLATFORM_EC_MINOR_MASK GENMASK(3, 0) 38 + #define MSI_PLATFORM_EC_MAJOR_MASK GENMASK(5, 4) 39 + #define MSI_PLATFORM_EC_CHANGED_PAGE BIT(6) 40 + #define MSI_PLATFORM_EC_IS_TIGERLAKE BIT(7) 41 + #define MSI_PLATFORM_EC_VERSION_OFFSET 2 42 + 43 + static bool force; 44 + module_param_unsafe(force, bool, 0); 45 + MODULE_PARM_DESC(force, "Force loading without checking for supported WMI interface versions"); 46 + 47 + enum msi_wmi_platform_method { 48 + MSI_PLATFORM_GET_PACKAGE = 0x01, 49 + MSI_PLATFORM_SET_PACKAGE = 0x02, 50 + MSI_PLATFORM_GET_EC = 0x03, 51 + MSI_PLATFORM_SET_EC = 0x04, 52 + MSI_PLATFORM_GET_BIOS = 0x05, 53 + MSI_PLATFORM_SET_BIOS = 0x06, 54 + MSI_PLATFORM_GET_SMBUS = 0x07, 55 + MSI_PLATFORM_SET_SMBUS = 0x08, 56 + MSI_PLATFORM_GET_MASTER_BATTERY = 0x09, 57 + MSI_PLATFORM_SET_MASTER_BATTERY = 0x0a, 58 + MSI_PLATFORM_GET_SLAVE_BATTERY = 0x0b, 59 + MSI_PLATFORM_SET_SLAVE_BATTERY = 0x0c, 60 + MSI_PLATFORM_GET_TEMPERATURE = 0x0d, 61 + MSI_PLATFORM_SET_TEMPERATURE = 0x0e, 62 + MSI_PLATFORM_GET_THERMAL = 0x0f, 63 + MSI_PLATFORM_SET_THERMAL = 0x10, 64 + MSI_PLATFORM_GET_FAN = 0x11, 65 + MSI_PLATFORM_SET_FAN = 0x12, 66 + MSI_PLATFORM_GET_DEVICE = 0x13, 67 + MSI_PLATFORM_SET_DEVICE = 0x14, 68 + MSI_PLATFORM_GET_POWER = 0x15, 69 + MSI_PLATFORM_SET_POWER = 0x16, 70 + MSI_PLATFORM_GET_DEBUG = 0x17, 71 + MSI_PLATFORM_SET_DEBUG = 0x18, 72 + MSI_PLATFORM_GET_AP = 0x19, 73 + MSI_PLATFORM_SET_AP = 0x1a, 74 + MSI_PLATFORM_GET_DATA = 0x1b, 75 + MSI_PLATFORM_SET_DATA = 0x1c, 76 + MSI_PLATFORM_GET_WMI = 0x1d, 77 + }; 78 + 79 + struct msi_wmi_platform_debugfs_data { 80 + struct wmi_device *wdev; 81 + enum msi_wmi_platform_method method; 82 + struct rw_semaphore buffer_lock; /* Protects debugfs buffer */ 83 + size_t length; 84 + u8 buffer[32]; 85 + }; 86 + 87 + static const char * const msi_wmi_platform_debugfs_names[] = { 88 + "get_package", 89 + "set_package", 90 + "get_ec", 91 + "set_ec", 92 + "get_bios", 93 + "set_bios", 94 + "get_smbus", 95 + "set_smbus", 96 + "get_master_battery", 97 + "set_master_battery", 98 + "get_slave_battery", 99 + "set_slave_battery", 100 + "get_temperature", 101 + "set_temperature", 102 + "get_thermal", 103 + "set_thermal", 104 + "get_fan", 105 + "set_fan", 106 + "get_device", 107 + "set_device", 108 + "get_power", 109 + "set_power", 110 + "get_debug", 111 + "set_debug", 112 + "get_ap", 113 + "set_ap", 114 + "get_data", 115 + "set_data", 116 + "get_wmi" 117 + }; 118 + 119 + static int msi_wmi_platform_parse_buffer(union acpi_object *obj, u8 *output, size_t length) 120 + { 121 + if (obj->type != ACPI_TYPE_BUFFER) 122 + return -ENOMSG; 123 + 124 + if (obj->buffer.length != length) 125 + return -EPROTO; 126 + 127 + if (!obj->buffer.pointer[0]) 128 + return -EIO; 129 + 130 + memcpy(output, obj->buffer.pointer, obj->buffer.length); 131 + 132 + return 0; 133 + } 134 + 135 + static int msi_wmi_platform_query(struct wmi_device *wdev, enum msi_wmi_platform_method method, 136 + u8 *input, size_t input_length, u8 *output, size_t output_length) 137 + { 138 + struct acpi_buffer out = { ACPI_ALLOCATE_BUFFER, NULL }; 139 + struct acpi_buffer in = { 140 + .length = input_length, 141 + .pointer = input 142 + }; 143 + union acpi_object *obj; 144 + acpi_status status; 145 + int ret; 146 + 147 + if (!input_length || !output_length) 148 + return -EINVAL; 149 + 150 + status = wmidev_evaluate_method(wdev, 0x0, method, &in, &out); 151 + if (ACPI_FAILURE(status)) 152 + return -EIO; 153 + 154 + obj = out.pointer; 155 + if (!obj) 156 + return -ENODATA; 157 + 158 + ret = msi_wmi_platform_parse_buffer(obj, output, output_length); 159 + kfree(obj); 160 + 161 + return ret; 162 + } 163 + 164 + static umode_t msi_wmi_platform_is_visible(const void *drvdata, enum hwmon_sensor_types type, 165 + u32 attr, int channel) 166 + { 167 + return 0444; 168 + } 169 + 170 + static int msi_wmi_platform_read(struct device *dev, enum hwmon_sensor_types type, u32 attr, 171 + int channel, long *val) 172 + { 173 + struct wmi_device *wdev = dev_get_drvdata(dev); 174 + u8 input[32] = { 0 }; 175 + u8 output[32]; 176 + u16 data; 177 + int ret; 178 + 179 + ret = msi_wmi_platform_query(wdev, MSI_PLATFORM_GET_FAN, input, sizeof(input), output, 180 + sizeof(output)); 181 + if (ret < 0) 182 + return ret; 183 + 184 + data = get_unaligned_be16(&output[channel * 2 + 1]); 185 + if (!data) 186 + *val = 0; 187 + else 188 + *val = 480000 / data; 189 + 190 + return 0; 191 + } 192 + 193 + static const struct hwmon_ops msi_wmi_platform_ops = { 194 + .is_visible = msi_wmi_platform_is_visible, 195 + .read = msi_wmi_platform_read, 196 + }; 197 + 198 + static const struct hwmon_channel_info * const msi_wmi_platform_info[] = { 199 + HWMON_CHANNEL_INFO(fan, 200 + HWMON_F_INPUT, 201 + HWMON_F_INPUT, 202 + HWMON_F_INPUT, 203 + HWMON_F_INPUT 204 + ), 205 + NULL 206 + }; 207 + 208 + static const struct hwmon_chip_info msi_wmi_platform_chip_info = { 209 + .ops = &msi_wmi_platform_ops, 210 + .info = msi_wmi_platform_info, 211 + }; 212 + 213 + static ssize_t msi_wmi_platform_write(struct file *fp, const char __user *input, size_t length, 214 + loff_t *offset) 215 + { 216 + struct seq_file *seq = fp->private_data; 217 + struct msi_wmi_platform_debugfs_data *data = seq->private; 218 + u8 payload[32] = { }; 219 + ssize_t ret; 220 + 221 + /* Do not allow partial writes */ 222 + if (*offset != 0) 223 + return -EINVAL; 224 + 225 + /* Do not allow incomplete command buffers */ 226 + if (length != data->length) 227 + return -EINVAL; 228 + 229 + ret = simple_write_to_buffer(payload, sizeof(payload), offset, input, length); 230 + if (ret < 0) 231 + return ret; 232 + 233 + down_write(&data->buffer_lock); 234 + ret = msi_wmi_platform_query(data->wdev, data->method, payload, data->length, data->buffer, 235 + data->length); 236 + up_write(&data->buffer_lock); 237 + 238 + if (ret < 0) 239 + return ret; 240 + 241 + return length; 242 + } 243 + 244 + static int msi_wmi_platform_show(struct seq_file *seq, void *p) 245 + { 246 + struct msi_wmi_platform_debugfs_data *data = seq->private; 247 + int ret; 248 + 249 + down_read(&data->buffer_lock); 250 + ret = seq_write(seq, data->buffer, data->length); 251 + up_read(&data->buffer_lock); 252 + 253 + return ret; 254 + } 255 + 256 + static int msi_wmi_platform_open(struct inode *inode, struct file *fp) 257 + { 258 + struct msi_wmi_platform_debugfs_data *data = inode->i_private; 259 + 260 + /* The seq_file uses the last byte of the buffer for detecting buffer overflows */ 261 + return single_open_size(fp, msi_wmi_platform_show, data, data->length + 1); 262 + } 263 + 264 + static const struct file_operations msi_wmi_platform_debugfs_fops = { 265 + .owner = THIS_MODULE, 266 + .open = msi_wmi_platform_open, 267 + .read = seq_read, 268 + .write = msi_wmi_platform_write, 269 + .llseek = seq_lseek, 270 + .release = single_release, 271 + }; 272 + 273 + static void msi_wmi_platform_debugfs_remove(void *data) 274 + { 275 + struct dentry *dir = data; 276 + 277 + debugfs_remove_recursive(dir); 278 + } 279 + 280 + static void msi_wmi_platform_debugfs_add(struct wmi_device *wdev, struct dentry *dir, 281 + const char *name, enum msi_wmi_platform_method method) 282 + { 283 + struct msi_wmi_platform_debugfs_data *data; 284 + struct dentry *entry; 285 + 286 + data = devm_kzalloc(&wdev->dev, sizeof(*data), GFP_KERNEL); 287 + if (!data) 288 + return; 289 + 290 + data->wdev = wdev; 291 + data->method = method; 292 + init_rwsem(&data->buffer_lock); 293 + 294 + /* The ACPI firmware for now always requires a 32 byte input buffer due to 295 + * a peculiarity in how Windows handles the CreateByteField() ACPI operator. 296 + */ 297 + data->length = 32; 298 + 299 + entry = debugfs_create_file(name, 0600, dir, data, &msi_wmi_platform_debugfs_fops); 300 + if (IS_ERR(entry)) 301 + devm_kfree(&wdev->dev, data); 302 + } 303 + 304 + static void msi_wmi_platform_debugfs_init(struct wmi_device *wdev) 305 + { 306 + struct dentry *dir; 307 + char dir_name[64]; 308 + int ret, method; 309 + 310 + scnprintf(dir_name, ARRAY_SIZE(dir_name), "%s-%s", DRIVER_NAME, dev_name(&wdev->dev)); 311 + 312 + dir = debugfs_create_dir(dir_name, NULL); 313 + if (IS_ERR(dir)) 314 + return; 315 + 316 + ret = devm_add_action_or_reset(&wdev->dev, msi_wmi_platform_debugfs_remove, dir); 317 + if (ret < 0) 318 + return; 319 + 320 + for (method = MSI_PLATFORM_GET_PACKAGE; method <= MSI_PLATFORM_GET_WMI; method++) 321 + msi_wmi_platform_debugfs_add(wdev, dir, msi_wmi_platform_debugfs_names[method - 1], 322 + method); 323 + } 324 + 325 + static int msi_wmi_platform_hwmon_init(struct wmi_device *wdev) 326 + { 327 + struct device *hdev; 328 + 329 + hdev = devm_hwmon_device_register_with_info(&wdev->dev, "msi_wmi_platform", wdev, 330 + &msi_wmi_platform_chip_info, NULL); 331 + 332 + return PTR_ERR_OR_ZERO(hdev); 333 + } 334 + 335 + static int msi_wmi_platform_ec_init(struct wmi_device *wdev) 336 + { 337 + u8 input[32] = { 0 }; 338 + u8 output[32]; 339 + u8 flags; 340 + int ret; 341 + 342 + ret = msi_wmi_platform_query(wdev, MSI_PLATFORM_GET_EC, input, sizeof(input), output, 343 + sizeof(output)); 344 + if (ret < 0) 345 + return ret; 346 + 347 + flags = output[MSI_PLATFORM_EC_FLAGS_OFFSET]; 348 + 349 + dev_dbg(&wdev->dev, "EC RAM version %lu.%lu\n", 350 + FIELD_GET(MSI_PLATFORM_EC_MAJOR_MASK, flags), 351 + FIELD_GET(MSI_PLATFORM_EC_MINOR_MASK, flags)); 352 + dev_dbg(&wdev->dev, "EC firmware version %.28s\n", 353 + &output[MSI_PLATFORM_EC_VERSION_OFFSET]); 354 + 355 + if (!(flags & MSI_PLATFORM_EC_IS_TIGERLAKE)) { 356 + if (!force) 357 + return -ENODEV; 358 + 359 + dev_warn(&wdev->dev, "Loading on a non-Tigerlake platform\n"); 360 + } 361 + 362 + return 0; 363 + } 364 + 365 + static int msi_wmi_platform_init(struct wmi_device *wdev) 366 + { 367 + u8 input[32] = { 0 }; 368 + u8 output[32]; 369 + int ret; 370 + 371 + ret = msi_wmi_platform_query(wdev, MSI_PLATFORM_GET_WMI, input, sizeof(input), output, 372 + sizeof(output)); 373 + if (ret < 0) 374 + return ret; 375 + 376 + dev_dbg(&wdev->dev, "WMI interface version %u.%u\n", 377 + output[MSI_PLATFORM_WMI_MAJOR_OFFSET], 378 + output[MSI_PLATFORM_WMI_MINOR_OFFSET]); 379 + 380 + if (output[MSI_PLATFORM_WMI_MAJOR_OFFSET] != MSI_WMI_PLATFORM_INTERFACE_VERSION) { 381 + if (!force) 382 + return -ENODEV; 383 + 384 + dev_warn(&wdev->dev, "Loading despite unsupported WMI interface version (%u.%u)\n", 385 + output[MSI_PLATFORM_WMI_MAJOR_OFFSET], 386 + output[MSI_PLATFORM_WMI_MINOR_OFFSET]); 387 + } 388 + 389 + return 0; 390 + } 391 + 392 + static int msi_wmi_platform_probe(struct wmi_device *wdev, const void *context) 393 + { 394 + int ret; 395 + 396 + ret = msi_wmi_platform_init(wdev); 397 + if (ret < 0) 398 + return ret; 399 + 400 + ret = msi_wmi_platform_ec_init(wdev); 401 + if (ret < 0) 402 + return ret; 403 + 404 + msi_wmi_platform_debugfs_init(wdev); 405 + 406 + return msi_wmi_platform_hwmon_init(wdev); 407 + } 408 + 409 + static const struct wmi_device_id msi_wmi_platform_id_table[] = { 410 + { MSI_PLATFORM_GUID, NULL }, 411 + { } 412 + }; 413 + MODULE_DEVICE_TABLE(wmi, msi_wmi_platform_id_table); 414 + 415 + static struct wmi_driver msi_wmi_platform_driver = { 416 + .driver = { 417 + .name = DRIVER_NAME, 418 + .probe_type = PROBE_PREFER_ASYNCHRONOUS, 419 + }, 420 + .id_table = msi_wmi_platform_id_table, 421 + .probe = msi_wmi_platform_probe, 422 + .no_singleton = true, 423 + }; 424 + module_wmi_driver(msi_wmi_platform_driver); 425 + 426 + MODULE_AUTHOR("Armin Wolf <W_Armin@gmx.de>"); 427 + MODULE_DESCRIPTION("MSI WMI platform features"); 428 + MODULE_LICENSE("GPL");
+19 -25
drivers/platform/x86/p2sb.c
··· 43 43 44 44 static struct p2sb_res_cache p2sb_resources[NR_P2SB_RES_CACHE]; 45 45 46 - static int p2sb_get_devfn(unsigned int *devfn) 46 + static void p2sb_get_devfn(unsigned int *devfn) 47 47 { 48 48 unsigned int fn = P2SB_DEVFN_DEFAULT; 49 49 const struct x86_cpu_id *id; ··· 53 53 fn = (unsigned int)id->driver_data; 54 54 55 55 *devfn = fn; 56 - return 0; 57 56 } 58 57 59 - static bool p2sb_valid_resource(struct resource *res) 58 + static bool p2sb_valid_resource(const struct resource *res) 60 59 { 61 - if (res->flags) 62 - return true; 63 - 64 - return false; 60 + return res->flags & ~IORESOURCE_UNSET; 65 61 } 66 62 67 63 /* Copy resource from the first BAR of the device in question */ ··· 131 135 int ret; 132 136 133 137 /* Get devfn for P2SB device itself */ 134 - ret = p2sb_get_devfn(&devfn_p2sb); 135 - if (ret) 136 - return ret; 138 + p2sb_get_devfn(&devfn_p2sb); 137 139 138 140 bus = p2sb_get_bus(NULL); 139 141 if (!bus) ··· 188 194 int p2sb_bar(struct pci_bus *bus, unsigned int devfn, struct resource *mem) 189 195 { 190 196 struct p2sb_res_cache *cache; 191 - int ret; 192 197 193 198 bus = p2sb_get_bus(bus); 194 199 if (!bus) 195 200 return -ENODEV; 196 201 197 - if (!devfn) { 198 - ret = p2sb_get_devfn(&devfn); 199 - if (ret) 200 - return ret; 201 - } 202 + if (!devfn) 203 + p2sb_get_devfn(&devfn); 202 204 203 205 cache = &p2sb_resources[PCI_FUNC(devfn)]; 204 206 if (cache->bus_dev_id != bus->dev.id) ··· 210 220 211 221 static int __init p2sb_fs_init(void) 212 222 { 213 - p2sb_cache_resources(); 214 - return 0; 223 + return p2sb_cache_resources(); 215 224 } 216 225 217 226 /* 218 - * pci_rescan_remove_lock to avoid access to unhidden P2SB devices can 219 - * not be locked in sysfs pci bus rescan path because of deadlock. To 220 - * avoid the deadlock, access to P2SB devices with the lock at an early 221 - * step in kernel initialization and cache required resources. This 222 - * should happen after subsys_initcall which initializes PCI subsystem 223 - * and before device_initcall which requires P2SB resources. 227 + * pci_rescan_remove_lock() can not be locked in sysfs PCI bus rescan path 228 + * because of deadlock. To avoid the deadlock, access P2SB devices with the lock 229 + * at an early step in kernel initialization and cache required resources. 230 + * 231 + * We want to run as early as possible. If the P2SB was assigned a bad BAR, 232 + * we'll need to wait on pcibios_assign_resources() to fix it. So, our list of 233 + * initcall dependencies looks something like this: 234 + * 235 + * ... 236 + * subsys_initcall (pci_subsys_init) 237 + * fs_initcall (pcibios_assign_resources) 224 238 */ 225 - fs_initcall(p2sb_fs_init); 239 + fs_initcall_sync(p2sb_fs_init);
+246
drivers/platform/x86/quickstart.c
··· 1 + // SPDX-License-Identifier: GPL-2.0-or-later 2 + /* 3 + * ACPI Direct App Launch driver 4 + * 5 + * Copyright (C) 2024 Armin Wolf <W_Armin@gmx.de> 6 + * Copyright (C) 2022 Arvid Norlander <lkml@vorapal.se> 7 + * Copyright (C) 2007-2010 Angelo Arrifano <miknix@gmail.com> 8 + * 9 + * Information gathered from disassembled dsdt and from here: 10 + * <https://archive.org/details/microsoft-acpi-dirapplaunch> 11 + */ 12 + 13 + #include <linux/acpi.h> 14 + #include <linux/device.h> 15 + #include <linux/errno.h> 16 + #include <linux/init.h> 17 + #include <linux/input.h> 18 + #include <linux/input/sparse-keymap.h> 19 + #include <linux/mod_devicetable.h> 20 + #include <linux/module.h> 21 + #include <linux/mutex.h> 22 + #include <linux/platform_device.h> 23 + #include <linux/pm_wakeup.h> 24 + #include <linux/printk.h> 25 + #include <linux/slab.h> 26 + #include <linux/sysfs.h> 27 + #include <linux/types.h> 28 + 29 + #include <asm/unaligned.h> 30 + 31 + #define DRIVER_NAME "quickstart" 32 + 33 + /* 34 + * There will be two events: 35 + * 0x02 - Button was pressed while device was off/sleeping. 36 + * 0x80 - Button was pressed while device was up. 37 + */ 38 + #define QUICKSTART_EVENT_RUNTIME 0x80 39 + 40 + struct quickstart_data { 41 + struct device *dev; 42 + struct mutex input_lock; /* Protects input sequence during notify */ 43 + struct input_dev *input_device; 44 + char input_name[32]; 45 + char phys[32]; 46 + u32 id; 47 + }; 48 + 49 + /* 50 + * Knowing what these buttons do require system specific knowledge. 51 + * This could be done by matching on DMI data in a long quirk table. 52 + * However, it is easier to leave it up to user space to figure this out. 53 + * 54 + * Using for example udev hwdb the scancode 0x1 can be remapped suitably. 55 + */ 56 + static const struct key_entry quickstart_keymap[] = { 57 + { KE_KEY, 0x1, { KEY_UNKNOWN } }, 58 + { KE_END, 0 }, 59 + }; 60 + 61 + static ssize_t button_id_show(struct device *dev, struct device_attribute *attr, char *buf) 62 + { 63 + struct quickstart_data *data = dev_get_drvdata(dev); 64 + 65 + return sysfs_emit(buf, "%u\n", data->id); 66 + } 67 + static DEVICE_ATTR_RO(button_id); 68 + 69 + static struct attribute *quickstart_attrs[] = { 70 + &dev_attr_button_id.attr, 71 + NULL 72 + }; 73 + ATTRIBUTE_GROUPS(quickstart); 74 + 75 + static void quickstart_notify(acpi_handle handle, u32 event, void *context) 76 + { 77 + struct quickstart_data *data = context; 78 + 79 + switch (event) { 80 + case QUICKSTART_EVENT_RUNTIME: 81 + mutex_lock(&data->input_lock); 82 + sparse_keymap_report_event(data->input_device, 0x1, 1, true); 83 + mutex_unlock(&data->input_lock); 84 + 85 + acpi_bus_generate_netlink_event(DRIVER_NAME, dev_name(data->dev), event, 0); 86 + break; 87 + default: 88 + dev_err(data->dev, FW_INFO "Unexpected ACPI notify event (%u)\n", event); 89 + break; 90 + } 91 + } 92 + 93 + /* 94 + * The GHID ACPI method is used to indicate the "role" of the button. 95 + * However, all the meanings of these values are vendor defined. 96 + * 97 + * We do however expose this value to user space. 98 + */ 99 + static int quickstart_get_ghid(struct quickstart_data *data) 100 + { 101 + struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL }; 102 + acpi_handle handle = ACPI_HANDLE(data->dev); 103 + union acpi_object *obj; 104 + acpi_status status; 105 + int ret = 0; 106 + 107 + /* 108 + * This returns a buffer telling the button usage ID, 109 + * and triggers pending notify events (The ones before booting). 110 + */ 111 + status = acpi_evaluate_object_typed(handle, "GHID", NULL, &buffer, ACPI_TYPE_BUFFER); 112 + if (ACPI_FAILURE(status)) 113 + return -EIO; 114 + 115 + obj = buffer.pointer; 116 + if (!obj) 117 + return -ENODATA; 118 + 119 + /* 120 + * Quoting the specification: 121 + * "The GHID method can return a BYTE, WORD, or DWORD. 122 + * The value must be encoded in little-endian byte 123 + * order (least significant byte first)." 124 + */ 125 + switch (obj->buffer.length) { 126 + case 1: 127 + data->id = obj->buffer.pointer[0]; 128 + break; 129 + case 2: 130 + data->id = get_unaligned_le16(obj->buffer.pointer); 131 + break; 132 + case 4: 133 + data->id = get_unaligned_le32(obj->buffer.pointer); 134 + break; 135 + default: 136 + dev_err(data->dev, 137 + FW_BUG "GHID method returned buffer of unexpected length %u\n", 138 + obj->buffer.length); 139 + ret = -EIO; 140 + break; 141 + } 142 + 143 + kfree(obj); 144 + 145 + return ret; 146 + } 147 + 148 + static void quickstart_notify_remove(void *context) 149 + { 150 + struct quickstart_data *data = context; 151 + acpi_handle handle; 152 + 153 + handle = ACPI_HANDLE(data->dev); 154 + 155 + acpi_remove_notify_handler(handle, ACPI_DEVICE_NOTIFY, quickstart_notify); 156 + } 157 + 158 + static void quickstart_mutex_destroy(void *data) 159 + { 160 + struct mutex *lock = data; 161 + 162 + mutex_destroy(lock); 163 + } 164 + 165 + static int quickstart_probe(struct platform_device *pdev) 166 + { 167 + struct quickstart_data *data; 168 + acpi_handle handle; 169 + acpi_status status; 170 + int ret; 171 + 172 + handle = ACPI_HANDLE(&pdev->dev); 173 + if (!handle) 174 + return -ENODEV; 175 + 176 + data = devm_kzalloc(&pdev->dev, sizeof(*data), GFP_KERNEL); 177 + if (!data) 178 + return -ENOMEM; 179 + 180 + data->dev = &pdev->dev; 181 + dev_set_drvdata(&pdev->dev, data); 182 + 183 + mutex_init(&data->input_lock); 184 + ret = devm_add_action_or_reset(&pdev->dev, quickstart_mutex_destroy, &data->input_lock); 185 + if (ret < 0) 186 + return ret; 187 + 188 + /* 189 + * We have to initialize the device wakeup before evaluating GHID because 190 + * doing so will notify the device if the button was used to wake the machine 191 + * from S5. 192 + */ 193 + device_init_wakeup(&pdev->dev, true); 194 + 195 + ret = quickstart_get_ghid(data); 196 + if (ret < 0) 197 + return ret; 198 + 199 + data->input_device = devm_input_allocate_device(&pdev->dev); 200 + if (!data->input_device) 201 + return -ENOMEM; 202 + 203 + ret = sparse_keymap_setup(data->input_device, quickstart_keymap, NULL); 204 + if (ret < 0) 205 + return ret; 206 + 207 + snprintf(data->input_name, sizeof(data->input_name), "Quickstart Button %u", data->id); 208 + snprintf(data->phys, sizeof(data->phys), DRIVER_NAME "/input%u", data->id); 209 + 210 + data->input_device->name = data->input_name; 211 + data->input_device->phys = data->phys; 212 + data->input_device->id.bustype = BUS_HOST; 213 + 214 + ret = input_register_device(data->input_device); 215 + if (ret < 0) 216 + return ret; 217 + 218 + status = acpi_install_notify_handler(handle, ACPI_DEVICE_NOTIFY, quickstart_notify, data); 219 + if (ACPI_FAILURE(status)) 220 + return -EIO; 221 + 222 + return devm_add_action_or_reset(&pdev->dev, quickstart_notify_remove, data); 223 + } 224 + 225 + static const struct acpi_device_id quickstart_device_ids[] = { 226 + { "PNP0C32" }, 227 + { } 228 + }; 229 + MODULE_DEVICE_TABLE(acpi, quickstart_device_ids); 230 + 231 + static struct platform_driver quickstart_platform_driver = { 232 + .driver = { 233 + .name = DRIVER_NAME, 234 + .dev_groups = quickstart_groups, 235 + .probe_type = PROBE_PREFER_ASYNCHRONOUS, 236 + .acpi_match_table = quickstart_device_ids, 237 + }, 238 + .probe = quickstart_probe, 239 + }; 240 + module_platform_driver(quickstart_platform_driver); 241 + 242 + MODULE_AUTHOR("Armin Wolf <W_Armin@gmx.de>"); 243 + MODULE_AUTHOR("Arvid Norlander <lkml@vorpal.se>"); 244 + MODULE_AUTHOR("Angelo Arrifano"); 245 + MODULE_DESCRIPTION("ACPI Direct App Launch driver"); 246 + MODULE_LICENSE("GPL");
+5 -5
drivers/platform/x86/samsung-laptop.c
··· 661 661 /* The logic is backwards, yeah, lots of fun... */ 662 662 for (i = 0; config->performance_levels[i].name; ++i) { 663 663 if (sretval.data[0] == config->performance_levels[i].value) 664 - return sprintf(buf, "%s\n", config->performance_levels[i].name); 664 + return sysfs_emit(buf, "%s\n", config->performance_levels[i].name); 665 665 } 666 - return sprintf(buf, "%s\n", "unknown"); 666 + return sysfs_emit(buf, "%s\n", "unknown"); 667 667 } 668 668 669 669 static ssize_t set_performance_level(struct device *dev, ··· 744 744 if (ret < 0) 745 745 return ret; 746 746 747 - return sprintf(buf, "%d\n", ret); 747 + return sysfs_emit(buf, "%d\n", ret); 748 748 } 749 749 750 750 static ssize_t set_battery_life_extender(struct device *dev, ··· 813 813 if (ret < 0) 814 814 return ret; 815 815 816 - return sprintf(buf, "%d\n", ret); 816 + return sysfs_emit(buf, "%d\n", ret); 817 817 } 818 818 819 819 static ssize_t set_usb_charge(struct device *dev, ··· 878 878 if (ret < 0) 879 879 return ret; 880 880 881 - return sprintf(buf, "%d\n", ret); 881 + return sysfs_emit(buf, "%d\n", ret); 882 882 } 883 883 884 884 static ssize_t set_lid_handling(struct device *dev,
+10 -3
drivers/platform/x86/think-lmi.c
··· 175 175 #define TLMI_SMP_PWD BIT(6) /* System Management */ 176 176 #define TLMI_CERT BIT(7) /* Certificate Based */ 177 177 178 - #define to_tlmi_pwd_setting(kobj) container_of(kobj, struct tlmi_pwd_setting, kobj) 179 - #define to_tlmi_attr_setting(kobj) container_of(kobj, struct tlmi_attr_setting, kobj) 180 - 181 178 static const struct tlmi_err_codes tlmi_errs[] = { 182 179 {"Success", 0}, 183 180 {"Not Supported", -EOPNOTSUPP}, ··· 194 197 static struct think_lmi tlmi_priv; 195 198 static const struct class *fw_attr_class; 196 199 static DEFINE_MUTEX(tlmi_mutex); 200 + 201 + static inline struct tlmi_pwd_setting *to_tlmi_pwd_setting(struct kobject *kobj) 202 + { 203 + return container_of(kobj, struct tlmi_pwd_setting, kobj); 204 + } 205 + 206 + static inline struct tlmi_attr_setting *to_tlmi_attr_setting(struct kobject *kobj) 207 + { 208 + return container_of(kobj, struct tlmi_attr_setting, kobj); 209 + } 197 210 198 211 /* Convert BIOS WMI error string to suitable error code */ 199 212 static int tlmi_errstr_to_err(const char *errstr)
+356 -519
drivers/platform/x86/thinkpad_acpi.c
··· 45 45 #include <linux/hwmon-sysfs.h> 46 46 #include <linux/init.h> 47 47 #include <linux/input.h> 48 + #include <linux/input/sparse-keymap.h> 48 49 #include <linux/jiffies.h> 49 50 #include <linux/kernel.h> 50 51 #include <linux/kthread.h> ··· 158 157 159 158 /* HKEY events */ 160 159 enum tpacpi_hkey_event_t { 161 - /* Hotkey-related */ 162 - TP_HKEY_EV_HOTKEY_BASE = 0x1001, /* first hotkey (FN+F1) */ 160 + /* Original hotkeys */ 161 + TP_HKEY_EV_ORIG_KEY_START = 0x1001, /* First hotkey (FN+F1) */ 163 162 TP_HKEY_EV_BRGHT_UP = 0x1010, /* Brightness up */ 164 163 TP_HKEY_EV_BRGHT_DOWN = 0x1011, /* Brightness down */ 165 164 TP_HKEY_EV_KBD_LIGHT = 0x1012, /* Thinklight/kbd backlight */ 166 165 TP_HKEY_EV_VOL_UP = 0x1015, /* Volume up or unmute */ 167 166 TP_HKEY_EV_VOL_DOWN = 0x1016, /* Volume down or unmute */ 168 167 TP_HKEY_EV_VOL_MUTE = 0x1017, /* Mixer output mute */ 168 + TP_HKEY_EV_ORIG_KEY_END = 0x1020, /* Last original hotkey code */ 169 + 170 + /* Adaptive keyboard (2014 X1 Carbon) */ 171 + TP_HKEY_EV_DFR_CHANGE_ROW = 0x1101, /* Change adaptive kbd Fn row mode */ 172 + TP_HKEY_EV_DFR_S_QUICKVIEW_ROW = 0x1102, /* Set adap. kbd Fn row to function mode */ 173 + TP_HKEY_EV_ADAPTIVE_KEY_START = 0x1103, /* First hotkey code on adaptive kbd */ 174 + TP_HKEY_EV_ADAPTIVE_KEY_END = 0x1116, /* Last hotkey code on adaptive kbd */ 175 + 176 + /* Extended hotkey events in 2017+ models */ 177 + TP_HKEY_EV_EXTENDED_KEY_START = 0x1300, /* First extended hotkey code */ 169 178 TP_HKEY_EV_PRIVACYGUARD_TOGGLE = 0x130f, /* Toggle priv.guard on/off */ 179 + TP_HKEY_EV_EXTENDED_KEY_END = 0x1319, /* Last extended hotkey code using 180 + * hkey -> scancode translation for 181 + * compat. Later codes are entered 182 + * directly in the sparse-keymap. 183 + */ 170 184 TP_HKEY_EV_AMT_TOGGLE = 0x131a, /* Toggle AMT on/off */ 185 + TP_HKEY_EV_DOUBLETAP_TOGGLE = 0x131c, /* Toggle trackpoint doubletap on/off */ 171 186 TP_HKEY_EV_PROFILE_TOGGLE = 0x131f, /* Toggle platform profile */ 172 187 173 188 /* Reasons for waking up from S3/S4 */ ··· 249 232 250 233 /* Misc */ 251 234 TP_HKEY_EV_RFKILL_CHANGED = 0x7000, /* rfkill switch changed */ 235 + 236 + /* Misc2 */ 237 + TP_HKEY_EV_TRACK_DOUBLETAP = 0x8036, /* trackpoint doubletap */ 252 238 }; 253 239 254 240 /**************************************************************************** ··· 373 353 u32 hotkey_poll_active:1; 374 354 u32 has_adaptive_kbd:1; 375 355 u32 kbd_lang:1; 356 + u32 trackpoint_doubletap:1; 376 357 struct quirk_entry *quirks; 377 358 } tp_features; 378 359 ··· 1765 1744 TP_ACPI_HOTKEYSCAN_THINKPAD, 1766 1745 TP_ACPI_HOTKEYSCAN_UNK1, 1767 1746 TP_ACPI_HOTKEYSCAN_UNK2, 1768 - TP_ACPI_HOTKEYSCAN_UNK3, 1747 + TP_ACPI_HOTKEYSCAN_MICMUTE, 1769 1748 TP_ACPI_HOTKEYSCAN_UNK4, 1770 - TP_ACPI_HOTKEYSCAN_UNK5, 1771 - TP_ACPI_HOTKEYSCAN_UNK6, 1772 - TP_ACPI_HOTKEYSCAN_UNK7, 1773 - TP_ACPI_HOTKEYSCAN_UNK8, 1749 + TP_ACPI_HOTKEYSCAN_CONFIG, 1750 + TP_ACPI_HOTKEYSCAN_SEARCH, 1751 + TP_ACPI_HOTKEYSCAN_SCALE, 1752 + TP_ACPI_HOTKEYSCAN_FILE, 1774 1753 1775 1754 /* Adaptive keyboard keycodes */ 1776 - TP_ACPI_HOTKEYSCAN_ADAPTIVE_START, 1755 + TP_ACPI_HOTKEYSCAN_ADAPTIVE_START, /* 32 / 0x20 */ 1777 1756 TP_ACPI_HOTKEYSCAN_MUTE2 = TP_ACPI_HOTKEYSCAN_ADAPTIVE_START, 1778 1757 TP_ACPI_HOTKEYSCAN_BRIGHTNESS_ZERO, 1779 1758 TP_ACPI_HOTKEYSCAN_CLIPPING_TOOL, ··· 1785 1764 TP_ACPI_HOTKEYSCAN_UNK11, 1786 1765 TP_ACPI_HOTKEYSCAN_UNK12, 1787 1766 TP_ACPI_HOTKEYSCAN_UNK13, 1788 - TP_ACPI_HOTKEYSCAN_CONFIG, 1767 + TP_ACPI_HOTKEYSCAN_CONFIG2, 1789 1768 TP_ACPI_HOTKEYSCAN_NEW_TAB, 1790 1769 TP_ACPI_HOTKEYSCAN_RELOAD, 1791 1770 TP_ACPI_HOTKEYSCAN_BACK, ··· 1796 1775 TP_ACPI_HOTKEYSCAN_ROTATE_DISPLAY, 1797 1776 1798 1777 /* Lenovo extended keymap, starting at 0x1300 */ 1799 - TP_ACPI_HOTKEYSCAN_EXTENDED_START, 1778 + TP_ACPI_HOTKEYSCAN_EXTENDED_START, /* 52 / 0x34 */ 1800 1779 /* first new observed key (star, favorites) is 0x1311 */ 1801 1780 TP_ACPI_HOTKEYSCAN_STAR = 69, 1802 1781 TP_ACPI_HOTKEYSCAN_CLIPPING_TOOL2, ··· 1807 1786 TP_ACPI_HOTKEYSCAN_NOTIFICATION_CENTER, 1808 1787 TP_ACPI_HOTKEYSCAN_PICKUP_PHONE, 1809 1788 TP_ACPI_HOTKEYSCAN_HANGUP_PHONE, 1810 - 1811 - /* Hotkey keymap size */ 1812 - TPACPI_HOTKEY_MAP_LEN 1813 1789 }; 1814 1790 1815 1791 enum { /* Keys/events available through NVRAM polling */ ··· 1919 1901 static u32 hotkey_user_mask; /* events visible to userspace */ 1920 1902 static u32 hotkey_acpi_mask; /* events enabled in firmware */ 1921 1903 1922 - static u16 *hotkey_keycode_map; 1923 - 1924 - static void tpacpi_driver_event(const unsigned int hkey_event); 1925 - static void hotkey_driver_event(const unsigned int scancode); 1904 + static bool tpacpi_driver_event(const unsigned int hkey_event); 1926 1905 static void hotkey_poll_setup(const bool may_warn); 1927 1906 1928 1907 /* HKEY.MHKG() return bits */ ··· 2251 2236 } 2252 2237 } 2253 2238 2254 - /* Do NOT call without validating scancode first */ 2255 - static void tpacpi_input_send_key(const unsigned int scancode) 2239 + static bool tpacpi_input_send_key(const u32 hkey, bool *send_acpi_ev) 2256 2240 { 2257 - const unsigned int keycode = hotkey_keycode_map[scancode]; 2241 + bool known_ev; 2242 + u32 scancode; 2258 2243 2259 - if (keycode != KEY_RESERVED) { 2260 - mutex_lock(&tpacpi_inputdev_send_mutex); 2244 + if (tpacpi_driver_event(hkey)) 2245 + return true; 2261 2246 2262 - input_event(tpacpi_inputdev, EV_MSC, MSC_SCAN, scancode); 2263 - input_report_key(tpacpi_inputdev, keycode, 1); 2264 - input_sync(tpacpi_inputdev); 2247 + /* 2248 + * Before the conversion to using the sparse-keymap helpers the driver used to 2249 + * map the hkey event codes to 0x00 - 0x4d scancodes so that a straight scancode 2250 + * indexed array could be used to map scancodes to keycodes: 2251 + * 2252 + * 0x1001 - 0x1020 -> 0x00 - 0x1f (Original ThinkPad events) 2253 + * 0x1103 - 0x1116 -> 0x20 - 0x33 (Adaptive keyboard, 2014 X1 Carbon) 2254 + * 0x1300 - 0x1319 -> 0x34 - 0x4d (Additional keys send in 2017+ models) 2255 + * 2256 + * The sparse-keymap tables still use these scancodes for these ranges to 2257 + * preserve userspace API compatibility (e.g. hwdb keymappings). 2258 + */ 2259 + if (hkey >= TP_HKEY_EV_ORIG_KEY_START && 2260 + hkey <= TP_HKEY_EV_ORIG_KEY_END) { 2261 + scancode = hkey - TP_HKEY_EV_ORIG_KEY_START; 2262 + if (!(hotkey_user_mask & (1 << scancode))) 2263 + return true; /* Not reported but still a known code */ 2264 + } else if (hkey >= TP_HKEY_EV_ADAPTIVE_KEY_START && 2265 + hkey <= TP_HKEY_EV_ADAPTIVE_KEY_END) { 2266 + scancode = hkey - TP_HKEY_EV_ADAPTIVE_KEY_START + 2267 + TP_ACPI_HOTKEYSCAN_ADAPTIVE_START; 2268 + } else if (hkey >= TP_HKEY_EV_EXTENDED_KEY_START && 2269 + hkey <= TP_HKEY_EV_EXTENDED_KEY_END) { 2270 + scancode = hkey - TP_HKEY_EV_EXTENDED_KEY_START + 2271 + TP_ACPI_HOTKEYSCAN_EXTENDED_START; 2272 + } else { 2273 + /* 2274 + * Do not send ACPI netlink events for unknown hotkeys, to 2275 + * avoid userspace starting to rely on them. Instead these 2276 + * should be added to the keymap to send evdev events. 2277 + */ 2278 + if (send_acpi_ev) 2279 + *send_acpi_ev = false; 2265 2280 2266 - input_event(tpacpi_inputdev, EV_MSC, MSC_SCAN, scancode); 2267 - input_report_key(tpacpi_inputdev, keycode, 0); 2268 - input_sync(tpacpi_inputdev); 2269 - 2270 - mutex_unlock(&tpacpi_inputdev_send_mutex); 2281 + scancode = hkey; 2271 2282 } 2272 - } 2273 2283 2274 - /* Do NOT call without validating scancode first */ 2275 - static void tpacpi_input_send_key_masked(const unsigned int scancode) 2276 - { 2277 - hotkey_driver_event(scancode); 2278 - if (hotkey_user_mask & (1 << scancode)) 2279 - tpacpi_input_send_key(scancode); 2284 + mutex_lock(&tpacpi_inputdev_send_mutex); 2285 + known_ev = sparse_keymap_report_event(tpacpi_inputdev, scancode, 1, true); 2286 + mutex_unlock(&tpacpi_inputdev_send_mutex); 2287 + 2288 + return known_ev; 2280 2289 } 2281 2290 2282 2291 #ifdef CONFIG_THINKPAD_ACPI_HOTKEY_POLL ··· 2309 2270 /* Do NOT call without validating scancode first */ 2310 2271 static void tpacpi_hotkey_send_key(unsigned int scancode) 2311 2272 { 2312 - tpacpi_input_send_key_masked(scancode); 2273 + tpacpi_input_send_key(TP_HKEY_EV_ORIG_KEY_START + scancode, NULL); 2313 2274 } 2314 2275 2315 2276 static void hotkey_read_nvram(struct tp_nvram_state *n, const u32 m) ··· 2614 2575 { 2615 2576 } 2616 2577 2578 + static void hotkey_poll_stop_sync(void) 2579 + { 2580 + } 2617 2581 #endif /* CONFIG_THINKPAD_ACPI_HOTKEY_POLL */ 2618 2582 2619 2583 static int hotkey_inputdev_open(struct input_dev *dev) ··· 2721 2679 struct device_attribute *attr, 2722 2680 char *buf) 2723 2681 { 2724 - return sprintf(buf, "0\n"); 2682 + return sysfs_emit(buf, "0\n"); 2725 2683 } 2726 2684 2727 2685 static DEVICE_ATTR_RO(hotkey_bios_enabled); ··· 3086 3044 3087 3045 static void hotkey_exit(void) 3088 3046 { 3089 - #ifdef CONFIG_THINKPAD_ACPI_HOTKEY_POLL 3090 3047 mutex_lock(&hotkey_mutex); 3091 3048 hotkey_poll_stop_sync(); 3092 - mutex_unlock(&hotkey_mutex); 3093 - #endif 3094 3049 dbg_printk(TPACPI_DBG_EXIT | TPACPI_DBG_HKEY, 3095 3050 "restoring original HKEY status and mask\n"); 3096 3051 /* yes, there is a bitwise or below, we want the ··· 3096 3057 hotkey_mask_set(hotkey_orig_mask)) | 3097 3058 hotkey_status_set(false)) != 0) 3098 3059 pr_err("failed to restore hot key mask to BIOS defaults\n"); 3099 - } 3100 3060 3101 - static void __init hotkey_unmap(const unsigned int scancode) 3102 - { 3103 - if (hotkey_keycode_map[scancode] != KEY_RESERVED) { 3104 - clear_bit(hotkey_keycode_map[scancode], 3105 - tpacpi_inputdev->keybit); 3106 - hotkey_keycode_map[scancode] = KEY_RESERVED; 3107 - } 3061 + mutex_unlock(&hotkey_mutex); 3108 3062 } 3109 3063 3110 3064 /* ··· 3128 3096 TPACPI_Q_IBM('I', 'Z', TPACPI_HK_Q_INIMASK), /* X20, X21 */ 3129 3097 TPACPI_Q_IBM('1', 'D', TPACPI_HK_Q_INIMASK), /* X22, X23, X24 */ 3130 3098 }; 3131 - 3132 - typedef u16 tpacpi_keymap_entry_t; 3133 - typedef tpacpi_keymap_entry_t tpacpi_keymap_t[TPACPI_HOTKEY_MAP_LEN]; 3134 3099 3135 3100 static int hotkey_init_tablet_mode(void) 3136 3101 { ··· 3165 3136 return in_tablet_mode; 3166 3137 } 3167 3138 3139 + static const struct key_entry keymap_ibm[] __initconst = { 3140 + /* Original hotkey mappings translated scancodes 0x00 - 0x1f */ 3141 + { KE_KEY, TP_ACPI_HOTKEYSCAN_FNF1, { KEY_FN_F1 } }, 3142 + { KE_KEY, TP_ACPI_HOTKEYSCAN_FNF2, { KEY_BATTERY } }, 3143 + { KE_KEY, TP_ACPI_HOTKEYSCAN_FNF3, { KEY_COFFEE } }, 3144 + { KE_KEY, TP_ACPI_HOTKEYSCAN_FNF4, { KEY_SLEEP } }, 3145 + { KE_KEY, TP_ACPI_HOTKEYSCAN_FNF5, { KEY_WLAN } }, 3146 + { KE_KEY, TP_ACPI_HOTKEYSCAN_FNF6, { KEY_FN_F6 } }, 3147 + { KE_KEY, TP_ACPI_HOTKEYSCAN_FNF7, { KEY_SWITCHVIDEOMODE } }, 3148 + { KE_KEY, TP_ACPI_HOTKEYSCAN_FNF8, { KEY_FN_F8 } }, 3149 + { KE_KEY, TP_ACPI_HOTKEYSCAN_FNF9, { KEY_FN_F9 } }, 3150 + { KE_KEY, TP_ACPI_HOTKEYSCAN_FNF10, { KEY_FN_F10 } }, 3151 + { KE_KEY, TP_ACPI_HOTKEYSCAN_FNF11, { KEY_FN_F11 } }, 3152 + { KE_KEY, TP_ACPI_HOTKEYSCAN_FNF12, { KEY_SUSPEND } }, 3153 + /* Brightness: firmware always reacts, suppressed through hotkey_reserved_mask. */ 3154 + { KE_KEY, TP_ACPI_HOTKEYSCAN_FNHOME, { KEY_BRIGHTNESSUP } }, 3155 + { KE_KEY, TP_ACPI_HOTKEYSCAN_FNEND, { KEY_BRIGHTNESSDOWN } }, 3156 + /* Thinklight: firmware always reacts, suppressed through hotkey_reserved_mask. */ 3157 + { KE_KEY, TP_ACPI_HOTKEYSCAN_FNPAGEUP, { KEY_KBDILLUMTOGGLE } }, 3158 + { KE_KEY, TP_ACPI_HOTKEYSCAN_FNSPACE, { KEY_ZOOM } }, 3159 + /* 3160 + * Volume: firmware always reacts and reprograms the built-in *extra* mixer. 3161 + * Suppressed by default through hotkey_reserved_mask. 3162 + */ 3163 + { KE_KEY, TP_ACPI_HOTKEYSCAN_VOLUMEUP, { KEY_VOLUMEUP } }, 3164 + { KE_KEY, TP_ACPI_HOTKEYSCAN_VOLUMEDOWN, { KEY_VOLUMEDOWN } }, 3165 + { KE_KEY, TP_ACPI_HOTKEYSCAN_MUTE, { KEY_MUTE } }, 3166 + { KE_KEY, TP_ACPI_HOTKEYSCAN_THINKPAD, { KEY_VENDOR } }, 3167 + { KE_END } 3168 + }; 3169 + 3170 + static const struct key_entry keymap_lenovo[] __initconst = { 3171 + /* Original hotkey mappings translated scancodes 0x00 - 0x1f */ 3172 + { KE_KEY, TP_ACPI_HOTKEYSCAN_FNF1, { KEY_FN_F1 } }, 3173 + { KE_KEY, TP_ACPI_HOTKEYSCAN_FNF2, { KEY_COFFEE } }, 3174 + { KE_KEY, TP_ACPI_HOTKEYSCAN_FNF3, { KEY_BATTERY } }, 3175 + { KE_KEY, TP_ACPI_HOTKEYSCAN_FNF4, { KEY_SLEEP } }, 3176 + { KE_KEY, TP_ACPI_HOTKEYSCAN_FNF5, { KEY_WLAN } }, 3177 + { KE_KEY, TP_ACPI_HOTKEYSCAN_FNF6, { KEY_CAMERA, } }, 3178 + { KE_KEY, TP_ACPI_HOTKEYSCAN_FNF7, { KEY_SWITCHVIDEOMODE } }, 3179 + { KE_KEY, TP_ACPI_HOTKEYSCAN_FNF8, { KEY_FN_F8 } }, 3180 + { KE_KEY, TP_ACPI_HOTKEYSCAN_FNF9, { KEY_FN_F9 } }, 3181 + { KE_KEY, TP_ACPI_HOTKEYSCAN_FNF10, { KEY_FN_F10 } }, 3182 + { KE_KEY, TP_ACPI_HOTKEYSCAN_FNF11, { KEY_FN_F11 } }, 3183 + { KE_KEY, TP_ACPI_HOTKEYSCAN_FNF12, { KEY_SUSPEND } }, 3184 + /* 3185 + * These should be enabled --only-- when ACPI video is disabled and 3186 + * are handled in a special way by the init code. 3187 + */ 3188 + { KE_KEY, TP_ACPI_HOTKEYSCAN_FNHOME, { KEY_BRIGHTNESSUP } }, 3189 + { KE_KEY, TP_ACPI_HOTKEYSCAN_FNEND, { KEY_BRIGHTNESSDOWN } }, 3190 + /* Suppressed by default through hotkey_reserved_mask. */ 3191 + { KE_KEY, TP_ACPI_HOTKEYSCAN_FNPAGEUP, { KEY_KBDILLUMTOGGLE } }, 3192 + { KE_KEY, TP_ACPI_HOTKEYSCAN_FNSPACE, { KEY_ZOOM } }, 3193 + /* 3194 + * Volume: z60/z61, T60 (BIOS version?): firmware always reacts and 3195 + * reprograms the built-in *extra* mixer. 3196 + * T60?, T61, R60?, R61: firmware and EC tries to send these over 3197 + * the regular keyboard (not through tpacpi). There are still weird bugs 3198 + * re. MUTE. May cause the BIOS to interfere with the HDA mixer. 3199 + * Suppressed by default through hotkey_reserved_mask. 3200 + */ 3201 + { KE_KEY, TP_ACPI_HOTKEYSCAN_VOLUMEUP, { KEY_VOLUMEUP } }, 3202 + { KE_KEY, TP_ACPI_HOTKEYSCAN_VOLUMEDOWN, { KEY_VOLUMEDOWN } }, 3203 + { KE_KEY, TP_ACPI_HOTKEYSCAN_MUTE, { KEY_MUTE } }, 3204 + { KE_KEY, TP_ACPI_HOTKEYSCAN_THINKPAD, { KEY_VENDOR } }, 3205 + { KE_KEY, TP_ACPI_HOTKEYSCAN_MICMUTE, { KEY_MICMUTE } }, 3206 + { KE_KEY, TP_ACPI_HOTKEYSCAN_CONFIG, { KEY_CONFIG } }, 3207 + { KE_KEY, TP_ACPI_HOTKEYSCAN_SEARCH, { KEY_SEARCH } }, 3208 + { KE_KEY, TP_ACPI_HOTKEYSCAN_SCALE, { KEY_SCALE } }, 3209 + { KE_KEY, TP_ACPI_HOTKEYSCAN_FILE, { KEY_FILE } }, 3210 + /* Adaptive keyboard mappings for Carbon X1 2014 translated scancodes 0x20 - 0x33 */ 3211 + { KE_KEY, TP_ACPI_HOTKEYSCAN_MUTE2, { KEY_RESERVED } }, 3212 + { KE_KEY, TP_ACPI_HOTKEYSCAN_BRIGHTNESS_ZERO, { KEY_BRIGHTNESS_MIN } }, 3213 + { KE_KEY, TP_ACPI_HOTKEYSCAN_CLIPPING_TOOL, { KEY_SELECTIVE_SCREENSHOT } }, 3214 + { KE_KEY, TP_ACPI_HOTKEYSCAN_CLOUD, { KEY_XFER } }, 3215 + { KE_KEY, TP_ACPI_HOTKEYSCAN_UNK9, { KEY_RESERVED } }, 3216 + { KE_KEY, TP_ACPI_HOTKEYSCAN_VOICE, { KEY_VOICECOMMAND } }, 3217 + { KE_KEY, TP_ACPI_HOTKEYSCAN_UNK10, { KEY_RESERVED } }, 3218 + { KE_KEY, TP_ACPI_HOTKEYSCAN_GESTURES, { KEY_RESERVED } }, 3219 + { KE_KEY, TP_ACPI_HOTKEYSCAN_UNK11, { KEY_RESERVED } }, 3220 + { KE_KEY, TP_ACPI_HOTKEYSCAN_UNK12, { KEY_RESERVED } }, 3221 + { KE_KEY, TP_ACPI_HOTKEYSCAN_UNK13, { KEY_RESERVED } }, 3222 + { KE_KEY, TP_ACPI_HOTKEYSCAN_CONFIG2, { KEY_CONFIG } }, 3223 + { KE_KEY, TP_ACPI_HOTKEYSCAN_NEW_TAB, { KEY_RESERVED } }, 3224 + { KE_KEY, TP_ACPI_HOTKEYSCAN_RELOAD, { KEY_REFRESH } }, 3225 + { KE_KEY, TP_ACPI_HOTKEYSCAN_BACK, { KEY_BACK } }, 3226 + { KE_KEY, TP_ACPI_HOTKEYSCAN_MIC_DOWN, { KEY_RESERVED } }, 3227 + { KE_KEY, TP_ACPI_HOTKEYSCAN_MIC_UP, { KEY_RESERVED } }, 3228 + { KE_KEY, TP_ACPI_HOTKEYSCAN_MIC_CANCELLATION, { KEY_RESERVED } }, 3229 + { KE_KEY, TP_ACPI_HOTKEYSCAN_CAMERA_MODE, { KEY_RESERVED } }, 3230 + { KE_KEY, TP_ACPI_HOTKEYSCAN_ROTATE_DISPLAY, { KEY_RESERVED } }, 3231 + /* Extended hotkeys mappings translated scancodes 0x34 - 0x4d */ 3232 + { KE_KEY, TP_ACPI_HOTKEYSCAN_STAR, { KEY_BOOKMARKS } }, 3233 + { KE_KEY, TP_ACPI_HOTKEYSCAN_CLIPPING_TOOL2, { KEY_SELECTIVE_SCREENSHOT } }, 3234 + { KE_KEY, TP_ACPI_HOTKEYSCAN_CALCULATOR, { KEY_CALC } }, 3235 + { KE_KEY, TP_ACPI_HOTKEYSCAN_BLUETOOTH, { KEY_BLUETOOTH } }, 3236 + { KE_KEY, TP_ACPI_HOTKEYSCAN_KEYBOARD, { KEY_KEYBOARD } }, 3237 + /* Used by "Lenovo Quick Clean" */ 3238 + { KE_KEY, TP_ACPI_HOTKEYSCAN_FN_RIGHT_SHIFT, { KEY_FN_RIGHT_SHIFT } }, 3239 + { KE_KEY, TP_ACPI_HOTKEYSCAN_NOTIFICATION_CENTER, { KEY_NOTIFICATION_CENTER } }, 3240 + { KE_KEY, TP_ACPI_HOTKEYSCAN_PICKUP_PHONE, { KEY_PICKUP_PHONE } }, 3241 + { KE_KEY, TP_ACPI_HOTKEYSCAN_HANGUP_PHONE, { KEY_HANGUP_PHONE } }, 3242 + /* 3243 + * All mapping below are for raw untranslated hkey event codes mapped directly 3244 + * after switching to sparse keymap support. The mappings above use translated 3245 + * scancodes to preserve uAPI compatibility, see tpacpi_input_send_key(). 3246 + */ 3247 + { KE_KEY, 0x131d, { KEY_VENDOR } }, /* System debug info, similar to old ThinkPad key */ 3248 + { KE_KEY, TP_HKEY_EV_TRACK_DOUBLETAP /* 0x8036 */, { KEY_PROG4 } }, 3249 + { KE_END } 3250 + }; 3251 + 3168 3252 static int __init hotkey_init(struct ibm_init_struct *iibm) 3169 3253 { 3170 - /* Requirements for changing the default keymaps: 3171 - * 3172 - * 1. Many of the keys are mapped to KEY_RESERVED for very 3173 - * good reasons. Do not change them unless you have deep 3174 - * knowledge on the IBM and Lenovo ThinkPad firmware for 3175 - * the various ThinkPad models. The driver behaves 3176 - * differently for KEY_RESERVED: such keys have their 3177 - * hot key mask *unset* in mask_recommended, and also 3178 - * in the initial hot key mask programmed into the 3179 - * firmware at driver load time, which means the firm- 3180 - * ware may react very differently if you change them to 3181 - * something else; 3182 - * 3183 - * 2. You must be subscribed to the linux-thinkpad and 3184 - * ibm-acpi-devel mailing lists, and you should read the 3185 - * list archives since 2007 if you want to change the 3186 - * keymaps. This requirement exists so that you will 3187 - * know the past history of problems with the thinkpad- 3188 - * acpi driver keymaps, and also that you will be 3189 - * listening to any bug reports; 3190 - * 3191 - * 3. Do not send thinkpad-acpi specific patches directly to 3192 - * for merging, *ever*. Send them to the linux-acpi 3193 - * mailinglist for comments. Merging is to be done only 3194 - * through acpi-test and the ACPI maintainer. 3195 - * 3196 - * If the above is too much to ask, don't change the keymap. 3197 - * Ask the thinkpad-acpi maintainer to do it, instead. 3198 - */ 3199 - 3200 3254 enum keymap_index { 3201 3255 TPACPI_KEYMAP_IBM_GENERIC = 0, 3202 3256 TPACPI_KEYMAP_LENOVO_GENERIC, 3203 - }; 3204 - 3205 - static const tpacpi_keymap_t tpacpi_keymaps[] __initconst = { 3206 - /* Generic keymap for IBM ThinkPads */ 3207 - [TPACPI_KEYMAP_IBM_GENERIC] = { 3208 - /* Scan Codes 0x00 to 0x0B: ACPI HKEY FN+F1..F12 */ 3209 - KEY_FN_F1, KEY_BATTERY, KEY_COFFEE, KEY_SLEEP, 3210 - KEY_WLAN, KEY_FN_F6, KEY_SWITCHVIDEOMODE, KEY_FN_F8, 3211 - KEY_FN_F9, KEY_FN_F10, KEY_FN_F11, KEY_SUSPEND, 3212 - 3213 - /* Scan codes 0x0C to 0x1F: Other ACPI HKEY hot keys */ 3214 - KEY_UNKNOWN, /* 0x0C: FN+BACKSPACE */ 3215 - KEY_UNKNOWN, /* 0x0D: FN+INSERT */ 3216 - KEY_UNKNOWN, /* 0x0E: FN+DELETE */ 3217 - 3218 - /* brightness: firmware always reacts to them */ 3219 - KEY_RESERVED, /* 0x0F: FN+HOME (brightness up) */ 3220 - KEY_RESERVED, /* 0x10: FN+END (brightness down) */ 3221 - 3222 - /* Thinklight: firmware always react to it */ 3223 - KEY_RESERVED, /* 0x11: FN+PGUP (thinklight toggle) */ 3224 - 3225 - KEY_UNKNOWN, /* 0x12: FN+PGDOWN */ 3226 - KEY_ZOOM, /* 0x13: FN+SPACE (zoom) */ 3227 - 3228 - /* Volume: firmware always react to it and reprograms 3229 - * the built-in *extra* mixer. Never map it to control 3230 - * another mixer by default. */ 3231 - KEY_RESERVED, /* 0x14: VOLUME UP */ 3232 - KEY_RESERVED, /* 0x15: VOLUME DOWN */ 3233 - KEY_RESERVED, /* 0x16: MUTE */ 3234 - 3235 - KEY_VENDOR, /* 0x17: Thinkpad/AccessIBM/Lenovo */ 3236 - 3237 - /* (assignments unknown, please report if found) */ 3238 - KEY_UNKNOWN, KEY_UNKNOWN, KEY_UNKNOWN, KEY_UNKNOWN, 3239 - KEY_UNKNOWN, KEY_UNKNOWN, KEY_UNKNOWN, KEY_UNKNOWN, 3240 - 3241 - /* No assignments, only used for Adaptive keyboards. */ 3242 - KEY_UNKNOWN, KEY_UNKNOWN, KEY_UNKNOWN, KEY_UNKNOWN, 3243 - KEY_UNKNOWN, KEY_UNKNOWN, KEY_UNKNOWN, KEY_UNKNOWN, 3244 - KEY_UNKNOWN, KEY_UNKNOWN, KEY_UNKNOWN, KEY_UNKNOWN, 3245 - KEY_UNKNOWN, KEY_UNKNOWN, KEY_UNKNOWN, KEY_UNKNOWN, 3246 - KEY_UNKNOWN, KEY_UNKNOWN, KEY_UNKNOWN, 3247 - 3248 - /* No assignment, used for newer Lenovo models */ 3249 - KEY_UNKNOWN, KEY_UNKNOWN, KEY_UNKNOWN, KEY_UNKNOWN, 3250 - KEY_UNKNOWN, KEY_UNKNOWN, KEY_UNKNOWN, KEY_UNKNOWN, 3251 - KEY_UNKNOWN, KEY_UNKNOWN, KEY_UNKNOWN, KEY_UNKNOWN, 3252 - KEY_UNKNOWN, KEY_UNKNOWN, KEY_UNKNOWN, KEY_UNKNOWN, 3253 - KEY_UNKNOWN, KEY_UNKNOWN, KEY_UNKNOWN, KEY_UNKNOWN, 3254 - KEY_UNKNOWN, KEY_UNKNOWN 3255 - 3256 - }, 3257 - 3258 - /* Generic keymap for Lenovo ThinkPads */ 3259 - [TPACPI_KEYMAP_LENOVO_GENERIC] = { 3260 - /* Scan Codes 0x00 to 0x0B: ACPI HKEY FN+F1..F12 */ 3261 - KEY_FN_F1, KEY_COFFEE, KEY_BATTERY, KEY_SLEEP, 3262 - KEY_WLAN, KEY_CAMERA, KEY_SWITCHVIDEOMODE, KEY_FN_F8, 3263 - KEY_FN_F9, KEY_FN_F10, KEY_FN_F11, KEY_SUSPEND, 3264 - 3265 - /* Scan codes 0x0C to 0x1F: Other ACPI HKEY hot keys */ 3266 - KEY_UNKNOWN, /* 0x0C: FN+BACKSPACE */ 3267 - KEY_UNKNOWN, /* 0x0D: FN+INSERT */ 3268 - KEY_UNKNOWN, /* 0x0E: FN+DELETE */ 3269 - 3270 - /* These should be enabled --only-- when ACPI video 3271 - * is disabled (i.e. in "vendor" mode), and are handled 3272 - * in a special way by the init code */ 3273 - KEY_BRIGHTNESSUP, /* 0x0F: FN+HOME (brightness up) */ 3274 - KEY_BRIGHTNESSDOWN, /* 0x10: FN+END (brightness down) */ 3275 - 3276 - KEY_RESERVED, /* 0x11: FN+PGUP (thinklight toggle) */ 3277 - 3278 - KEY_UNKNOWN, /* 0x12: FN+PGDOWN */ 3279 - KEY_ZOOM, /* 0x13: FN+SPACE (zoom) */ 3280 - 3281 - /* Volume: z60/z61, T60 (BIOS version?): firmware always 3282 - * react to it and reprograms the built-in *extra* mixer. 3283 - * Never map it to control another mixer by default. 3284 - * 3285 - * T60?, T61, R60?, R61: firmware and EC tries to send 3286 - * these over the regular keyboard, so these are no-ops, 3287 - * but there are still weird bugs re. MUTE, so do not 3288 - * change unless you get test reports from all Lenovo 3289 - * models. May cause the BIOS to interfere with the 3290 - * HDA mixer. 3291 - */ 3292 - KEY_RESERVED, /* 0x14: VOLUME UP */ 3293 - KEY_RESERVED, /* 0x15: VOLUME DOWN */ 3294 - KEY_RESERVED, /* 0x16: MUTE */ 3295 - 3296 - KEY_VENDOR, /* 0x17: Thinkpad/AccessIBM/Lenovo */ 3297 - 3298 - /* (assignments unknown, please report if found) */ 3299 - KEY_UNKNOWN, KEY_UNKNOWN, 3300 - 3301 - /* 3302 - * The mic mute button only sends 0x1a. It does not 3303 - * automatically mute the mic or change the mute light. 3304 - */ 3305 - KEY_MICMUTE, /* 0x1a: Mic mute (since ?400 or so) */ 3306 - 3307 - /* (assignments unknown, please report if found) */ 3308 - KEY_UNKNOWN, 3309 - 3310 - /* Extra keys in use since the X240 / T440 / T540 */ 3311 - KEY_CONFIG, KEY_SEARCH, KEY_SCALE, KEY_FILE, 3312 - 3313 - /* 3314 - * These are the adaptive keyboard keycodes for Carbon X1 2014. 3315 - * The first item in this list is the Mute button which is 3316 - * emitted with 0x103 through 3317 - * adaptive_keyboard_hotkey_notify_hotkey() when the sound 3318 - * symbol is held. 3319 - * We'll need to offset those by 0x20. 3320 - */ 3321 - KEY_RESERVED, /* Mute held, 0x103 */ 3322 - KEY_BRIGHTNESS_MIN, /* Backlight off */ 3323 - KEY_RESERVED, /* Clipping tool */ 3324 - KEY_RESERVED, /* Cloud */ 3325 - KEY_RESERVED, 3326 - KEY_VOICECOMMAND, /* Voice */ 3327 - KEY_RESERVED, 3328 - KEY_RESERVED, /* Gestures */ 3329 - KEY_RESERVED, 3330 - KEY_RESERVED, 3331 - KEY_RESERVED, 3332 - KEY_CONFIG, /* Settings */ 3333 - KEY_RESERVED, /* New tab */ 3334 - KEY_REFRESH, /* Reload */ 3335 - KEY_BACK, /* Back */ 3336 - KEY_RESERVED, /* Microphone down */ 3337 - KEY_RESERVED, /* Microphone up */ 3338 - KEY_RESERVED, /* Microphone cancellation */ 3339 - KEY_RESERVED, /* Camera mode */ 3340 - KEY_RESERVED, /* Rotate display, 0x116 */ 3341 - 3342 - /* 3343 - * These are found in 2017 models (e.g. T470s, X270). 3344 - * The lowest known value is 0x311, which according to 3345 - * the manual should launch a user defined favorite 3346 - * application. 3347 - * 3348 - * The offset for these is TP_ACPI_HOTKEYSCAN_EXTENDED_START, 3349 - * corresponding to 0x34. 3350 - */ 3351 - 3352 - /* (assignments unknown, please report if found) */ 3353 - KEY_UNKNOWN, KEY_UNKNOWN, KEY_UNKNOWN, KEY_UNKNOWN, 3354 - KEY_UNKNOWN, KEY_UNKNOWN, KEY_UNKNOWN, KEY_UNKNOWN, 3355 - KEY_UNKNOWN, KEY_UNKNOWN, KEY_UNKNOWN, KEY_UNKNOWN, 3356 - KEY_UNKNOWN, KEY_UNKNOWN, KEY_UNKNOWN, KEY_UNKNOWN, 3357 - KEY_UNKNOWN, 3358 - 3359 - KEY_BOOKMARKS, /* Favorite app, 0x311 */ 3360 - KEY_SELECTIVE_SCREENSHOT, /* Clipping tool */ 3361 - KEY_CALC, /* Calculator (above numpad, P52) */ 3362 - KEY_BLUETOOTH, /* Bluetooth */ 3363 - KEY_KEYBOARD, /* Keyboard, 0x315 */ 3364 - KEY_FN_RIGHT_SHIFT, /* Fn + right Shift */ 3365 - KEY_NOTIFICATION_CENTER, /* Notification Center */ 3366 - KEY_PICKUP_PHONE, /* Answer incoming call */ 3367 - KEY_HANGUP_PHONE, /* Decline incoming call */ 3368 - }, 3369 3257 }; 3370 3258 3371 3259 static const struct tpacpi_quirk tpacpi_keymap_qtable[] __initconst = { ··· 3299 3353 }, 3300 3354 }; 3301 3355 3302 - #define TPACPI_HOTKEY_MAP_SIZE sizeof(tpacpi_keymap_t) 3303 - #define TPACPI_HOTKEY_MAP_TYPESIZE sizeof(tpacpi_keymap_entry_t) 3304 - 3305 - int res, i; 3306 - int status; 3307 - int hkeyv; 3356 + unsigned long keymap_id, quirks; 3357 + const struct key_entry *keymap; 3308 3358 bool radiosw_state = false; 3309 3359 bool tabletsw_state = false; 3310 - 3311 - unsigned long quirks; 3312 - unsigned long keymap_id; 3360 + int hkeyv, res, status; 3313 3361 3314 3362 vdbg_printk(TPACPI_DBG_INIT | TPACPI_DBG_HKEY, 3315 3363 "initializing hotkey subdriver\n"); ··· 3443 3503 /* Set up key map */ 3444 3504 keymap_id = tpacpi_check_quirks(tpacpi_keymap_qtable, 3445 3505 ARRAY_SIZE(tpacpi_keymap_qtable)); 3446 - BUG_ON(keymap_id >= ARRAY_SIZE(tpacpi_keymaps)); 3447 3506 dbg_printk(TPACPI_DBG_INIT | TPACPI_DBG_HKEY, 3448 3507 "using keymap number %lu\n", keymap_id); 3449 3508 3450 - hotkey_keycode_map = kmemdup(&tpacpi_keymaps[keymap_id], 3451 - TPACPI_HOTKEY_MAP_SIZE, GFP_KERNEL); 3452 - if (!hotkey_keycode_map) { 3453 - pr_err("failed to allocate memory for key map\n"); 3454 - return -ENOMEM; 3509 + /* Keys which should be reserved on both IBM and Lenovo models */ 3510 + hotkey_reserved_mask = TP_ACPI_HKEY_KBD_LIGHT_MASK | 3511 + TP_ACPI_HKEY_VOLUP_MASK | 3512 + TP_ACPI_HKEY_VOLDWN_MASK | 3513 + TP_ACPI_HKEY_MUTE_MASK; 3514 + /* 3515 + * Reserve brightness up/down unconditionally on IBM models, on Lenovo 3516 + * models these are disabled based on acpi_video_get_backlight_type(). 3517 + */ 3518 + if (keymap_id == TPACPI_KEYMAP_IBM_GENERIC) { 3519 + hotkey_reserved_mask |= TP_ACPI_HKEY_BRGHTUP_MASK | 3520 + TP_ACPI_HKEY_BRGHTDWN_MASK; 3521 + keymap = keymap_ibm; 3522 + } else { 3523 + keymap = keymap_lenovo; 3455 3524 } 3456 3525 3457 - input_set_capability(tpacpi_inputdev, EV_MSC, MSC_SCAN); 3458 - tpacpi_inputdev->keycodesize = TPACPI_HOTKEY_MAP_TYPESIZE; 3459 - tpacpi_inputdev->keycodemax = TPACPI_HOTKEY_MAP_LEN; 3460 - tpacpi_inputdev->keycode = hotkey_keycode_map; 3461 - for (i = 0; i < TPACPI_HOTKEY_MAP_LEN; i++) { 3462 - if (hotkey_keycode_map[i] != KEY_RESERVED) { 3463 - input_set_capability(tpacpi_inputdev, EV_KEY, 3464 - hotkey_keycode_map[i]); 3465 - } else { 3466 - if (i < sizeof(hotkey_reserved_mask)*8) 3467 - hotkey_reserved_mask |= 1 << i; 3468 - } 3469 - } 3526 + res = sparse_keymap_setup(tpacpi_inputdev, keymap, NULL); 3527 + if (res) 3528 + return res; 3470 3529 3471 3530 if (tp_features.hotkey_wlsw) { 3472 3531 input_set_capability(tpacpi_inputdev, EV_SW, SW_RFKILL_ALL); ··· 3488 3549 /* Disable brightness up/down on Lenovo thinkpads when 3489 3550 * ACPI is handling them, otherwise it is plain impossible 3490 3551 * for userspace to do something even remotely sane */ 3491 - hotkey_reserved_mask |= 3492 - (1 << TP_ACPI_HOTKEYSCAN_FNHOME) 3493 - | (1 << TP_ACPI_HOTKEYSCAN_FNEND); 3494 - hotkey_unmap(TP_ACPI_HOTKEYSCAN_FNHOME); 3495 - hotkey_unmap(TP_ACPI_HOTKEYSCAN_FNEND); 3552 + hotkey_reserved_mask |= TP_ACPI_HKEY_BRGHTUP_MASK | 3553 + TP_ACPI_HKEY_BRGHTDWN_MASK; 3496 3554 } 3497 3555 3498 3556 #ifdef CONFIG_THINKPAD_ACPI_HOTKEY_POLL ··· 3529 3593 3530 3594 hotkey_poll_setup_safe(true); 3531 3595 3596 + /* Enable doubletap by default */ 3597 + tp_features.trackpoint_doubletap = 1; 3598 + 3532 3599 return 0; 3533 3600 } 3534 3601 ··· 3548 3609 WEB_CONFERENCE_MODE = 3, */ 3549 3610 FUNCTION_MODE 3550 3611 }; 3551 - 3552 - #define DFR_CHANGE_ROW 0x101 3553 - #define DFR_SHOW_QUICKVIEW_ROW 0x102 3554 - #define FIRST_ADAPTIVE_KEY 0x103 3555 3612 3556 3613 /* press Fn key a while second, it will switch to Function Mode. Then 3557 3614 * release Fn key, previous mode be restored. ··· 3599 3664 return adaptive_keyboard_modes[i]; 3600 3665 } 3601 3666 3602 - static bool adaptive_keyboard_hotkey_notify_hotkey(unsigned int scancode) 3667 + static void adaptive_keyboard_change_row(void) 3603 3668 { 3604 - int current_mode = 0; 3605 - int new_mode = 0; 3606 - int keycode; 3669 + int mode; 3607 3670 3608 - switch (scancode) { 3609 - case DFR_CHANGE_ROW: 3610 - if (adaptive_keyboard_mode_is_saved) { 3611 - new_mode = adaptive_keyboard_prev_mode; 3612 - adaptive_keyboard_mode_is_saved = false; 3613 - } else { 3614 - current_mode = adaptive_keyboard_get_mode(); 3615 - if (current_mode < 0) 3616 - return false; 3617 - new_mode = adaptive_keyboard_get_next_mode( 3618 - current_mode); 3619 - } 3620 - 3621 - if (adaptive_keyboard_set_mode(new_mode) < 0) 3622 - return false; 3623 - 3624 - return true; 3625 - 3626 - case DFR_SHOW_QUICKVIEW_ROW: 3627 - current_mode = adaptive_keyboard_get_mode(); 3628 - if (current_mode < 0) 3629 - return false; 3630 - 3631 - adaptive_keyboard_prev_mode = current_mode; 3632 - adaptive_keyboard_mode_is_saved = true; 3633 - 3634 - if (adaptive_keyboard_set_mode (FUNCTION_MODE) < 0) 3635 - return false; 3636 - return true; 3637 - 3638 - default: 3639 - if (scancode < FIRST_ADAPTIVE_KEY || 3640 - scancode >= FIRST_ADAPTIVE_KEY + 3641 - TP_ACPI_HOTKEYSCAN_EXTENDED_START - 3642 - TP_ACPI_HOTKEYSCAN_ADAPTIVE_START) { 3643 - pr_info("Unhandled adaptive keyboard key: 0x%x\n", 3644 - scancode); 3645 - return false; 3646 - } 3647 - keycode = hotkey_keycode_map[scancode - FIRST_ADAPTIVE_KEY + 3648 - TP_ACPI_HOTKEYSCAN_ADAPTIVE_START]; 3649 - if (keycode != KEY_RESERVED) { 3650 - mutex_lock(&tpacpi_inputdev_send_mutex); 3651 - 3652 - input_report_key(tpacpi_inputdev, keycode, 1); 3653 - input_sync(tpacpi_inputdev); 3654 - 3655 - input_report_key(tpacpi_inputdev, keycode, 0); 3656 - input_sync(tpacpi_inputdev); 3657 - 3658 - mutex_unlock(&tpacpi_inputdev_send_mutex); 3659 - } 3660 - return true; 3671 + if (adaptive_keyboard_mode_is_saved) { 3672 + mode = adaptive_keyboard_prev_mode; 3673 + adaptive_keyboard_mode_is_saved = false; 3674 + } else { 3675 + mode = adaptive_keyboard_get_mode(); 3676 + if (mode < 0) 3677 + return; 3678 + mode = adaptive_keyboard_get_next_mode(mode); 3661 3679 } 3680 + 3681 + adaptive_keyboard_set_mode(mode); 3662 3682 } 3663 3683 3664 - static bool hotkey_notify_extended_hotkey(const u32 hkey) 3684 + static void adaptive_keyboard_s_quickview_row(void) 3665 3685 { 3666 - unsigned int scancode; 3686 + int mode; 3667 3687 3668 - switch (hkey) { 3669 - case TP_HKEY_EV_PRIVACYGUARD_TOGGLE: 3670 - case TP_HKEY_EV_AMT_TOGGLE: 3671 - case TP_HKEY_EV_PROFILE_TOGGLE: 3672 - tpacpi_driver_event(hkey); 3673 - return true; 3674 - } 3688 + mode = adaptive_keyboard_get_mode(); 3689 + if (mode < 0) 3690 + return; 3675 3691 3676 - /* Extended keycodes start at 0x300 and our offset into the map 3677 - * TP_ACPI_HOTKEYSCAN_EXTENDED_START. The calculated scancode 3678 - * will be positive, but might not be in the correct range. 3679 - */ 3680 - scancode = (hkey & 0xfff) - (0x300 - TP_ACPI_HOTKEYSCAN_EXTENDED_START); 3681 - if (scancode >= TP_ACPI_HOTKEYSCAN_EXTENDED_START && 3682 - scancode < TPACPI_HOTKEY_MAP_LEN) { 3683 - tpacpi_input_send_key(scancode); 3684 - return true; 3685 - } 3692 + adaptive_keyboard_prev_mode = mode; 3693 + adaptive_keyboard_mode_is_saved = true; 3686 3694 3687 - return false; 3695 + adaptive_keyboard_set_mode(FUNCTION_MODE); 3688 3696 } 3689 3697 3690 - static bool hotkey_notify_hotkey(const u32 hkey, 3691 - bool *send_acpi_ev, 3692 - bool *ignore_acpi_ev) 3698 + /* 0x1000-0x1FFF: key presses */ 3699 + static bool hotkey_notify_hotkey(const u32 hkey, bool *send_acpi_ev) 3693 3700 { 3694 - /* 0x1000-0x1FFF: key presses */ 3695 - unsigned int scancode = hkey & 0xfff; 3696 - *send_acpi_ev = true; 3697 - *ignore_acpi_ev = false; 3701 + /* Never send ACPI netlink events for original hotkeys (hkey: 0x1001 - 0x1020) */ 3702 + if (hkey >= TP_HKEY_EV_ORIG_KEY_START && hkey <= TP_HKEY_EV_ORIG_KEY_END) { 3703 + *send_acpi_ev = false; 3698 3704 3699 - /* 3700 - * Original events are in the 0x10XX range, the adaptive keyboard 3701 - * found in 2014 X1 Carbon emits events are of 0x11XX. In 2017 3702 - * models, additional keys are emitted through 0x13XX. 3703 - */ 3704 - switch ((hkey >> 8) & 0xf) { 3705 - case 0: 3706 - if (scancode > 0 && 3707 - scancode <= TP_ACPI_HOTKEYSCAN_ADAPTIVE_START) { 3708 - /* HKEY event 0x1001 is scancode 0x00 */ 3709 - scancode--; 3710 - if (!(hotkey_source_mask & (1 << scancode))) { 3711 - tpacpi_input_send_key_masked(scancode); 3712 - *send_acpi_ev = false; 3713 - } else { 3714 - *ignore_acpi_ev = true; 3715 - } 3705 + /* Original hotkeys may be polled from NVRAM instead */ 3706 + unsigned int scancode = hkey - TP_HKEY_EV_ORIG_KEY_START; 3707 + if (hotkey_source_mask & (1 << scancode)) 3716 3708 return true; 3717 - } 3718 - break; 3719 - 3720 - case 1: 3721 - return adaptive_keyboard_hotkey_notify_hotkey(scancode); 3722 - 3723 - case 3: 3724 - return hotkey_notify_extended_hotkey(hkey); 3725 3709 } 3726 3710 3727 - return false; 3711 + return tpacpi_input_send_key(hkey, send_acpi_ev); 3728 3712 } 3729 3713 3730 - static bool hotkey_notify_wakeup(const u32 hkey, 3731 - bool *send_acpi_ev, 3732 - bool *ignore_acpi_ev) 3714 + /* 0x2000-0x2FFF: Wakeup reason */ 3715 + static bool hotkey_notify_wakeup(const u32 hkey, bool *send_acpi_ev) 3733 3716 { 3734 - /* 0x2000-0x2FFF: Wakeup reason */ 3735 - *send_acpi_ev = true; 3736 - *ignore_acpi_ev = false; 3737 - 3738 3717 switch (hkey) { 3739 3718 case TP_HKEY_EV_WKUP_S3_UNDOCK: /* suspend, undock */ 3740 3719 case TP_HKEY_EV_WKUP_S4_UNDOCK: /* hibernation, undock */ 3741 3720 hotkey_wakeup_reason = TP_ACPI_WAKEUP_UNDOCK; 3742 - *ignore_acpi_ev = true; 3721 + *send_acpi_ev = false; 3743 3722 break; 3744 3723 3745 3724 case TP_HKEY_EV_WKUP_S3_BAYEJ: /* suspend, bay eject */ 3746 3725 case TP_HKEY_EV_WKUP_S4_BAYEJ: /* hibernation, bay eject */ 3747 3726 hotkey_wakeup_reason = TP_ACPI_WAKEUP_BAYEJ; 3748 - *ignore_acpi_ev = true; 3727 + *send_acpi_ev = false; 3749 3728 break; 3750 3729 3751 3730 case TP_HKEY_EV_WKUP_S3_BATLOW: /* Battery on critical low level/S3 */ ··· 3681 3832 return true; 3682 3833 } 3683 3834 3684 - static bool hotkey_notify_dockevent(const u32 hkey, 3685 - bool *send_acpi_ev, 3686 - bool *ignore_acpi_ev) 3835 + /* 0x4000-0x4FFF: dock-related events */ 3836 + static bool hotkey_notify_dockevent(const u32 hkey, bool *send_acpi_ev) 3687 3837 { 3688 - /* 0x4000-0x4FFF: dock-related events */ 3689 - *send_acpi_ev = true; 3690 - *ignore_acpi_ev = false; 3691 - 3692 3838 switch (hkey) { 3693 3839 case TP_HKEY_EV_UNDOCK_ACK: 3694 3840 /* ACPI undock operation completed after wakeup */ ··· 3713 3869 case TP_HKEY_EV_KBD_COVER_ATTACH: 3714 3870 case TP_HKEY_EV_KBD_COVER_DETACH: 3715 3871 *send_acpi_ev = false; 3716 - *ignore_acpi_ev = true; 3717 3872 return true; 3718 3873 3719 3874 default: ··· 3720 3877 } 3721 3878 } 3722 3879 3723 - static bool hotkey_notify_usrevent(const u32 hkey, 3724 - bool *send_acpi_ev, 3725 - bool *ignore_acpi_ev) 3880 + /* 0x5000-0x5FFF: human interface helpers */ 3881 + static bool hotkey_notify_usrevent(const u32 hkey, bool *send_acpi_ev) 3726 3882 { 3727 - /* 0x5000-0x5FFF: human interface helpers */ 3728 - *send_acpi_ev = true; 3729 - *ignore_acpi_ev = false; 3730 - 3731 3883 switch (hkey) { 3732 3884 case TP_HKEY_EV_PEN_INSERTED: /* X61t: tablet pen inserted into bay */ 3733 3885 case TP_HKEY_EV_PEN_REMOVED: /* X61t: tablet pen removed from bay */ ··· 3739 3901 case TP_HKEY_EV_LID_OPEN: /* Lid opened */ 3740 3902 case TP_HKEY_EV_BRGHT_CHANGED: /* brightness changed */ 3741 3903 /* do not propagate these events */ 3742 - *ignore_acpi_ev = true; 3904 + *send_acpi_ev = false; 3743 3905 return true; 3744 3906 3745 3907 default: ··· 3750 3912 static void thermal_dump_all_sensors(void); 3751 3913 static void palmsensor_refresh(void); 3752 3914 3753 - static bool hotkey_notify_6xxx(const u32 hkey, 3754 - bool *send_acpi_ev, 3755 - bool *ignore_acpi_ev) 3915 + /* 0x6000-0x6FFF: thermal alarms/notices and keyboard events */ 3916 + static bool hotkey_notify_6xxx(const u32 hkey, bool *send_acpi_ev) 3756 3917 { 3757 - /* 0x6000-0x6FFF: thermal alarms/notices and keyboard events */ 3758 - *send_acpi_ev = true; 3759 - *ignore_acpi_ev = false; 3760 - 3761 3918 switch (hkey) { 3762 3919 case TP_HKEY_EV_THM_TABLE_CHANGED: 3763 3920 pr_debug("EC reports: Thermal Table has changed\n"); ··· 3798 3965 /* key press events, we just ignore them as long as the EC 3799 3966 * is still reporting them in the normal keyboard stream */ 3800 3967 *send_acpi_ev = false; 3801 - *ignore_acpi_ev = true; 3802 3968 return true; 3803 3969 3804 3970 case TP_HKEY_EV_KEY_FN_ESC: 3805 3971 /* Get the media key status to force the status LED to update */ 3806 3972 acpi_evalf(hkey_handle, NULL, "GMKS", "v"); 3807 3973 *send_acpi_ev = false; 3808 - *ignore_acpi_ev = true; 3809 3974 return true; 3810 3975 3811 3976 case TP_HKEY_EV_TABLET_CHANGED: ··· 3827 3996 return true; 3828 3997 } 3829 3998 3999 + static bool hotkey_notify_8xxx(const u32 hkey, bool *send_acpi_ev) 4000 + { 4001 + switch (hkey) { 4002 + case TP_HKEY_EV_TRACK_DOUBLETAP: 4003 + if (tp_features.trackpoint_doubletap) 4004 + tpacpi_input_send_key(hkey, send_acpi_ev); 4005 + 4006 + return true; 4007 + default: 4008 + return false; 4009 + } 4010 + } 4011 + 3830 4012 static void hotkey_notify(struct ibm_struct *ibm, u32 event) 3831 4013 { 3832 4014 u32 hkey; 3833 4015 bool send_acpi_ev; 3834 - bool ignore_acpi_ev; 3835 4016 bool known_ev; 3836 4017 3837 4018 if (event != 0x80) { ··· 3868 4025 } 3869 4026 3870 4027 send_acpi_ev = true; 3871 - ignore_acpi_ev = false; 4028 + known_ev = false; 3872 4029 3873 4030 switch (hkey >> 12) { 3874 4031 case 1: 3875 4032 /* 0x1000-0x1FFF: key presses */ 3876 - known_ev = hotkey_notify_hotkey(hkey, &send_acpi_ev, 3877 - &ignore_acpi_ev); 4033 + known_ev = hotkey_notify_hotkey(hkey, &send_acpi_ev); 3878 4034 break; 3879 4035 case 2: 3880 4036 /* 0x2000-0x2FFF: Wakeup reason */ 3881 - known_ev = hotkey_notify_wakeup(hkey, &send_acpi_ev, 3882 - &ignore_acpi_ev); 4037 + known_ev = hotkey_notify_wakeup(hkey, &send_acpi_ev); 3883 4038 break; 3884 4039 case 3: 3885 4040 /* 0x3000-0x3FFF: bay-related wakeups */ ··· 3892 4051 /* FIXME: kick libata if SATA link offline */ 3893 4052 known_ev = true; 3894 4053 break; 3895 - default: 3896 - known_ev = false; 3897 4054 } 3898 4055 break; 3899 4056 case 4: 3900 4057 /* 0x4000-0x4FFF: dock-related events */ 3901 - known_ev = hotkey_notify_dockevent(hkey, &send_acpi_ev, 3902 - &ignore_acpi_ev); 4058 + known_ev = hotkey_notify_dockevent(hkey, &send_acpi_ev); 3903 4059 break; 3904 4060 case 5: 3905 4061 /* 0x5000-0x5FFF: human interface helpers */ 3906 - known_ev = hotkey_notify_usrevent(hkey, &send_acpi_ev, 3907 - &ignore_acpi_ev); 4062 + known_ev = hotkey_notify_usrevent(hkey, &send_acpi_ev); 3908 4063 break; 3909 4064 case 6: 3910 4065 /* 0x6000-0x6FFF: thermal alarms/notices and 3911 4066 * keyboard events */ 3912 - known_ev = hotkey_notify_6xxx(hkey, &send_acpi_ev, 3913 - &ignore_acpi_ev); 4067 + known_ev = hotkey_notify_6xxx(hkey, &send_acpi_ev); 3914 4068 break; 3915 4069 case 7: 3916 4070 /* 0x7000-0x7FFF: misc */ 3917 4071 if (tp_features.hotkey_wlsw && 3918 4072 hkey == TP_HKEY_EV_RFKILL_CHANGED) { 3919 4073 tpacpi_send_radiosw_update(); 3920 - send_acpi_ev = 0; 4074 + send_acpi_ev = false; 3921 4075 known_ev = true; 3922 - break; 3923 4076 } 3924 - fallthrough; /* to default */ 3925 - default: 3926 - known_ev = false; 4077 + break; 4078 + case 8: 4079 + /* 0x8000-0x8FFF: misc2 */ 4080 + known_ev = hotkey_notify_8xxx(hkey, &send_acpi_ev); 4081 + break; 3927 4082 } 3928 4083 if (!known_ev) { 3929 4084 pr_notice("unhandled HKEY event 0x%04x\n", hkey); ··· 3928 4091 } 3929 4092 3930 4093 /* netlink events */ 3931 - if (!ignore_acpi_ev && send_acpi_ev) { 4094 + if (send_acpi_ev) { 3932 4095 acpi_bus_generate_netlink_event( 3933 4096 ibm->acpi->device->pnp.device_class, 3934 4097 dev_name(&ibm->acpi->device->dev), ··· 9626 9789 battery = BAT_PRIMARY; 9627 9790 if (tpacpi_battery_get(what, battery, &ret)) 9628 9791 return -ENODEV; 9629 - return sprintf(buf, "%d\n", ret); 9792 + return sysfs_emit(buf, "%d\n", ret); 9630 9793 } 9631 9794 9632 9795 static ssize_t charge_control_start_threshold_show(struct device *device, ··· 10963 11126 * HKEY event callout for other subdrivers go here 10964 11127 * (yes, it is ugly, but it is quick, safe, and gets the job done 10965 11128 */ 10966 - static void tpacpi_driver_event(const unsigned int hkey_event) 11129 + static bool tpacpi_driver_event(const unsigned int hkey_event) 10967 11130 { 10968 - if (ibm_backlight_device) { 10969 - switch (hkey_event) { 10970 - case TP_HKEY_EV_BRGHT_UP: 10971 - case TP_HKEY_EV_BRGHT_DOWN: 11131 + switch (hkey_event) { 11132 + case TP_HKEY_EV_BRGHT_UP: 11133 + case TP_HKEY_EV_BRGHT_DOWN: 11134 + if (ibm_backlight_device) 10972 11135 tpacpi_brightness_notify_change(); 10973 - } 10974 - } 10975 - if (alsa_card) { 10976 - switch (hkey_event) { 10977 - case TP_HKEY_EV_VOL_UP: 10978 - case TP_HKEY_EV_VOL_DOWN: 10979 - case TP_HKEY_EV_VOL_MUTE: 10980 - volume_alsa_notify_change(); 10981 - } 10982 - } 10983 - if (tp_features.kbdlight && hkey_event == TP_HKEY_EV_KBD_LIGHT) { 10984 - enum led_brightness brightness; 10985 - 10986 - mutex_lock(&kbdlight_mutex); 10987 - 10988 11136 /* 10989 - * Check the brightness actually changed, setting the brightness 10990 - * through kbdlight_set_level() also triggers this event. 11137 + * Key press events are suppressed by default hotkey_user_mask 11138 + * and should still be reported if explicitly requested. 10991 11139 */ 10992 - brightness = kbdlight_sysfs_get(NULL); 10993 - if (kbdlight_brightness != brightness) { 10994 - kbdlight_brightness = brightness; 10995 - led_classdev_notify_brightness_hw_changed( 10996 - &tpacpi_led_kbdlight.led_classdev, brightness); 11140 + return false; 11141 + case TP_HKEY_EV_VOL_UP: 11142 + case TP_HKEY_EV_VOL_DOWN: 11143 + case TP_HKEY_EV_VOL_MUTE: 11144 + if (alsa_card) 11145 + volume_alsa_notify_change(); 11146 + 11147 + /* Key events are suppressed by default hotkey_user_mask */ 11148 + return false; 11149 + case TP_HKEY_EV_KBD_LIGHT: 11150 + if (tp_features.kbdlight) { 11151 + enum led_brightness brightness; 11152 + 11153 + mutex_lock(&kbdlight_mutex); 11154 + 11155 + /* 11156 + * Check the brightness actually changed, setting the brightness 11157 + * through kbdlight_set_level() also triggers this event. 11158 + */ 11159 + brightness = kbdlight_sysfs_get(NULL); 11160 + if (kbdlight_brightness != brightness) { 11161 + kbdlight_brightness = brightness; 11162 + led_classdev_notify_brightness_hw_changed( 11163 + &tpacpi_led_kbdlight.led_classdev, brightness); 11164 + } 11165 + 11166 + mutex_unlock(&kbdlight_mutex); 10997 11167 } 10998 - 10999 - mutex_unlock(&kbdlight_mutex); 11000 - } 11001 - 11002 - if (hkey_event == TP_HKEY_EV_THM_CSM_COMPLETED) { 11168 + /* Key events are suppressed by default hotkey_user_mask */ 11169 + return false; 11170 + case TP_HKEY_EV_DFR_CHANGE_ROW: 11171 + adaptive_keyboard_change_row(); 11172 + return true; 11173 + case TP_HKEY_EV_DFR_S_QUICKVIEW_ROW: 11174 + adaptive_keyboard_s_quickview_row(); 11175 + return true; 11176 + case TP_HKEY_EV_THM_CSM_COMPLETED: 11003 11177 lapsensor_refresh(); 11004 11178 /* If we are already accessing DYTC then skip dytc update */ 11005 11179 if (!atomic_add_unless(&dytc_ignore_event, -1, 0)) 11006 11180 dytc_profile_refresh(); 11007 - } 11008 11181 11009 - if (lcdshadow_dev && hkey_event == TP_HKEY_EV_PRIVACYGUARD_TOGGLE) { 11010 - enum drm_privacy_screen_status old_hw_state; 11011 - bool changed; 11182 + return true; 11183 + case TP_HKEY_EV_PRIVACYGUARD_TOGGLE: 11184 + if (lcdshadow_dev) { 11185 + enum drm_privacy_screen_status old_hw_state; 11186 + bool changed; 11012 11187 11013 - mutex_lock(&lcdshadow_dev->lock); 11014 - old_hw_state = lcdshadow_dev->hw_state; 11015 - lcdshadow_get_hw_state(lcdshadow_dev); 11016 - changed = lcdshadow_dev->hw_state != old_hw_state; 11017 - mutex_unlock(&lcdshadow_dev->lock); 11188 + mutex_lock(&lcdshadow_dev->lock); 11189 + old_hw_state = lcdshadow_dev->hw_state; 11190 + lcdshadow_get_hw_state(lcdshadow_dev); 11191 + changed = lcdshadow_dev->hw_state != old_hw_state; 11192 + mutex_unlock(&lcdshadow_dev->lock); 11018 11193 11019 - if (changed) 11020 - drm_privacy_screen_call_notifier_chain(lcdshadow_dev); 11021 - } 11022 - if (hkey_event == TP_HKEY_EV_AMT_TOGGLE) { 11194 + if (changed) 11195 + drm_privacy_screen_call_notifier_chain(lcdshadow_dev); 11196 + } 11197 + return true; 11198 + case TP_HKEY_EV_AMT_TOGGLE: 11023 11199 /* If we're enabling AMT we need to force balanced mode */ 11024 11200 if (!dytc_amt_active) 11025 11201 /* This will also set AMT mode enabled */ 11026 11202 dytc_profile_set(NULL, PLATFORM_PROFILE_BALANCED); 11027 11203 else 11028 11204 dytc_control_amt(!dytc_amt_active); 11029 - } 11030 - if (hkey_event == TP_HKEY_EV_PROFILE_TOGGLE) { 11031 - switch (dytc_current_profile) { 11032 - case PLATFORM_PROFILE_LOW_POWER: 11033 - dytc_profile_set(NULL, PLATFORM_PROFILE_BALANCED); 11034 - break; 11035 - case PLATFORM_PROFILE_BALANCED: 11036 - dytc_profile_set(NULL, PLATFORM_PROFILE_PERFORMANCE); 11037 - break; 11038 - case PLATFORM_PROFILE_PERFORMANCE: 11039 - dytc_profile_set(NULL, PLATFORM_PROFILE_LOW_POWER); 11040 - break; 11041 - default: 11042 - pr_warn("Profile HKEY unexpected profile %d", dytc_current_profile); 11043 - } 11044 - /* Notify user space the profile changed */ 11045 - platform_profile_notify(); 11046 - } 11047 - } 11048 11205 11049 - static void hotkey_driver_event(const unsigned int scancode) 11050 - { 11051 - tpacpi_driver_event(TP_HKEY_EV_HOTKEY_BASE + scancode); 11206 + return true; 11207 + case TP_HKEY_EV_DOUBLETAP_TOGGLE: 11208 + tp_features.trackpoint_doubletap = !tp_features.trackpoint_doubletap; 11209 + return true; 11210 + case TP_HKEY_EV_PROFILE_TOGGLE: 11211 + platform_profile_cycle(); 11212 + return true; 11213 + } 11214 + 11215 + return false; 11052 11216 } 11053 11217 11054 11218 /* --------------------------------------------------------------------- */ ··· 11652 11814 input_unregister_device(tpacpi_inputdev); 11653 11815 else 11654 11816 input_free_device(tpacpi_inputdev); 11655 - kfree(hotkey_keycode_map); 11656 11817 } 11657 11818 11658 11819 if (tpacpi_sensors_pdev)
+33 -3
drivers/platform/x86/toshiba_acpi.c
··· 57 57 MODULE_PARM_DESC(turn_on_panel_on_resume, 58 58 "Call HCI_PANEL_POWER_ON on resume (-1 = auto, 0 = no, 1 = yes"); 59 59 60 + static int hci_hotkey_quickstart = -1; 61 + module_param(hci_hotkey_quickstart, int, 0644); 62 + MODULE_PARM_DESC(hci_hotkey_quickstart, 63 + "Call HCI_HOTKEY_EVENT with value 0x5 for quickstart button support (-1 = auto, 0 = no, 1 = yes"); 64 + 60 65 #define TOSHIBA_WMI_EVENT_GUID "59142400-C6A3-40FA-BADB-8A2652834100" 61 66 62 67 /* Scan code for Fn key on TOS1900 models */ ··· 141 136 #define HCI_ACCEL_MASK 0x7fff 142 137 #define HCI_ACCEL_DIRECTION_MASK 0x8000 143 138 #define HCI_HOTKEY_DISABLE 0x0b 139 + #define HCI_HOTKEY_ENABLE_QUICKSTART 0x05 144 140 #define HCI_HOTKEY_ENABLE 0x09 145 141 #define HCI_HOTKEY_SPECIAL_FUNCTIONS 0x10 146 142 #define HCI_LCD_BRIGHTNESS_BITS 3 ··· 2737 2731 return -ENODEV; 2738 2732 2739 2733 /* 2734 + * Enable quickstart buttons if supported. 2735 + * 2740 2736 * Enable the "Special Functions" mode only if they are 2741 2737 * supported and if they are activated. 2742 2738 */ 2743 - if (dev->kbd_function_keys_supported && dev->special_functions) 2739 + if (hci_hotkey_quickstart) 2740 + result = hci_write(dev, HCI_HOTKEY_EVENT, 2741 + HCI_HOTKEY_ENABLE_QUICKSTART); 2742 + else if (dev->kbd_function_keys_supported && dev->special_functions) 2744 2743 result = hci_write(dev, HCI_HOTKEY_EVENT, 2745 2744 HCI_HOTKEY_SPECIAL_FUNCTIONS); 2746 2745 else ··· 3269 3258 * works. toshiba_acpi_resume() uses HCI_PANEL_POWER_ON to avoid changing 3270 3259 * the configured brightness level. 3271 3260 */ 3272 - static const struct dmi_system_id turn_on_panel_on_resume_dmi_ids[] = { 3261 + #define QUIRK_TURN_ON_PANEL_ON_RESUME BIT(0) 3262 + /* 3263 + * Some Toshibas use "quickstart" keys. On these, HCI_HOTKEY_EVENT must use 3264 + * the value HCI_HOTKEY_ENABLE_QUICKSTART. 3265 + */ 3266 + #define QUIRK_HCI_HOTKEY_QUICKSTART BIT(1) 3267 + 3268 + static const struct dmi_system_id toshiba_dmi_quirks[] = { 3273 3269 { 3274 3270 /* Toshiba Portégé R700 */ 3275 3271 /* https://bugzilla.kernel.org/show_bug.cgi?id=21012 */ ··· 3284 3266 DMI_MATCH(DMI_SYS_VENDOR, "TOSHIBA"), 3285 3267 DMI_MATCH(DMI_PRODUCT_NAME, "PORTEGE R700"), 3286 3268 }, 3269 + .driver_data = (void *)QUIRK_TURN_ON_PANEL_ON_RESUME, 3287 3270 }, 3288 3271 { 3289 3272 /* Toshiba Satellite/Portégé R830 */ ··· 3294 3275 DMI_MATCH(DMI_SYS_VENDOR, "TOSHIBA"), 3295 3276 DMI_MATCH(DMI_PRODUCT_NAME, "R830"), 3296 3277 }, 3278 + .driver_data = (void *)QUIRK_TURN_ON_PANEL_ON_RESUME, 3297 3279 }, 3298 3280 { 3299 3281 /* Toshiba Satellite/Portégé Z830 */ ··· 3302 3282 DMI_MATCH(DMI_SYS_VENDOR, "TOSHIBA"), 3303 3283 DMI_MATCH(DMI_PRODUCT_NAME, "Z830"), 3304 3284 }, 3285 + .driver_data = (void *)(QUIRK_TURN_ON_PANEL_ON_RESUME | QUIRK_HCI_HOTKEY_QUICKSTART), 3305 3286 }, 3306 3287 }; 3307 3288 ··· 3311 3290 struct toshiba_acpi_dev *dev; 3312 3291 const char *hci_method; 3313 3292 u32 dummy; 3293 + const struct dmi_system_id *dmi_id; 3294 + long quirks = 0; 3314 3295 int ret = 0; 3315 3296 3316 3297 if (toshiba_acpi) ··· 3465 3442 } 3466 3443 #endif 3467 3444 3445 + dmi_id = dmi_first_match(toshiba_dmi_quirks); 3446 + if (dmi_id) 3447 + quirks = (long)dmi_id->driver_data; 3448 + 3468 3449 if (turn_on_panel_on_resume == -1) 3469 - turn_on_panel_on_resume = dmi_check_system(turn_on_panel_on_resume_dmi_ids); 3450 + turn_on_panel_on_resume = !!(quirks & QUIRK_TURN_ON_PANEL_ON_RESUME); 3451 + 3452 + if (hci_hotkey_quickstart == -1) 3453 + hci_hotkey_quickstart = !!(quirks & QUIRK_HCI_HOTKEY_QUICKSTART); 3470 3454 3471 3455 toshiba_wwan_available(dev); 3472 3456 if (dev->wwan_supported)
+10 -10
drivers/platform/x86/uv_sysfs.c
··· 129 129 130 130 static ssize_t hub_partition_show(struct uv_bios_hub_info *hub_info, char *buf) 131 131 { 132 - return sprintf(buf, "%d\n", hub_info->f.fields.this_part); 132 + return sysfs_emit(buf, "%d\n", hub_info->f.fields.this_part); 133 133 } 134 134 135 135 static ssize_t hub_shared_show(struct uv_bios_hub_info *hub_info, char *buf) 136 136 { 137 - return sprintf(buf, "%d\n", hub_info->f.fields.is_shared); 137 + return sysfs_emit(buf, "%d\n", hub_info->f.fields.is_shared); 138 138 } 139 139 static ssize_t hub_nasid_show(struct uv_bios_hub_info *hub_info, char *buf) 140 140 { 141 141 int cnode = get_obj_to_cnode(hub_info->id); 142 142 143 - return sprintf(buf, "%d\n", ordinal_to_nasid(cnode)); 143 + return sysfs_emit(buf, "%d\n", ordinal_to_nasid(cnode)); 144 144 } 145 145 static ssize_t hub_cnode_show(struct uv_bios_hub_info *hub_info, char *buf) 146 146 { 147 - return sprintf(buf, "%d\n", get_obj_to_cnode(hub_info->id)); 147 + return sysfs_emit(buf, "%d\n", get_obj_to_cnode(hub_info->id)); 148 148 } 149 149 150 150 struct hub_sysfs_entry { ··· 304 304 305 305 static ssize_t uv_port_conn_hub_show(struct uv_bios_port_info *port, char *buf) 306 306 { 307 - return sprintf(buf, "%d\n", port->conn_id); 307 + return sysfs_emit(buf, "%d\n", port->conn_id); 308 308 } 309 309 310 310 static ssize_t uv_port_conn_port_show(struct uv_bios_port_info *port, char *buf) 311 311 { 312 - return sprintf(buf, "%d\n", port->conn_port); 312 + return sysfs_emit(buf, "%d\n", port->conn_port); 313 313 } 314 314 315 315 struct uv_port_sysfs_entry { ··· 470 470 471 471 static ssize_t uv_pci_iio_stack_show(struct uv_pci_top_obj *top_obj, char *buf) 472 472 { 473 - return sprintf(buf, "%d\n", top_obj->iio_stack); 473 + return sysfs_emit(buf, "%d\n", top_obj->iio_stack); 474 474 } 475 475 476 476 static ssize_t uv_pci_ppb_addr_show(struct uv_pci_top_obj *top_obj, char *buf) ··· 480 480 481 481 static ssize_t uv_pci_slot_show(struct uv_pci_top_obj *top_obj, char *buf) 482 482 { 483 - return sprintf(buf, "%d\n", top_obj->slot); 483 + return sysfs_emit(buf, "%d\n", top_obj->slot); 484 484 } 485 485 486 486 struct uv_pci_top_sysfs_entry { ··· 725 725 static ssize_t partition_id_show(struct kobject *kobj, 726 726 struct kobj_attribute *attr, char *buf) 727 727 { 728 - return sprintf(buf, "%ld\n", sn_partition_id); 728 + return sysfs_emit(buf, "%ld\n", sn_partition_id); 729 729 } 730 730 731 731 static ssize_t coherence_id_show(struct kobject *kobj, 732 732 struct kobj_attribute *attr, char *buf) 733 733 { 734 - return sprintf(buf, "%ld\n", sn_coherency_id); 734 + return sysfs_emit(buf, "%ld\n", sn_coherency_id); 735 735 } 736 736 737 737 static ssize_t uv_type_show(struct kobject *kobj,
+45 -15
drivers/platform/x86/wmi.c
··· 1153 1153 return 0; 1154 1154 } 1155 1155 1156 + static int ec_read_multiple(u8 address, u8 *buffer, size_t bytes) 1157 + { 1158 + size_t i; 1159 + int ret; 1160 + 1161 + for (i = 0; i < bytes; i++) { 1162 + ret = ec_read(address + i, &buffer[i]); 1163 + if (ret < 0) 1164 + return ret; 1165 + } 1166 + 1167 + return 0; 1168 + } 1169 + 1170 + static int ec_write_multiple(u8 address, u8 *buffer, size_t bytes) 1171 + { 1172 + size_t i; 1173 + int ret; 1174 + 1175 + for (i = 0; i < bytes; i++) { 1176 + ret = ec_write(address + i, buffer[i]); 1177 + if (ret < 0) 1178 + return ret; 1179 + } 1180 + 1181 + return 0; 1182 + } 1183 + 1156 1184 /* 1157 1185 * WMI can have EmbeddedControl access regions. In which case, we just want to 1158 1186 * hand these off to the EC driver. ··· 1190 1162 u32 bits, u64 *value, 1191 1163 void *handler_context, void *region_context) 1192 1164 { 1193 - int result = 0; 1194 - u8 temp = 0; 1165 + int bytes = bits / BITS_PER_BYTE; 1166 + int ret; 1195 1167 1196 - if ((address > 0xFF) || !value) 1168 + if (!value) 1169 + return AE_NULL_ENTRY; 1170 + 1171 + if (!bytes || bytes > sizeof(*value)) 1172 + return AE_BAD_PARAMETER; 1173 + 1174 + if (address > U8_MAX || address + bytes - 1 > U8_MAX) 1197 1175 return AE_BAD_PARAMETER; 1198 1176 1199 1177 if (function != ACPI_READ && function != ACPI_WRITE) 1200 1178 return AE_BAD_PARAMETER; 1201 1179 1202 - if (bits != 8) 1203 - return AE_BAD_PARAMETER; 1180 + if (function == ACPI_READ) 1181 + ret = ec_read_multiple(address, (u8 *)value, bytes); 1182 + else 1183 + ret = ec_write_multiple(address, (u8 *)value, bytes); 1204 1184 1205 - if (function == ACPI_READ) { 1206 - result = ec_read(address, &temp); 1207 - *value = temp; 1208 - } else { 1209 - temp = 0xff & *value; 1210 - result = ec_write(address, temp); 1211 - } 1212 - 1213 - switch (result) { 1185 + switch (ret) { 1214 1186 case -EINVAL: 1215 1187 return AE_BAD_PARAMETER; 1216 1188 case -ENODEV: 1217 1189 return AE_NOT_FOUND; 1218 1190 case -ETIME: 1219 1191 return AE_TIME; 1220 - default: 1192 + case 0: 1221 1193 return AE_OK; 1194 + default: 1195 + return AE_ERROR; 1222 1196 } 1223 1197 } 1224 1198
+7 -9
drivers/platform/x86/x86-android-tablets/core.c
··· 52 52 return -ENOMEM; 53 53 54 54 lookup->dev_id = KBUILD_MODNAME; 55 - lookup->table[0].key = chip; 56 - lookup->table[0].chip_hwnum = pin; 57 - lookup->table[0].con_id = con_id; 58 - lookup->table[0].flags = active_low ? GPIO_ACTIVE_LOW : GPIO_ACTIVE_HIGH; 55 + lookup->table[0] = 56 + GPIO_LOOKUP(chip, pin, con_id, active_low ? GPIO_ACTIVE_LOW : GPIO_ACTIVE_HIGH); 59 57 60 58 gpiod_add_lookup_table(lookup); 61 59 gpiod = devm_gpiod_get(&x86_android_tablet_device->dev, con_id, dflags); ··· 276 278 { 277 279 int i; 278 280 279 - for (i = 0; i < serdev_count; i++) { 281 + for (i = serdev_count - 1; i >= 0; i--) { 280 282 if (serdevs[i]) 281 283 serdev_device_remove(serdevs[i]); 282 284 } 283 285 284 286 kfree(serdevs); 285 287 286 - for (i = 0; i < pdev_count; i++) 288 + for (i = pdev_count - 1; i >= 0; i--) 287 289 platform_device_unregister(pdevs[i]); 288 290 289 291 kfree(pdevs); 290 292 kfree(buttons); 291 293 292 - for (i = 0; i < spi_dev_count; i++) 294 + for (i = spi_dev_count - 1; i >= 0; i--) 293 295 spi_unregister_device(spi_devs[i]); 294 296 295 297 kfree(spi_devs); 296 298 297 - for (i = 0; i < i2c_client_count; i++) 299 + for (i = i2c_client_count - 1; i >= 0; i--) 298 300 i2c_unregister_device(i2c_clients[i]); 299 301 300 302 kfree(i2c_clients); ··· 341 343 gpiod_add_lookup_table(gpiod_lookup_tables[i]); 342 344 343 345 if (dev_info->init) { 344 - ret = dev_info->init(); 346 + ret = dev_info->init(&pdev->dev); 345 347 if (ret < 0) { 346 348 x86_android_tablet_remove(pdev); 347 349 return ret;
+18
drivers/platform/x86/x86-android-tablets/dmi.c
··· 106 106 }, 107 107 { 108 108 /* 109 + * Lenovo Yoga Tablet 2 Pro 1380F/L (13") This has more or less 110 + * the same BIOS as the 830F/L or 1050F/L (8" and 10") below, 111 + * but unlike the 8" / 10" models which share the same mainboard 112 + * this model has a different mainboard. 113 + * This match for the 13" model MUST come before the 8" + 10" 114 + * match since that one will also match the 13" model! 115 + */ 116 + .matches = { 117 + DMI_MATCH(DMI_SYS_VENDOR, "Intel Corp."), 118 + DMI_MATCH(DMI_PRODUCT_NAME, "VALLEYVIEW C0 PLATFORM"), 119 + DMI_MATCH(DMI_BOARD_NAME, "BYT-T FFD8"), 120 + /* Full match so as to NOT match the 830/1050 BIOS */ 121 + DMI_MATCH(DMI_BIOS_VERSION, "BLADE_21.X64.0005.R00.1504101516"), 122 + }, 123 + .driver_data = (void *)&lenovo_yoga_tab2_1380_info, 124 + }, 125 + { 126 + /* 109 127 * Lenovo Yoga Tablet 2 830F/L or 1050F/L (The 8" and 10" 110 128 * Lenovo Yoga Tablet 2 use the same mainboard) 111 129 */
+220 -4
drivers/platform/x86/x86-android-tablets/lenovo.c
··· 19 19 #include <linux/pinctrl/machine.h> 20 20 #include <linux/platform_data/lp855x.h> 21 21 #include <linux/platform_device.h> 22 + #include <linux/power/bq24190_charger.h> 22 23 #include <linux/reboot.h> 23 24 #include <linux/rmi.h> 24 25 #include <linux/spi/spi.h> ··· 230 229 NULL 231 230 }; 232 231 233 - static int __init lenovo_yb1_x90_init(void) 232 + static int __init lenovo_yb1_x90_init(struct device *dev) 234 233 { 235 234 /* Enable the regulators used by the touchscreens */ 236 235 ··· 412 411 NULL 413 412 }; 414 413 415 - static int __init lenovo_yoga_tab2_830_1050_init(void); 414 + static int __init lenovo_yoga_tab2_830_1050_init(struct device *dev); 416 415 static void lenovo_yoga_tab2_830_1050_exit(void); 417 416 418 417 const struct x86_dev_info lenovo_yoga_tab2_830_1050_info __initconst = { ··· 534 533 return NOTIFY_DONE; 535 534 } 536 535 537 - static int __init lenovo_yoga_tab2_830_1050_init(void) 536 + static int __init lenovo_yoga_tab2_830_1050_init(struct device *dev) 538 537 { 539 538 int ret; 540 539 ··· 565 564 pinctrl_unregister_mappings(&lenovo_yoga_tab2_830_1050_codec_pinctrl_map); 566 565 } 567 566 } 567 + 568 + /* 569 + * Lenovo Yoga Tablet 2 Pro 1380F/L 570 + * 571 + * The Lenovo Yoga Tablet 2 Pro 1380F/L mostly has the same design as the 830F/L 572 + * and the 1050F/L so this re-uses some of the handling for that from above. 573 + */ 574 + static const char * const lc824206xa_chg_det_psy[] = { "lc824206xa-charger-detect" }; 575 + 576 + static const struct property_entry lenovo_yoga_tab2_1380_bq24190_props[] = { 577 + PROPERTY_ENTRY_STRING_ARRAY("supplied-from", lc824206xa_chg_det_psy), 578 + PROPERTY_ENTRY_REF("monitored-battery", &generic_lipo_hv_4v35_battery_node), 579 + PROPERTY_ENTRY_BOOL("omit-battery-class"), 580 + PROPERTY_ENTRY_BOOL("disable-reset"), 581 + { } 582 + }; 583 + 584 + static const struct software_node lenovo_yoga_tab2_1380_bq24190_node = { 585 + .properties = lenovo_yoga_tab2_1380_bq24190_props, 586 + }; 587 + 588 + /* For enabling the bq24190 5V boost based on id-pin */ 589 + static struct regulator_consumer_supply lc824206xa_consumer = { 590 + .supply = "vbus", 591 + .dev_name = "i2c-lc824206xa", 592 + }; 593 + 594 + static const struct regulator_init_data lenovo_yoga_tab2_1380_bq24190_vbus_init_data = { 595 + .constraints = { 596 + .name = "bq24190_vbus", 597 + .valid_ops_mask = REGULATOR_CHANGE_STATUS, 598 + }, 599 + .consumer_supplies = &lc824206xa_consumer, 600 + .num_consumer_supplies = 1, 601 + }; 602 + 603 + struct bq24190_platform_data lenovo_yoga_tab2_1380_bq24190_pdata = { 604 + .regulator_init_data = &lenovo_yoga_tab2_1380_bq24190_vbus_init_data, 605 + }; 606 + 607 + static const struct property_entry lenovo_yoga_tab2_1380_lc824206xa_props[] = { 608 + PROPERTY_ENTRY_BOOL("onnn,enable-miclr-for-dcp"), 609 + { } 610 + }; 611 + 612 + static const struct software_node lenovo_yoga_tab2_1380_lc824206xa_node = { 613 + .properties = lenovo_yoga_tab2_1380_lc824206xa_props, 614 + }; 615 + 616 + static const char * const lenovo_yoga_tab2_1380_lms303d_mount_matrix[] = { 617 + "0", "-1", "0", 618 + "-1", "0", "0", 619 + "0", "0", "1" 620 + }; 621 + 622 + static const struct property_entry lenovo_yoga_tab2_1380_lms303d_props[] = { 623 + PROPERTY_ENTRY_STRING_ARRAY("mount-matrix", lenovo_yoga_tab2_1380_lms303d_mount_matrix), 624 + { } 625 + }; 626 + 627 + static const struct software_node lenovo_yoga_tab2_1380_lms303d_node = { 628 + .properties = lenovo_yoga_tab2_1380_lms303d_props, 629 + }; 630 + 631 + static const struct x86_i2c_client_info lenovo_yoga_tab2_1380_i2c_clients[] __initconst = { 632 + { 633 + /* BQ27541 fuel-gauge */ 634 + .board_info = { 635 + .type = "bq27541", 636 + .addr = 0x55, 637 + .dev_name = "bq27541", 638 + .swnode = &fg_bq24190_supply_node, 639 + }, 640 + .adapter_path = "\\_SB_.I2C1", 641 + }, { 642 + /* bq24292i battery charger */ 643 + .board_info = { 644 + .type = "bq24190", 645 + .addr = 0x6b, 646 + .dev_name = "bq24292i", 647 + .swnode = &lenovo_yoga_tab2_1380_bq24190_node, 648 + .platform_data = &lenovo_yoga_tab2_1380_bq24190_pdata, 649 + }, 650 + .adapter_path = "\\_SB_.I2C1", 651 + .irq_data = { 652 + .type = X86_ACPI_IRQ_TYPE_GPIOINT, 653 + .chip = "INT33FC:02", 654 + .index = 2, 655 + .trigger = ACPI_EDGE_SENSITIVE, 656 + .polarity = ACPI_ACTIVE_HIGH, 657 + .con_id = "bq24292i_irq", 658 + }, 659 + }, { 660 + /* LP8557 Backlight controller */ 661 + .board_info = { 662 + .type = "lp8557", 663 + .addr = 0x2c, 664 + .dev_name = "lp8557", 665 + .platform_data = &lenovo_lp8557_pwm_and_reg_pdata, 666 + }, 667 + .adapter_path = "\\_SB_.I2C3", 668 + }, { 669 + /* LC824206XA Micro USB Switch */ 670 + .board_info = { 671 + .type = "lc824206xa", 672 + .addr = 0x48, 673 + .dev_name = "lc824206xa", 674 + .swnode = &lenovo_yoga_tab2_1380_lc824206xa_node, 675 + }, 676 + .adapter_path = "\\_SB_.I2C3", 677 + .irq_data = { 678 + .type = X86_ACPI_IRQ_TYPE_GPIOINT, 679 + .chip = "INT33FC:02", 680 + .index = 1, 681 + .trigger = ACPI_LEVEL_SENSITIVE, 682 + .polarity = ACPI_ACTIVE_LOW, 683 + .con_id = "lc824206xa_irq", 684 + }, 685 + }, { 686 + /* AL3320A ambient light sensor */ 687 + .board_info = { 688 + .type = "al3320a", 689 + .addr = 0x1c, 690 + .dev_name = "al3320a", 691 + }, 692 + .adapter_path = "\\_SB_.I2C5", 693 + }, { 694 + /* LSM303DA accelerometer + magnetometer */ 695 + .board_info = { 696 + .type = "lsm303d", 697 + .addr = 0x1d, 698 + .dev_name = "lsm303d", 699 + .swnode = &lenovo_yoga_tab2_1380_lms303d_node, 700 + }, 701 + .adapter_path = "\\_SB_.I2C5", 702 + }, { 703 + /* Synaptics RMI touchscreen */ 704 + .board_info = { 705 + .type = "rmi4_i2c", 706 + .addr = 0x38, 707 + .dev_name = "rmi4_i2c", 708 + .platform_data = &lenovo_yoga_tab2_830_1050_rmi_pdata, 709 + }, 710 + .adapter_path = "\\_SB_.I2C6", 711 + .irq_data = { 712 + .type = X86_ACPI_IRQ_TYPE_APIC, 713 + .index = 0x45, 714 + .trigger = ACPI_EDGE_SENSITIVE, 715 + .polarity = ACPI_ACTIVE_HIGH, 716 + }, 717 + } 718 + }; 719 + 720 + static const struct platform_device_info lenovo_yoga_tab2_1380_pdevs[] __initconst = { 721 + { 722 + /* For the Tablet 2 Pro 1380's custom fast charging driver */ 723 + .name = "lenovo-yoga-tab2-pro-1380-fastcharger", 724 + .id = PLATFORM_DEVID_NONE, 725 + }, 726 + }; 727 + 728 + const char * const lenovo_yoga_tab2_1380_modules[] __initconst = { 729 + "bq24190_charger", /* For the Vbus regulator for lc824206xa */ 730 + NULL 731 + }; 732 + 733 + static int __init lenovo_yoga_tab2_1380_init(struct device *dev) 734 + { 735 + int ret; 736 + 737 + /* To verify that the DMI matching works vs the 830 / 1050 models */ 738 + pr_info("detected Lenovo Yoga Tablet 2 Pro 1380F/L\n"); 739 + 740 + ret = lenovo_yoga_tab2_830_1050_init_codec(); 741 + if (ret) 742 + return ret; 743 + 744 + /* SYS_OFF_PRIO_FIRMWARE + 1 so that it runs before acpi_power_off */ 745 + lenovo_yoga_tab2_830_1050_sys_off_handler = 746 + register_sys_off_handler(SYS_OFF_MODE_POWER_OFF, SYS_OFF_PRIO_FIRMWARE + 1, 747 + lenovo_yoga_tab2_830_1050_power_off, NULL); 748 + if (IS_ERR(lenovo_yoga_tab2_830_1050_sys_off_handler)) 749 + return PTR_ERR(lenovo_yoga_tab2_830_1050_sys_off_handler); 750 + 751 + return 0; 752 + } 753 + 754 + static struct gpiod_lookup_table lenovo_yoga_tab2_1380_fc_gpios = { 755 + .dev_id = "serial0-0", 756 + .table = { 757 + GPIO_LOOKUP("INT33FC:00", 57, "uart3_txd", GPIO_ACTIVE_HIGH), 758 + GPIO_LOOKUP("INT33FC:00", 61, "uart3_rxd", GPIO_ACTIVE_HIGH), 759 + { } 760 + }, 761 + }; 762 + 763 + static struct gpiod_lookup_table * const lenovo_yoga_tab2_1380_gpios[] = { 764 + &lenovo_yoga_tab2_830_1050_codec_gpios, 765 + &lenovo_yoga_tab2_1380_fc_gpios, 766 + NULL 767 + }; 768 + 769 + const struct x86_dev_info lenovo_yoga_tab2_1380_info __initconst = { 770 + .i2c_client_info = lenovo_yoga_tab2_1380_i2c_clients, 771 + .i2c_client_count = ARRAY_SIZE(lenovo_yoga_tab2_1380_i2c_clients), 772 + .pdev_info = lenovo_yoga_tab2_1380_pdevs, 773 + .pdev_count = ARRAY_SIZE(lenovo_yoga_tab2_1380_pdevs), 774 + .gpio_button = &lenovo_yoga_tab2_830_1050_lid, 775 + .gpio_button_count = 1, 776 + .gpiod_lookup_tables = lenovo_yoga_tab2_1380_gpios, 777 + .bat_swnode = &generic_lipo_hv_4v35_battery_node, 778 + .modules = lenovo_yoga_tab2_1380_modules, 779 + .init = lenovo_yoga_tab2_1380_init, 780 + .exit = lenovo_yoga_tab2_830_1050_exit, 781 + }; 568 782 569 783 /* Lenovo Yoga Tab 3 Pro YT3-X90F */ 570 784 ··· 978 762 } 979 763 }; 980 764 981 - static int __init lenovo_yt3_init(void) 765 + static int __init lenovo_yt3_init(struct device *dev) 982 766 { 983 767 int ret; 984 768
+131 -2
drivers/platform/x86/x86-android-tablets/other.c
··· 11 11 #include <linux/acpi.h> 12 12 #include <linux/gpio/machine.h> 13 13 #include <linux/input.h> 14 + #include <linux/leds.h> 14 15 #include <linux/platform_device.h> 16 + #include <linux/pwm.h> 17 + 18 + #include <dt-bindings/leds/common.h> 15 19 16 20 #include "shared-psy-info.h" 17 21 #include "x86-android-tablets.h" ··· 185 181 }, 186 182 }; 187 183 188 - static int __init chuwi_hi8_init(void) 184 + static int __init chuwi_hi8_init(struct device *dev) 189 185 { 190 186 /* 191 187 * Avoid the acpi_unregister_gsi() call in x86_acpi_irq_helper_get() ··· 246 242 #define CZC_EC_EXTRA_PORT 0x68 247 243 #define CZC_EC_ANDROID_KEYS 0x63 248 244 249 - static int __init czc_p10t_init(void) 245 + static int __init czc_p10t_init(struct device *dev) 250 246 { 251 247 /* 252 248 * The device boots up in "Windows 7" mode, when the home button sends a ··· 598 594 }; 599 595 600 596 /* 597 + * The fwnode for ktd2026 on Xaomi pad2. It composed of a RGB LED node 598 + * with three subnodes for each color (B/G/R). The RGB LED node is named 599 + * "multi-led" to align with the name in the device tree. 600 + */ 601 + 602 + /* main fwnode for ktd2026 */ 603 + static const struct software_node ktd2026_node = { 604 + .name = "ktd2026", 605 + }; 606 + 607 + static const struct property_entry ktd2026_rgb_led_props[] = { 608 + PROPERTY_ENTRY_U32("reg", 0), 609 + PROPERTY_ENTRY_U32("color", LED_COLOR_ID_RGB), 610 + PROPERTY_ENTRY_STRING("label", "mipad2:rgb:indicator"), 611 + PROPERTY_ENTRY_STRING("linux,default-trigger", "bq27520-0-charging-orange-full-green"), 612 + { } 613 + }; 614 + 615 + static const struct software_node ktd2026_rgb_led_node = { 616 + .name = "multi-led", 617 + .properties = ktd2026_rgb_led_props, 618 + .parent = &ktd2026_node, 619 + }; 620 + 621 + static const struct property_entry ktd2026_blue_led_props[] = { 622 + PROPERTY_ENTRY_U32("reg", 0), 623 + PROPERTY_ENTRY_U32("color", LED_COLOR_ID_BLUE), 624 + { } 625 + }; 626 + 627 + static const struct software_node ktd2026_blue_led_node = { 628 + .properties = ktd2026_blue_led_props, 629 + .parent = &ktd2026_rgb_led_node, 630 + }; 631 + 632 + static const struct property_entry ktd2026_green_led_props[] = { 633 + PROPERTY_ENTRY_U32("reg", 1), 634 + PROPERTY_ENTRY_U32("color", LED_COLOR_ID_GREEN), 635 + { } 636 + }; 637 + 638 + static const struct software_node ktd2026_green_led_node = { 639 + .properties = ktd2026_green_led_props, 640 + .parent = &ktd2026_rgb_led_node, 641 + }; 642 + 643 + static const struct property_entry ktd2026_red_led_props[] = { 644 + PROPERTY_ENTRY_U32("reg", 2), 645 + PROPERTY_ENTRY_U32("color", LED_COLOR_ID_RED), 646 + { } 647 + }; 648 + 649 + static const struct software_node ktd2026_red_led_node = { 650 + .properties = ktd2026_red_led_props, 651 + .parent = &ktd2026_rgb_led_node, 652 + }; 653 + 654 + static const struct software_node *ktd2026_node_group[] = { 655 + &ktd2026_node, 656 + &ktd2026_rgb_led_node, 657 + &ktd2026_red_led_node, 658 + &ktd2026_green_led_node, 659 + &ktd2026_blue_led_node, 660 + NULL 661 + }; 662 + 663 + /* 664 + * For the LEDs which backlight the menu / home / back capacitive buttons on 665 + * the bottom bezel. These are attached to a TPS61158 LED controller which 666 + * is controlled by the "pwm_soc_lpss_2" PWM output. 667 + */ 668 + #define XIAOMI_MIPAD2_LED_PERIOD_NS 19200 669 + #define XIAOMI_MIPAD2_LED_DEFAULT_DUTY 6000 /* From Android kernel */ 670 + 671 + static struct pwm_device *xiaomi_mipad2_led_pwm; 672 + 673 + static int xiaomi_mipad2_brightness_set(struct led_classdev *led_cdev, 674 + enum led_brightness val) 675 + { 676 + struct pwm_state state = { 677 + .period = XIAOMI_MIPAD2_LED_PERIOD_NS, 678 + .duty_cycle = val, 679 + /* Always set PWM enabled to avoid the pin floating */ 680 + .enabled = true, 681 + }; 682 + 683 + return pwm_apply_might_sleep(xiaomi_mipad2_led_pwm, &state); 684 + } 685 + 686 + static int __init xiaomi_mipad2_init(struct device *dev) 687 + { 688 + struct led_classdev *led_cdev; 689 + int ret; 690 + 691 + xiaomi_mipad2_led_pwm = devm_pwm_get(dev, "pwm_soc_lpss_2"); 692 + if (IS_ERR(xiaomi_mipad2_led_pwm)) 693 + return dev_err_probe(dev, PTR_ERR(xiaomi_mipad2_led_pwm), "getting pwm\n"); 694 + 695 + led_cdev = devm_kzalloc(dev, sizeof(*led_cdev), GFP_KERNEL); 696 + if (!led_cdev) 697 + return -ENOMEM; 698 + 699 + led_cdev->name = "mipad2:white:touch-buttons-backlight"; 700 + led_cdev->max_brightness = XIAOMI_MIPAD2_LED_PERIOD_NS; 701 + /* "input-events" trigger uses blink_brightness */ 702 + led_cdev->blink_brightness = XIAOMI_MIPAD2_LED_DEFAULT_DUTY; 703 + led_cdev->default_trigger = "input-events"; 704 + led_cdev->brightness_set_blocking = xiaomi_mipad2_brightness_set; 705 + 706 + ret = devm_led_classdev_register(dev, led_cdev); 707 + if (ret) 708 + return dev_err_probe(dev, ret, "registering LED\n"); 709 + 710 + return software_node_register_node_group(ktd2026_node_group); 711 + } 712 + 713 + static void xiaomi_mipad2_exit(void) 714 + { 715 + software_node_unregister_node_group(ktd2026_node_group); 716 + } 717 + 718 + /* 601 719 * If the EFI bootloader is not Xiaomi's own signed Android loader, then the 602 720 * Xiaomi Mi Pad 2 X86 tablet sets OSID in the DSDT to 1 (Windows), causing 603 721 * a bunch of devices to be hidden. ··· 742 616 .type = "ktd2026", 743 617 .addr = 0x30, 744 618 .dev_name = "ktd2026", 619 + .swnode = &ktd2026_node, 745 620 }, 746 621 .adapter_path = "\\_SB_.PCI0.I2C3", 747 622 }, ··· 751 624 const struct x86_dev_info xiaomi_mipad2_info __initconst = { 752 625 .i2c_client_info = xiaomi_mipad2_i2c_clients, 753 626 .i2c_client_count = ARRAY_SIZE(xiaomi_mipad2_i2c_clients), 627 + .init = xiaomi_mipad2_init, 628 + .exit = xiaomi_mipad2_exit, 754 629 };
+2 -1
drivers/platform/x86/x86-android-tablets/x86-android-tablets.h
··· 89 89 int pdev_count; 90 90 int serdev_count; 91 91 int gpio_button_count; 92 - int (*init)(void); 92 + int (*init)(struct device *dev); 93 93 void (*exit)(void); 94 94 }; 95 95 ··· 112 112 extern const struct x86_dev_info lenovo_yogabook_x90_info; 113 113 extern const struct x86_dev_info lenovo_yogabook_x91_info; 114 114 extern const struct x86_dev_info lenovo_yoga_tab2_830_1050_info; 115 + extern const struct x86_dev_info lenovo_yoga_tab2_1380_info; 115 116 extern const struct x86_dev_info lenovo_yt3_info; 116 117 extern const struct x86_dev_info medion_lifetab_s10346_info; 117 118 extern const struct x86_dev_info nextbook_ares8_info;
+21 -9
drivers/platform/x86/xiaomi-wmi.c
··· 2 2 /* WMI driver for Xiaomi Laptops */ 3 3 4 4 #include <linux/acpi.h> 5 + #include <linux/device.h> 5 6 #include <linux/input.h> 6 7 #include <linux/module.h> 8 + #include <linux/mutex.h> 7 9 #include <linux/wmi.h> 8 10 9 11 #include <uapi/linux/input-event-codes.h> ··· 22 20 23 21 struct xiaomi_wmi { 24 22 struct input_dev *input_dev; 23 + struct mutex key_lock; /* Protects the key event sequence */ 25 24 unsigned int key_code; 26 25 }; 26 + 27 + static void xiaomi_mutex_destroy(void *data) 28 + { 29 + struct mutex *lock = data; 30 + 31 + mutex_destroy(lock); 32 + } 27 33 28 34 static int xiaomi_wmi_probe(struct wmi_device *wdev, const void *context) 29 35 { 30 36 struct xiaomi_wmi *data; 37 + int ret; 31 38 32 - if (wdev == NULL || context == NULL) 39 + if (!context) 33 40 return -EINVAL; 34 41 35 42 data = devm_kzalloc(&wdev->dev, sizeof(struct xiaomi_wmi), GFP_KERNEL); 36 43 if (data == NULL) 37 44 return -ENOMEM; 38 45 dev_set_drvdata(&wdev->dev, data); 46 + 47 + mutex_init(&data->key_lock); 48 + ret = devm_add_action_or_reset(&wdev->dev, xiaomi_mutex_destroy, &data->key_lock); 49 + if (ret < 0) 50 + return ret; 39 51 40 52 data->input_dev = devm_input_allocate_device(&wdev->dev); 41 53 if (data->input_dev == NULL) ··· 66 50 67 51 static void xiaomi_wmi_notify(struct wmi_device *wdev, union acpi_object *dummy) 68 52 { 69 - struct xiaomi_wmi *data; 53 + struct xiaomi_wmi *data = dev_get_drvdata(&wdev->dev); 70 54 71 - if (wdev == NULL) 72 - return; 73 - 74 - data = dev_get_drvdata(&wdev->dev); 75 - if (data == NULL) 76 - return; 77 - 55 + mutex_lock(&data->key_lock); 78 56 input_report_key(data->input_dev, data->key_code, 1); 79 57 input_sync(data->input_dev); 80 58 input_report_key(data->input_dev, data->key_code, 0); 81 59 input_sync(data->input_dev); 60 + mutex_unlock(&data->key_lock); 82 61 } 83 62 84 63 static const struct wmi_device_id xiaomi_wmi_id_table[] = { ··· 94 83 .id_table = xiaomi_wmi_id_table, 95 84 .probe = xiaomi_wmi_probe, 96 85 .notify = xiaomi_wmi_notify, 86 + .no_singleton = true, 97 87 }; 98 88 module_wmi_driver(xiaomi_wmi_driver); 99 89
+1
include/dt-bindings/leds/common.h
··· 46 46 #define LED_FUNCTION_CAPSLOCK "capslock" 47 47 #define LED_FUNCTION_SCROLLLOCK "scrolllock" 48 48 #define LED_FUNCTION_NUMLOCK "numlock" 49 + #define LED_FUNCTION_FNLOCK "fnlock" 49 50 /* Obsolete equivalents: "tpacpi::thinklight" (IBM/Lenovo Thinkpads), 50 51 "lp5523:kb{1,2,3,4,5,6}" (Nokia N900) */ 51 52 #define LED_FUNCTION_KBD_BACKLIGHT "kbd_backlight"
+2 -2
include/linux/devm-helpers.h
··· 41 41 * detached. A few drivers need delayed work which must be cancelled before 42 42 * driver is detached to avoid accessing removed resources. 43 43 * devm_delayed_work_autocancel() can be used to omit the explicit 44 - * cancelleation when driver is detached. 44 + * cancellation when driver is detached. 45 45 */ 46 46 static inline int devm_delayed_work_autocancel(struct device *dev, 47 47 struct delayed_work *w, ··· 66 66 * A few drivers need to queue work which must be cancelled before driver 67 67 * is detached to avoid accessing removed resources. 68 68 * devm_work_autocancel() can be used to omit the explicit 69 - * cancelleation when driver is detached. 69 + * cancellation when driver is detached. 70 70 */ 71 71 static inline int devm_work_autocancel(struct device *dev, 72 72 struct work_struct *w,
+9 -3
include/linux/intel_tpmi.h
··· 27 27 28 28 /** 29 29 * struct intel_tpmi_plat_info - Platform information for a TPMI device instance 30 - * @package_id: CPU Package id 31 - * @bus_number: PCI bus number 32 - * @device_number: PCI device number 30 + * @cdie_mask: Mask of all compute dies in the partition 31 + * @package_id: CPU Package id 32 + * @partition: Package partition id when multiple VSEC PCI devices per package 33 + * @segment: PCI segment ID 34 + * @bus_number: PCI bus number 35 + * @device_number: PCI device number 33 36 * @function_number: PCI function number 34 37 * 35 38 * Structure to store platform data for a TPMI device instance. This 36 39 * struct is used to return data via tpmi_get_platform_data(). 37 40 */ 38 41 struct intel_tpmi_plat_info { 42 + u16 cdie_mask; 39 43 u8 package_id; 44 + u8 partition; 45 + u8 segment; 40 46 u8 bus_number; 41 47 u8 device_number; 42 48 u8 function_number;
+6
include/linux/platform_data/x86/asus-wmi.h
··· 71 71 #define ASUS_WMI_DEVID_LID_FLIP 0x00060062 72 72 #define ASUS_WMI_DEVID_LID_FLIP_ROG 0x00060077 73 73 #define ASUS_WMI_DEVID_MINI_LED_MODE 0x0005001E 74 + #define ASUS_WMI_DEVID_MINI_LED_MODE2 0x0005002E 74 75 75 76 /* Storage */ 76 77 #define ASUS_WMI_DEVID_CARDREADER 0x00080013 ··· 128 127 129 128 /* gpu mux switch, 0 = dGPU, 1 = Optimus */ 130 129 #define ASUS_WMI_DEVID_GPU_MUX 0x00090016 130 + #define ASUS_WMI_DEVID_GPU_MUX_VIVO 0x00090026 131 131 132 132 /* TUF laptop RGB modes/colours */ 133 133 #define ASUS_WMI_DEVID_TUF_RGB_MODE 0x00100056 134 + #define ASUS_WMI_DEVID_TUF_RGB_MODE2 0x0010005A 134 135 135 136 /* TUF laptop RGB power/state */ 136 137 #define ASUS_WMI_DEVID_TUF_RGB_STATE 0x00100057 138 + 139 + /* Bootup sound control */ 140 + #define ASUS_WMI_DEVID_BOOT_SOUND 0x00130022 137 141 138 142 /* DSTS masks */ 139 143 #define ASUS_WMI_DSTS_STATUS_BIT 0x00000001
+1
include/linux/platform_profile.h
··· 36 36 37 37 int platform_profile_register(struct platform_profile_handler *pprof); 38 38 int platform_profile_remove(void); 39 + int platform_profile_cycle(void); 39 40 void platform_profile_notify(void); 40 41 41 42 #endif /*_PLATFORM_PROFILE_H_*/
+1 -1
include/trace/events/intel_ifs.h
··· 28 28 __entry->status = status; 29 29 ), 30 30 31 - TP_printk("batch: %.2d, start: %.4x, stop: %.4x, status: %.16llx", 31 + TP_printk("batch: 0x%.2x, start: 0x%.4x, stop: 0x%.4x, status: 0x%.16llx", 32 32 __entry->batch, 33 33 __entry->start, 34 34 __entry->stop,
+1
tools/arch/x86/dell-uart-backlight-emulator/.gitignore
··· 1 + dell-uart-backlight-emulator
+19
tools/arch/x86/dell-uart-backlight-emulator/Makefile
··· 1 + # SPDX-License-Identifier: GPL-2.0 2 + # Makefile for Intel Software Defined Silicon provisioning tool 3 + 4 + dell-uart-backlight-emulator: dell-uart-backlight-emulator.c 5 + 6 + BINDIR ?= /usr/bin 7 + 8 + override CFLAGS += -O2 -Wall 9 + 10 + %: %.c 11 + $(CC) $(CFLAGS) -o $@ $< $(LDFLAGS) 12 + 13 + .PHONY : clean 14 + clean : 15 + @rm -f dell-uart-backlight-emulator 16 + 17 + install : dell-uart-backlight-emulator 18 + install -d $(DESTDIR)$(BINDIR) 19 + install -m 755 -p dell-uart-backlight-emulator $(DESTDIR)$(BINDIR)/dell-uart-backlight-emulator
+46
tools/arch/x86/dell-uart-backlight-emulator/README
··· 1 + Emulator for DELL0501 UART attached backlight controller 2 + -------------------------------------------------------- 3 + 4 + Dell All In One (AIO) models released after 2017 use a backlight controller 5 + board connected to an UART. 6 + 7 + In DSDT this uart port will be defined as: 8 + 9 + Name (_HID, "DELL0501") 10 + Name (_CID, EisaId ("PNP0501") 11 + 12 + With the DELL0501 indicating that we are dealing with an UART with 13 + the backlight controller board attached. 14 + 15 + This small emulator allows testing 16 + the drivers/platform/x86/dell/dell-uart-backlight.c driver without access 17 + to an actual Dell All In One. 18 + 19 + This requires: 20 + 1. A (desktop) PC with a 16550 UART on the motherboard and a standard DB9 21 + connector connected to this UART. 22 + 2. A DB9 NULL modem cable. 23 + 3. A second DB9 serial port, this can e.g. be a USB to serial converter 24 + with a DB9 connector plugged into the same desktop PC. 25 + 4. A DSDT overlay for the desktop PC replacing the _HID of the 16550 UART 26 + ACPI Device() with "DELL0501" and adding a _CID of "PNP0501", see 27 + DSDT.patch for an example of the necessary DSDT changes. 28 + 29 + With everything setup and the NULL modem cable connected between 30 + the 2 serial ports run: 31 + 32 + ./dell-uart-backlight-emulator <path-to-/dev/tty*S#-for-second-port> 33 + 34 + For example when using an USB to serial converter for the second port: 35 + 36 + ./dell-uart-backlight-emulator /dev/ttyUSB0 37 + 38 + And then (re)load the dell-uart-backlight driver: 39 + 40 + sudo rmmod dell-uart-backlight; sudo modprobe dell-uart-backlight dyndbg 41 + 42 + After this check "dmesg" to see if the driver correctly received 43 + the firmware version string from the emulator. If this works there 44 + should be a /sys/class/backlight/dell_uart_backlight/ directory now 45 + and writes to the brightness or bl_power files should be reflected 46 + by matching output from the emulator.
+163
tools/arch/x86/dell-uart-backlight-emulator/dell-uart-backlight-emulator.c
··· 1 + // SPDX-License-Identifier: GPL-2.0-or-later 2 + /* 3 + * Dell AIO Serial Backlight board emulator for testing 4 + * the Linux dell-uart-backlight driver. 5 + * 6 + * Copyright (C) 2024 Hans de Goede <hansg@kernel.org> 7 + */ 8 + #include <errno.h> 9 + #include <fcntl.h> 10 + #include <signal.h> 11 + #include <stdio.h> 12 + #include <stdlib.h> 13 + #include <string.h> 14 + #include <sys/ioctl.h> 15 + #include <sys/stat.h> 16 + #include <sys/types.h> 17 + #include <sys/un.h> 18 + #include <termios.h> 19 + #include <unistd.h> 20 + 21 + int serial_fd; 22 + int brightness = 50; 23 + 24 + static unsigned char dell_uart_checksum(unsigned char *buf, int len) 25 + { 26 + unsigned char val = 0; 27 + 28 + while (len-- > 0) 29 + val += buf[len]; 30 + 31 + return val ^ 0xff; 32 + } 33 + 34 + /* read() will return -1 on SIGINT / SIGTERM causing the mainloop to cleanly exit */ 35 + void signalhdlr(int signum) 36 + { 37 + } 38 + 39 + int main(int argc, char *argv[]) 40 + { 41 + struct sigaction sigact = { .sa_handler = signalhdlr }; 42 + unsigned char buf[4], csum, response[32]; 43 + const char *version_str = "PHI23-V321"; 44 + struct termios tty, saved_tty; 45 + int ret, idx, len = 0; 46 + 47 + if (argc != 2) { 48 + fprintf(stderr, "Invalid or missing arguments\n"); 49 + fprintf(stderr, "Usage: %s <serial-port>\n", argv[0]); 50 + return 1; 51 + } 52 + 53 + serial_fd = open(argv[1], O_RDWR | O_NOCTTY); 54 + if (serial_fd == -1) { 55 + fprintf(stderr, "Error opening %s: %s\n", argv[1], strerror(errno)); 56 + return 1; 57 + } 58 + 59 + ret = tcgetattr(serial_fd, &tty); 60 + if (ret == -1) { 61 + fprintf(stderr, "Error getting tcattr: %s\n", strerror(errno)); 62 + goto out_close; 63 + } 64 + saved_tty = tty; 65 + 66 + cfsetspeed(&tty, 9600); 67 + cfmakeraw(&tty); 68 + tty.c_cflag &= ~CSTOPB; 69 + tty.c_cflag &= ~CRTSCTS; 70 + tty.c_cflag |= CLOCAL | CREAD; 71 + 72 + ret = tcsetattr(serial_fd, TCSANOW, &tty); 73 + if (ret == -1) { 74 + fprintf(stderr, "Error setting tcattr: %s\n", strerror(errno)); 75 + goto out_restore; 76 + } 77 + 78 + sigaction(SIGINT, &sigact, 0); 79 + sigaction(SIGTERM, &sigact, 0); 80 + 81 + idx = 0; 82 + while (read(serial_fd, &buf[idx], 1) == 1) { 83 + if (idx == 0) { 84 + switch (buf[0]) { 85 + /* 3 MSB bits: cmd-len + 01010 SOF marker */ 86 + case 0x6a: len = 3; break; 87 + case 0x8a: len = 4; break; 88 + default: 89 + fprintf(stderr, "Error unexpected first byte: 0x%02x\n", buf[0]); 90 + continue; /* Try to sync up with sender */ 91 + } 92 + } 93 + 94 + /* Process msg when len bytes have been received */ 95 + if (idx != (len - 1)) { 96 + idx++; 97 + continue; 98 + } 99 + 100 + /* Reset idx for next command */ 101 + idx = 0; 102 + 103 + csum = dell_uart_checksum(buf, len - 1); 104 + if (buf[len - 1] != csum) { 105 + fprintf(stderr, "Error checksum mismatch got 0x%02x expected 0x%02x\n", 106 + buf[len - 1], csum); 107 + continue; 108 + } 109 + 110 + switch ((buf[0] << 8) | buf[1]) { 111 + case 0x6a06: /* cmd = 0x06, get version */ 112 + len = strlen(version_str); 113 + strcpy((char *)&response[2], version_str); 114 + printf("Get version, reply: %s\n", version_str); 115 + break; 116 + case 0x8a0b: /* cmd = 0x0b, set brightness */ 117 + if (buf[2] > 100) { 118 + fprintf(stderr, "Error invalid brightness param: %d\n", buf[2]); 119 + continue; 120 + } 121 + 122 + len = 0; 123 + brightness = buf[2]; 124 + printf("Set brightness %d\n", brightness); 125 + break; 126 + case 0x6a0c: /* cmd = 0x0c, get brightness */ 127 + len = 1; 128 + response[2] = brightness; 129 + printf("Get brightness, reply: %d\n", brightness); 130 + break; 131 + case 0x8a0e: /* cmd = 0x0e, set backlight power */ 132 + if (buf[2] != 0 && buf[2] != 1) { 133 + fprintf(stderr, "Error invalid set power param: %d\n", buf[2]); 134 + continue; 135 + } 136 + 137 + len = 0; 138 + printf("Set power %d\n", buf[2]); 139 + break; 140 + default: 141 + fprintf(stderr, "Error unknown cmd 0x%04x\n", 142 + (buf[0] << 8) | buf[1]); 143 + continue; 144 + } 145 + 146 + /* Respond with <total-len> <cmd> <data...> <csum> */ 147 + response[0] = len + 3; /* response length in bytes */ 148 + response[1] = buf[1]; /* ack cmd */ 149 + csum = dell_uart_checksum(response, len + 2); 150 + response[len + 2] = csum; 151 + ret = write(serial_fd, response, response[0]); 152 + if (ret != (response[0])) 153 + fprintf(stderr, "Error writing %d bytes: %d\n", 154 + response[0], ret); 155 + } 156 + 157 + ret = 0; 158 + out_restore: 159 + tcsetattr(serial_fd, TCSANOW, &saved_tty); 160 + out_close: 161 + close(serial_fd); 162 + return ret; 163 + }
+66 -42
tools/arch/x86/intel_sdsi/intel_sdsi.c
··· 43 43 #define METER_CERT_MAX_SIZE 4096 44 44 #define STATE_MAX_NUM_LICENSES 16 45 45 #define STATE_MAX_NUM_IN_BUNDLE (uint32_t)8 46 - #define METER_MAX_NUM_BUNDLES 8 46 + #define FEAT_LEN 5 /* 4 plus NUL terminator */ 47 47 48 48 #define __round_mask(x, y) ((__typeof__(x))((y) - 1)) 49 49 #define round_up(x, y) ((((x) - 1) | __round_mask(x, y)) + 1) ··· 154 154 }; 155 155 156 156 struct meter_certificate { 157 - uint32_t block_signature; 158 - uint32_t counter_unit; 157 + uint32_t signature; 158 + uint32_t version; 159 159 uint64_t ppin; 160 + uint32_t counter_unit; 160 161 uint32_t bundle_length; 161 - uint32_t reserved; 162 + uint64_t reserved; 162 163 uint32_t mmrc_encoding; 163 164 uint32_t mmrc_counter; 164 165 }; ··· 168 167 uint32_t encoding; 169 168 uint32_t counter; 170 169 }; 170 + #define METER_BUNDLE_SIZE sizeof(struct bundle_encoding_counter) 171 + #define BUNDLE_COUNT(length) ((length) / METER_BUNDLE_SIZE) 172 + #define METER_MAX_NUM_BUNDLES \ 173 + ((METER_CERT_MAX_SIZE - sizeof(struct meter_certificate)) / \ 174 + sizeof(struct bundle_encoding_counter)) 171 175 172 176 struct sdsi_dev { 173 177 struct sdsi_regs regs; ··· 185 179 enum command { 186 180 CMD_SOCKET_INFO, 187 181 CMD_METER_CERT, 182 + CMD_METER_CURRENT_CERT, 188 183 CMD_STATE_CERT, 189 184 CMD_PROV_AKC, 190 185 CMD_PROV_CAP, ··· 323 316 } 324 317 } 325 318 326 - static void get_feature(uint32_t encoding, char *feature) 319 + static void get_feature(uint32_t encoding, char feature[5]) 327 320 { 328 321 char *name = (char *)&encoding; 329 322 323 + feature[4] = '\0'; 330 324 feature[3] = name[0]; 331 325 feature[2] = name[1]; 332 326 feature[1] = name[2]; 333 327 feature[0] = name[3]; 334 328 } 335 329 336 - static int sdsi_meter_cert_show(struct sdsi_dev *s) 330 + static int sdsi_meter_cert_show(struct sdsi_dev *s, bool show_current) 337 331 { 338 332 char buf[METER_CERT_MAX_SIZE] = {0}; 339 333 struct bundle_encoding_counter *bec; 340 334 struct meter_certificate *mc; 341 335 uint32_t count = 0; 342 336 FILE *cert_ptr; 337 + char *cert_fname; 343 338 int ret, size; 339 + char name[FEAT_LEN]; 344 340 345 341 ret = sdsi_update_registers(s); 346 342 if (ret) ··· 351 341 352 342 if (!s->regs.en_features.sdsi) { 353 343 fprintf(stderr, "SDSi feature is present but not enabled.\n"); 354 - fprintf(stderr, " Unable to read meter certificate\n"); 355 344 return -1; 356 345 } 357 346 ··· 365 356 return ret; 366 357 } 367 358 368 - cert_ptr = fopen("meter_certificate", "r"); 359 + cert_fname = show_current ? "meter_current" : "meter_certificate"; 360 + cert_ptr = fopen(cert_fname, "r"); 361 + 369 362 if (!cert_ptr) { 370 - perror("Could not open 'meter_certificate' file"); 363 + fprintf(stderr, "Could not open '%s' file: %s", cert_fname, strerror(errno)); 371 364 return -1; 372 365 } 373 366 374 367 size = fread(buf, 1, sizeof(buf), cert_ptr); 375 368 if (!size) { 376 - fprintf(stderr, "Could not read 'meter_certificate' file\n"); 369 + fprintf(stderr, "Could not read '%s' file\n", cert_fname); 377 370 fclose(cert_ptr); 378 371 return -1; 379 372 } ··· 386 375 printf("\n"); 387 376 printf("Meter certificate for device %s\n", s->dev_name); 388 377 printf("\n"); 389 - printf("Block Signature: 0x%x\n", mc->block_signature); 390 - printf("Count Unit: %dms\n", mc->counter_unit); 391 - printf("PPIN: 0x%lx\n", mc->ppin); 392 - printf("Feature Bundle Length: %d\n", mc->bundle_length); 393 - printf("MMRC encoding: %d\n", mc->mmrc_encoding); 394 - printf("MMRC counter: %d\n", mc->mmrc_counter); 395 - if (mc->bundle_length % 8) { 378 + 379 + get_feature(mc->signature, name); 380 + printf("Signature: %s\n", name); 381 + 382 + printf("Version: %d\n", mc->version); 383 + printf("Count Unit: %dms\n", mc->counter_unit); 384 + printf("PPIN: 0x%lx\n", mc->ppin); 385 + printf("Feature Bundle Length: %d\n", mc->bundle_length); 386 + 387 + get_feature(mc->mmrc_encoding, name); 388 + printf("MMRC encoding: %s\n", name); 389 + 390 + printf("MMRC counter: %d\n", mc->mmrc_counter); 391 + if (mc->bundle_length % METER_BUNDLE_SIZE) { 396 392 fprintf(stderr, "Invalid bundle length\n"); 397 393 return -1; 398 394 } 399 395 400 - if (mc->bundle_length > METER_MAX_NUM_BUNDLES * 8) { 401 - fprintf(stderr, "More than %d bundles: %d\n", 402 - METER_MAX_NUM_BUNDLES, mc->bundle_length / 8); 396 + if (mc->bundle_length > METER_MAX_NUM_BUNDLES * METER_BUNDLE_SIZE) { 397 + fprintf(stderr, "More than %ld bundles: actual %ld\n", 398 + METER_MAX_NUM_BUNDLES, BUNDLE_COUNT(mc->bundle_length)); 403 399 return -1; 404 400 } 405 401 406 - bec = (void *)(mc) + sizeof(mc); 402 + bec = (struct bundle_encoding_counter *)(mc + 1); 407 403 408 - printf("Number of Feature Counters: %d\n", mc->bundle_length / 8); 409 - while (count++ < mc->bundle_length / 8) { 410 - char feature[5]; 404 + printf("Number of Feature Counters: %ld\n", BUNDLE_COUNT(mc->bundle_length)); 405 + while (count < BUNDLE_COUNT(mc->bundle_length)) { 406 + char feature[FEAT_LEN]; 411 407 412 - feature[4] = '\0'; 413 408 get_feature(bec[count].encoding, feature); 414 409 printf(" %s: %d\n", feature, bec[count].counter); 410 + ++count; 415 411 } 416 412 417 413 return 0; ··· 498 480 sizeof(*lki) + // size of the license key info 499 481 offset; // offset to this blob content 500 482 struct bundle_encoding *bundle = (void *)(lbc) + sizeof(*lbc); 501 - char feature[5]; 483 + char feature[FEAT_LEN]; 502 484 uint32_t i; 503 485 504 486 printf(" Blob %d:\n", count - 1); ··· 510 492 printf(" Previous PPIN: 0x%lx\n", lbc->previous_ppin); 511 493 printf(" Blob revision ID: %u\n", lbc->rev_id); 512 494 printf(" Number of Features: %u\n", lbc->num_bundles); 513 - 514 - feature[4] = '\0'; 515 495 516 496 for (i = 0; i < min(lbc->num_bundles, STATE_MAX_NUM_IN_BUNDLE); i++) { 517 497 get_feature(bundle[i].encoding, feature); ··· 741 725 742 726 static void usage(char *prog) 743 727 { 744 - printf("Usage: %s [-l] [-d DEVNO [-i] [-s] [-m] [-a FILE] [-c FILE]]\n", prog); 728 + printf("Usage: %s [-l] [-d DEVNO [-i] [-s] [-m | -C] [-a FILE] [-c FILE]\n", prog); 745 729 } 746 730 747 731 static void show_help(void) ··· 750 734 printf(" %-18s\t%s\n", "-l, --list", "list available On Demand devices"); 751 735 printf(" %-18s\t%s\n", "-d, --devno DEVNO", "On Demand device number"); 752 736 printf(" %-18s\t%s\n", "-i, --info", "show socket information"); 753 - printf(" %-18s\t%s\n", "-s, --state", "show state certificate"); 754 - printf(" %-18s\t%s\n", "-m, --meter", "show meter certificate"); 737 + printf(" %-18s\t%s\n", "-s, --state", "show state certificate data"); 738 + printf(" %-18s\t%s\n", "-m, --meter", "show meter certificate data"); 739 + printf(" %-18s\t%s\n", "-C, --meter_current", "show live unattested meter data"); 755 740 printf(" %-18s\t%s\n", "-a, --akc FILE", "provision socket with AKC FILE"); 756 741 printf(" %-18s\t%s\n", "-c, --cap FILE>", "provision socket with CAP FILE"); 757 742 } ··· 768 751 int option_index = 0; 769 752 770 753 static struct option long_options[] = { 771 - {"akc", required_argument, 0, 'a'}, 772 - {"cap", required_argument, 0, 'c'}, 773 - {"devno", required_argument, 0, 'd'}, 774 - {"help", no_argument, 0, 'h'}, 775 - {"info", no_argument, 0, 'i'}, 776 - {"list", no_argument, 0, 'l'}, 777 - {"meter", no_argument, 0, 'm'}, 778 - {"state", no_argument, 0, 's'}, 779 - {0, 0, 0, 0 } 754 + {"akc", required_argument, 0, 'a'}, 755 + {"cap", required_argument, 0, 'c'}, 756 + {"devno", required_argument, 0, 'd'}, 757 + {"help", no_argument, 0, 'h'}, 758 + {"info", no_argument, 0, 'i'}, 759 + {"list", no_argument, 0, 'l'}, 760 + {"meter", no_argument, 0, 'm'}, 761 + {"meter_current", no_argument, 0, 'C'}, 762 + {"state", no_argument, 0, 's'}, 763 + {0, 0, 0, 0 } 780 764 }; 781 765 782 766 783 767 progname = argv[0]; 784 768 785 - while ((opt = getopt_long_only(argc, argv, "+a:c:d:hilms", long_options, 769 + while ((opt = getopt_long_only(argc, argv, "+a:c:d:hilmCs", long_options, 786 770 &option_index)) != -1) { 787 771 switch (opt) { 788 772 case 'd': ··· 798 780 break; 799 781 case 'm': 800 782 command = CMD_METER_CERT; 783 + break; 784 + case 'C': 785 + command = CMD_METER_CURRENT_CERT; 801 786 break; 802 787 case 's': 803 788 command = CMD_STATE_CERT; ··· 840 819 ret = sdsi_read_reg(s); 841 820 break; 842 821 case CMD_METER_CERT: 843 - ret = sdsi_meter_cert_show(s); 822 + ret = sdsi_meter_cert_show(s, false); 823 + break; 824 + case CMD_METER_CURRENT_CERT: 825 + ret = sdsi_meter_cert_show(s, true); 844 826 break; 845 827 case CMD_STATE_CERT: 846 828 ret = sdsi_state_cert_show(s);
+23 -2
tools/power/x86/intel-speed-select/isst-config.c
··· 16 16 int arg; 17 17 }; 18 18 19 - static const char *version_str = "v1.18"; 19 + static const char *version_str = "v1.19"; 20 20 21 - static const int supported_api_ver = 2; 21 + static const int supported_api_ver = 3; 22 22 static struct isst_if_platform_info isst_platform_info; 23 23 static char *progname; 24 24 static int debug_flag; ··· 46 46 static int auto_mode; 47 47 static int fact_enable_fail; 48 48 static int cgroupv2; 49 + static int max_die_id; 50 + static int max_punit_id; 49 51 50 52 /* clos related */ 51 53 static int current_clos = -1; ··· 564 562 } 565 563 566 564 for (i = 0; i < MAX_PACKAGE_COUNT; i++) { 565 + if (max_die_id == max_punit_id) { 566 + for (k = 0; k < MAX_PUNIT_PER_DIE && k < MAX_DIE_PER_PACKAGE; k++) { 567 + id.cpu = cpus[i][k][k]; 568 + id.pkg = i; 569 + id.die = k; 570 + id.punit = k; 571 + if (isst_is_punit_valid(&id)) 572 + callback(&id, arg1, arg2, arg3, arg4); 573 + } 574 + continue; 575 + } 576 + 567 577 for (j = 0; j < MAX_DIE_PER_PACKAGE; j++) { 568 578 /* 569 579 * Fix me: ··· 808 794 cpu_map[i].initialized = 1; 809 795 810 796 cpu_cnt[pkg_id][die_id][punit_id]++; 797 + 798 + if (max_die_id < die_id) 799 + max_die_id = die_id; 800 + 801 + if (max_punit_id < cpu_map[i].punit_id) 802 + max_punit_id = cpu_map[i].punit_id; 811 803 812 804 debug_printf( 813 805 "map logical_cpu:%d core: %d die:%d pkg:%d punit:%d punit_cpu:%d punit_core:%d\n", ··· 2074 2054 struct isst_fact_info fact_info; 2075 2055 int ret; 2076 2056 2057 + memset(&fact_info, 0, sizeof(fact_info)); 2077 2058 ret = isst_get_fact_info(id, tdp_level, fact_bucket, &fact_info); 2078 2059 if (ret) { 2079 2060 isst_display_error_info_message(1, "Failed to get turbo-freq info at this level", 1, tdp_level);
+2 -1
tools/power/x86/intel-speed-select/isst-core-mbox.c
··· 746 746 static int _get_fact_bucket_info(struct isst_id *id, int level, 747 747 struct isst_fact_bucket_info *bucket_info) 748 748 { 749 + int trl_max_levels = isst_get_trl_max_levels(); 749 750 unsigned int resp; 750 751 int i, k, ret; 751 752 ··· 770 769 } 771 770 } 772 771 773 - for (k = 0; k < 3; ++k) { 772 + for (k = 0; k < trl_max_levels; ++k) { 774 773 for (i = 0; i < 2; ++i) { 775 774 int j; 776 775
+8 -2
tools/power/x86/intel-speed-select/isst-core-tpmi.c
··· 194 194 if (!(info.level_mask & level_mask)) 195 195 return -1; 196 196 197 - ctdp_level->fact_support = info.sst_tf_support; 198 - ctdp_level->pbf_support = info.sst_bf_support; 197 + if (api_version() > 2) { 198 + ctdp_level->fact_support = info.sst_tf_support & BIT(config_index); 199 + ctdp_level->pbf_support = info.sst_bf_support & BIT(config_index); 200 + } else { 201 + ctdp_level->fact_support = info.sst_tf_support; 202 + ctdp_level->pbf_support = info.sst_bf_support; 203 + } 204 + 199 205 ctdp_level->fact_enabled = !!(info.feature_state & BIT(1)); 200 206 ctdp_level->pbf_enabled = !!(info.feature_state & BIT(0)); 201 207
+1
tools/power/x86/intel-speed-select/isst-core.c
··· 23 23 isst_ops = mbox_get_platform_ops(); 24 24 break; 25 25 case 2: 26 + case 3: 26 27 isst_ops = tpmi_get_platform_ops(); 27 28 break; 28 29 default:
+21 -9
tools/power/x86/intel-speed-select/isst-display.c
··· 172 172 int level = 1; 173 173 174 174 if (out_format_is_json()) { 175 - if (api_version() > 1) 176 - snprintf(header, sizeof(header), "package-%d:die-%d:powerdomain-%d:cpu-%d", 177 - id->pkg, id->die, id->punit, id->cpu); 178 - else 175 + if (api_version() > 1) { 176 + if (id->cpu < 0) 177 + snprintf(header, sizeof(header), 178 + "package-%d:die-%d:powerdomain-%d:cpu-None", 179 + id->pkg, id->die, id->punit); 180 + else 181 + snprintf(header, sizeof(header), 182 + "package-%d:die-%d:powerdomain-%d:cpu-%d", 183 + id->pkg, id->die, id->punit, id->cpu); 184 + } else { 179 185 snprintf(header, sizeof(header), "package-%d:die-%d:cpu-%d", 180 186 id->pkg, id->die, id->cpu); 187 + } 181 188 format_and_print(outf, level, header, NULL); 182 189 return 1; 183 190 } ··· 196 189 snprintf(header, sizeof(header), "powerdomain-%d", id->punit); 197 190 format_and_print(outf, level++, header, NULL); 198 191 } 199 - snprintf(header, sizeof(header), "cpu-%d", id->cpu); 192 + 193 + if (id->cpu < 0) 194 + snprintf(header, sizeof(header), "cpu-None"); 195 + else 196 + snprintf(header, sizeof(header), "cpu-%d", id->cpu); 197 + 200 198 format_and_print(outf, level, header, NULL); 201 199 202 200 return level; ··· 211 199 struct isst_pbf_info *pbf_info, 212 200 int disp_level) 213 201 { 214 - char header[256]; 215 - char value[512]; 202 + static char header[256]; 203 + static char value[1024]; 216 204 217 205 snprintf(header, sizeof(header), "speed-select-base-freq-properties"); 218 206 format_and_print(outf, disp_level, header, NULL); ··· 350 338 void isst_ctdp_display_information(struct isst_id *id, FILE *outf, int tdp_level, 351 339 struct isst_pkg_ctdp *pkg_dev) 352 340 { 353 - char header[256]; 354 - char value[512]; 341 + static char header[256]; 342 + static char value[1024]; 355 343 static int level; 356 344 int trl_max_levels = isst_get_trl_max_levels(); 357 345 int i;
+1 -1
tools/power/x86/intel-speed-select/isst.h
··· 80 80 #define DISP_FREQ_MULTIPLIER 100 81 81 82 82 #define MAX_PACKAGE_COUNT 32 83 - #define MAX_DIE_PER_PACKAGE 2 83 + #define MAX_DIE_PER_PACKAGE 16 84 84 #define MAX_PUNIT_PER_DIE 8 85 85 86 86 /* Unified structure to specific a CPU or a Power Domain */