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

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

Pull x86 platform drivers updates from Ilpo Järvinen:

- alienware-wmi:
- Refactor and split WMAX/legacy drivers

- dell-ddv:
- Correct +0.1 offset in temperature
- Use the power supply extension mechanism for battery temperatures

- intel/pmc:
- Refactor init to mostly use a common init function
- Add support for Arrow Lake U/H
- Add support for Panther Lake

- intel/sst:
- Improve multi die handling
- Prefix header search path with sysroot (fixes cross-compiling)

- lenovo-wmi-hotkey-utilities:
- Support for mic & audio mute LEDs

- samsung-galaxybook:
- Add driver for Samsung Galaxy Book series

- wmi:
- Rework WCxx/WExx ACPI method handling
- Enable data block collection when the data block is set

- platform/arm:
- Add Huawei Matebook E Go EC driver

- platform/mellanox:
- Relocate to drivers/platform/mellanox/
- mlxbf-bootctl:
- RTC battery status sysfs support

- Miscellaneous cleanups / refactoring / improvements

* tag 'platform-drivers-x86-v6.15-1' of git://git.kernel.org/pub/scm/linux/kernel/git/pdx86/platform-drivers-x86: (75 commits)
platform/x86: x86-android-tablets: Add select POWER_SUPPLY to Kconfig
platform/x86/amd/pmf: convert timeouts to secs_to_jiffies()
platform/x86: thinkpad_acpi: convert timeouts to secs_to_jiffies()
irqdomain: platform/x86: Switch to irq_domain_create_linear()
platform/x86/amd/pmc: fix leak in probe()
tools/power/x86/intel-speed-select: v1.22 release
tools/power/x86/intel-speed-select: Prefix header search path with sysroot
tools/power/x86/intel-speed-select: Die ID for IO dies
tools/power/x86/intel-speed-select: Fix the condition to check multi die system
tools/power/x86/intel-speed-select: Prevent increasing MAX_DIE_PER_PACKAGE
platform/x86/amd/pmc: Use managed APIs for mutex
platform/x86/amd/pmc: Remove unnecessary line breaks
platform/x86/amd/pmc: Move macros and structures to the PMC header file
platform/x86/amd/pmc: Notify user when platform does not support s0ix transition
platform/x86: dell-ddv: Use the power supply extension mechanism
platform/x86: dell-ddv: Use devm_battery_hook_register
platform/x86: dell-ddv: Fix temperature calculation
platform/x86: thinkpad_acpi: check the return value of devm_mutex_init()
platform/x86: samsung-galaxybook: Fix block_recording not supported logic
platform/x86: dell-uart-backlight: Make dell_uart_bl_serdev_driver static
...

+5998 -2198
+10
Documentation/ABI/testing/sysfs-platform-mellanox-bootctl
··· 150 150 The "mfg_lock" sysfs attribute is write-only. 151 151 A successful write to this attribute will latch the 152 152 board-level attributes into EEPROM, making them read-only. 153 + 154 + What: /sys/bus/platform/devices/MLNXBF04:00/rtc_battery 155 + Date: June 2025 156 + KernelVersion: 6.15 157 + Contact: "Xiangrong Li <xiangrongl@nvidia.com>" 158 + Description: 159 + The "rtc_battery" sysfs attribute is read-only. 160 + A successful read from this attribute returns the status of 161 + the board's RTC battery. The RTC battery status register is 162 + also cleared upon successful read operation.
+1
Documentation/admin-guide/laptops/index.rst
··· 11 11 disk-shock-protection 12 12 laptop-mode 13 13 lg-laptop 14 + samsung-galaxybook 14 15 sony-laptop 15 16 sonypi 16 17 thinkpad-acpi
+174
Documentation/admin-guide/laptops/samsung-galaxybook.rst
··· 1 + .. SPDX-License-Identifier: GPL-2.0-or-later 2 + 3 + ========================== 4 + Samsung Galaxy Book Driver 5 + ========================== 6 + 7 + Joshua Grisham <josh@joshuagrisham.com> 8 + 9 + This is a Linux x86 platform driver for Samsung Galaxy Book series notebook 10 + devices which utilizes Samsung's ``SCAI`` ACPI device in order to control 11 + extra features and receive various notifications. 12 + 13 + Supported devices 14 + ================= 15 + 16 + Any device with one of the supported ACPI device IDs should be supported. This 17 + covers most of the "Samsung Galaxy Book" series notebooks that are currently 18 + available as of this writing, and could include other Samsung notebook devices 19 + as well. 20 + 21 + Status 22 + ====== 23 + 24 + The following features are currently supported: 25 + 26 + - :ref:`Keyboard backlight <keyboard-backlight>` control 27 + - :ref:`Performance mode <performance-mode>` control implemented using the 28 + platform profile interface 29 + - :ref:`Battery charge control end threshold 30 + <battery-charge-control-end-threshold>` (stop charging battery at given 31 + percentage value) implemented as a battery hook 32 + - :ref:`Firmware Attributes <firmware-attributes>` to allow control of various 33 + device settings 34 + - :ref:`Handling of Fn hotkeys <keyboard-hotkey-actions>` for various actions 35 + - :ref:`Handling of ACPI notifications and hotkeys 36 + <acpi-notifications-and-hotkey-actions>` 37 + 38 + Because different models of these devices can vary in their features, there is 39 + logic built within the driver which attempts to test each implemented feature 40 + for a valid response before enabling its support (registering additional devices 41 + or extensions, adding sysfs attributes, etc). Therefore, it can be important to 42 + note that not all features may be supported for your particular device. 43 + 44 + The following features might be possible to implement but will require 45 + additional investigation and are therefore not supported at this time: 46 + 47 + - "Dolby Atmos" mode for the speakers 48 + - "Outdoor Mode" for increasing screen brightness on models with ``SAM0427`` 49 + - "Silent Mode" on models with ``SAM0427`` 50 + 51 + .. _keyboard-backlight: 52 + 53 + Keyboard backlight 54 + ================== 55 + 56 + A new LED class named ``samsung-galaxybook::kbd_backlight`` is created which 57 + will then expose the device using the standard sysfs-based LED interface at 58 + ``/sys/class/leds/samsung-galaxybook::kbd_backlight``. Brightness can be 59 + controlled by writing the desired value to the ``brightness`` sysfs attribute or 60 + with any other desired userspace utility. 61 + 62 + .. note:: 63 + Most of these devices have an ambient light sensor which also turns 64 + off the keyboard backlight under well-lit conditions. This behavior does not 65 + seem possible to control at this time, but can be good to be aware of. 66 + 67 + .. _performance-mode: 68 + 69 + Performance mode 70 + ================ 71 + 72 + This driver implements the 73 + Documentation/userspace-api/sysfs-platform_profile.rst interface for working 74 + with the "performance mode" function of the Samsung ACPI device. 75 + 76 + Mapping of each Samsung "performance mode" to its respective platform profile is 77 + performed dynamically by the driver, as not all models support all of the same 78 + performance modes. Your device might have one or more of the following mappings: 79 + 80 + - "Silent" maps to ``low-power`` 81 + - "Quiet" maps to ``quiet`` 82 + - "Optimized" maps to ``balanced`` 83 + - "High performance" maps to ``performance`` 84 + 85 + The result of the mapping can be printed in the kernel log when the module is 86 + loaded. Supported profiles can also be retrieved from 87 + ``/sys/firmware/acpi/platform_profile_choices``, while 88 + ``/sys/firmware/acpi/platform_profile`` can be used to read or write the 89 + currently selected profile. 90 + 91 + The ``balanced`` platform profile will be set during module load if no profile 92 + has been previously set. 93 + 94 + .. _battery-charge-control-end-threshold: 95 + 96 + Battery charge control end threshold 97 + ==================================== 98 + 99 + This platform driver will add the ability to set the battery's charge control 100 + end threshold, but does not have the ability to set a start threshold. 101 + 102 + This feature is typically called "Battery Saver" by the various Samsung 103 + applications in Windows, but in Linux we have implemented the standardized 104 + "charge control threshold" sysfs interface on the battery device to allow for 105 + controlling this functionality from the userspace. 106 + 107 + The sysfs attribute 108 + ``/sys/class/power_supply/BAT1/charge_control_end_threshold`` can be used to 109 + read or set the desired charge end threshold. 110 + 111 + If you wish to maintain interoperability with the Samsung Settings application 112 + in Windows, then you should set the value to 100 to represent "off", or enable 113 + the feature using only one of the following values: 50, 60, 70, 80, or 90. 114 + Otherwise, the driver will accept any value between 1 and 100 as the percentage 115 + that you wish the battery to stop charging at. 116 + 117 + .. note:: 118 + Some devices have been observed as automatically "turning off" the charge 119 + control end threshold if an input value of less than 30 is given. 120 + 121 + .. _firmware-attributes: 122 + 123 + Firmware Attributes 124 + =================== 125 + 126 + The following enumeration-typed firmware attributes are set up by this driver 127 + and should be accessible under 128 + ``/sys/class/firmware-attributes/samsung-galaxybook/attributes/`` if your device 129 + supports them: 130 + 131 + - ``power_on_lid_open`` (device should power on when the lid is opened) 132 + - ``usb_charging`` (USB ports can deliver power to connected devices even when 133 + the device is powered off or in a low sleep state) 134 + - ``block_recording`` (blocks access to camera and microphone) 135 + 136 + All of these attributes are simple boolean-like enumeration values which use 0 137 + to represent "off" and 1 to represent "on". Use the ``current_value`` attribute 138 + to get or change the setting on the device. 139 + 140 + Note that when ``block_recording`` is updated, the input device "Samsung Galaxy 141 + Book Lens Cover" will receive a ``SW_CAMERA_LENS_COVER`` switch event which 142 + reflects the current state. 143 + 144 + .. _keyboard-hotkey-actions: 145 + 146 + Keyboard hotkey actions (i8042 filter) 147 + ====================================== 148 + 149 + The i8042 filter will swallow the keyboard events for the Fn+F9 hotkey (Multi- 150 + level keyboard backlight toggle) and Fn+F10 hotkey (Block recording toggle) 151 + and instead execute their actions within the driver itself. 152 + 153 + Fn+F9 will cycle through the brightness levels of the keyboard backlight. A 154 + notification will be sent using ``led_classdev_notify_brightness_hw_changed`` 155 + so that the userspace can be aware of the change. This mimics the behavior of 156 + other existing devices where the brightness level is cycled internally by the 157 + embedded controller and then reported via a notification. 158 + 159 + Fn+F10 will toggle the value of the "block recording" setting, which blocks 160 + or allows usage of the built-in camera and microphone (and generates the same 161 + Lens Cover switch event mentioned above). 162 + 163 + .. _acpi-notifications-and-hotkey-actions: 164 + 165 + ACPI notifications and hotkey actions 166 + ===================================== 167 + 168 + ACPI notifications will generate ACPI netlink events under the device class 169 + ``samsung-galaxybook`` and bus ID matching the Samsung ACPI device ID found on 170 + your device. The events can be received using userspace tools such as 171 + ``acpi_listen`` and ``acpid``. 172 + 173 + The Fn+F11 Performance mode hotkey will be handled by the driver; each keypress 174 + will cycle to the next available platform profile.
+124
Documentation/devicetree/bindings/platform/huawei,gaokun-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/huawei,gaokun-ec.yaml# 5 + $schema: http://devicetree.org/meta-schemas/core.yaml# 6 + 7 + title: Huawei Matebook E Go Embedded Controller 8 + 9 + maintainers: 10 + - Pengyu Luo <mitltlatltl@gmail.com> 11 + 12 + description: 13 + Different from other Qualcomm Snapdragon sc8180x and sc8280xp-based 14 + machines, the Huawei Matebook E Go tablets use embedded controllers 15 + while others use a system called PMIC GLink which handles battery, 16 + UCSI, USB Type-C DP Alt Mode. In addition, Huawei's implementation 17 + also handles additional features, such as charging thresholds, FN 18 + lock, smart charging, tablet lid status, thermal sensors, and more. 19 + 20 + properties: 21 + compatible: 22 + enum: 23 + - huawei,gaokun3-ec 24 + 25 + reg: 26 + const: 0x38 27 + 28 + '#address-cells': 29 + const: 1 30 + 31 + '#size-cells': 32 + const: 0 33 + 34 + interrupts: 35 + maxItems: 1 36 + 37 + patternProperties: 38 + '^connector@[01]$': 39 + $ref: /schemas/connector/usb-connector.yaml# 40 + 41 + properties: 42 + reg: 43 + maxItems: 1 44 + 45 + required: 46 + - compatible 47 + - reg 48 + - interrupts 49 + 50 + additionalProperties: false 51 + 52 + examples: 53 + - | 54 + #include <dt-bindings/interrupt-controller/irq.h> 55 + i2c { 56 + #address-cells = <1>; 57 + #size-cells = <0>; 58 + 59 + embedded-controller@38 { 60 + compatible = "huawei,gaokun3-ec"; 61 + reg = <0x38>; 62 + 63 + interrupts-extended = <&tlmm 107 IRQ_TYPE_LEVEL_LOW>; 64 + 65 + #address-cells = <1>; 66 + #size-cells = <0>; 67 + 68 + connector@0 { 69 + compatible = "usb-c-connector"; 70 + reg = <0>; 71 + power-role = "dual"; 72 + data-role = "dual"; 73 + 74 + ports { 75 + #address-cells = <1>; 76 + #size-cells = <0>; 77 + 78 + port@0 { 79 + reg = <0>; 80 + 81 + ucsi0_ss_in: endpoint { 82 + remote-endpoint = <&usb_0_qmpphy_out>; 83 + }; 84 + }; 85 + 86 + port@1 { 87 + reg = <1>; 88 + 89 + ucsi0_sbu: endpoint { 90 + remote-endpoint = <&usb0_sbu_mux>; 91 + }; 92 + }; 93 + }; 94 + }; 95 + 96 + connector@1 { 97 + compatible = "usb-c-connector"; 98 + reg = <1>; 99 + power-role = "dual"; 100 + data-role = "dual"; 101 + 102 + ports { 103 + #address-cells = <1>; 104 + #size-cells = <0>; 105 + 106 + port@0 { 107 + reg = <0>; 108 + 109 + ucsi1_ss_in: endpoint { 110 + remote-endpoint = <&usb_1_qmpphy_out>; 111 + }; 112 + }; 113 + 114 + port@1 { 115 + reg = <1>; 116 + 117 + ucsi1_sbu: endpoint { 118 + remote-endpoint = <&usb1_sbu_mux>; 119 + }; 120 + }; 121 + }; 122 + }; 123 + }; 124 + };
+3
Documentation/wmi/acpi-interface.rst
··· 89 89 instead of events and thus the last two characters of the ACPI method name are 90 90 the method ID of the data block to enable/disable. 91 91 92 + Those ACPI methods are also called before setting data blocks to match the 93 + behaviour of the Windows driver. 94 + 92 95 _WED ACPI method 93 96 ---------------- 94 97
+4
Documentation/wmi/driver-development-guide.rst
··· 96 96 Because of this, WMI drivers should use the state container design pattern as described in 97 97 Documentation/driver-api/driver-model/design-patterns.rst. 98 98 99 + .. warning:: Using both GUID-based and non-GUID-based functions for querying WMI data blocks and 100 + handling WMI events simultaneously on the same device is guaranteed to corrupt the 101 + WMI device state and might lead to erratic behaviour. 102 + 99 103 WMI method drivers 100 104 ------------------ 101 105
+24 -7
MAINTAINERS
··· 793 793 F: drivers/perf/alibaba_uncore_drw_pmu.c 794 794 795 795 ALIENWARE WMI DRIVER 796 + M: Kurt Borja <kuurtb@gmail.com> 797 + L: platform-driver-x86@vger.kernel.org 796 798 L: Dell.Client.Kernel@dell.com 797 799 S: Maintained 798 800 F: Documentation/wmi/devices/alienware-wmi.rst 799 - F: drivers/platform/x86/dell/alienware-wmi.c 801 + F: drivers/platform/x86/dell/alienware-wmi* 800 802 801 803 ALLEGRO DVT VIDEO IP CORE DRIVER 802 804 M: Michael Tretter <m.tretter@pengutronix.de> ··· 10752 10750 F: Documentation/networking/device_drivers/ethernet/huawei/hinic.rst 10753 10751 F: drivers/net/ethernet/huawei/hinic/ 10754 10752 10753 + HUAWEI MATEBOOK E GO EMBEDDED CONTROLLER DRIVER 10754 + M: Pengyu Luo <mitltlatltl@gmail.com> 10755 + S: Maintained 10756 + F: Documentation/devicetree/bindings/platform/huawei,gaokun-ec.yaml 10757 + F: drivers/platform/arm64/huawei-gaokun-ec.c 10758 + F: include/linux/platform_data/huawei-gaokun-ec.h 10759 + 10755 10760 HUGETLB SUBSYSTEM 10756 10761 M: Muchun Song <muchun.song@linux.dev> 10757 10762 L: linux-mm@kvack.org ··· 13222 13213 W: http://legousb.sourceforge.net/ 13223 13214 F: drivers/usb/misc/legousbtower.c 13224 13215 13216 + LENOVO WMI HOTKEY UTILITIES DRIVER 13217 + M: Jackie Dong <xy-jackie@139.com> 13218 + L: platform-driver-x86@vger.kernel.org 13219 + S: Maintained 13220 + F: drivers/platform/x86/lenovo-wmi-hotkey-utilities.c 13221 + 13225 13222 LETSKETCH HID TABLET DRIVER 13226 13223 M: Hans de Goede <hdegoede@redhat.com> 13227 13224 L: linux-input@vger.kernel.org ··· 15106 15091 M: Vadim Pasternak <vadimp@nvidia.com> 15107 15092 L: platform-driver-x86@vger.kernel.org 15108 15093 S: Supported 15094 + F: Documentation/ABI/stable/sysfs-driver-mlxreg-io 15109 15095 F: Documentation/ABI/testing/sysfs-platform-mellanox-bootctl 15110 15096 F: drivers/platform/mellanox/ 15111 15097 F: include/linux/platform_data/mlxreg.h ··· 15176 15160 F: Documentation/leds/leds-mlxcpld.rst 15177 15161 F: drivers/leds/leds-mlxcpld.c 15178 15162 F: drivers/leds/leds-mlxreg.c 15179 - 15180 - MELLANOX PLATFORM DRIVER 15181 - M: Vadim Pasternak <vadimp@nvidia.com> 15182 - L: platform-driver-x86@vger.kernel.org 15183 - S: Supported 15184 - F: drivers/platform/x86/mlx-platform.c 15185 15163 15186 15164 MEMBARRIER SUPPORT 15187 15165 M: Mathieu Desnoyers <mathieu.desnoyers@efficios.com> ··· 21103 21093 L: linux-fbdev@vger.kernel.org 21104 21094 S: Maintained 21105 21095 F: drivers/video/fbdev/s3c-fb.c 21096 + 21097 + SAMSUNG GALAXY BOOK DRIVER 21098 + M: Joshua Grisham <josh@joshuagrisham.com> 21099 + L: platform-driver-x86@vger.kernel.org 21100 + S: Maintained 21101 + F: Documentation/admin-guide/laptops/samsung-galaxybook.rst 21102 + F: drivers/platform/x86/samsung-galaxybook.c 21106 21103 21107 21104 SAMSUNG INTERCONNECT DRIVERS 21108 21105 M: Sylwester Nawrocki <s.nawrocki@samsung.com>
+163
arch/arm64/boot/dts/qcom/sc8280xp-huawei-gaokun3.dts
··· 28 28 29 29 aliases { 30 30 i2c4 = &i2c4; 31 + i2c15 = &i2c15; 31 32 serial1 = &uart2; 32 33 }; 33 34 ··· 213 212 <&cpu6 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, 214 213 <&cpu7 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>; 215 214 }; 215 + }; 216 + }; 217 + }; 218 + 219 + usb0-sbu-mux { 220 + compatible = "pericom,pi3usb102", "gpio-sbu-mux"; 221 + 222 + select-gpios = <&tlmm 164 GPIO_ACTIVE_HIGH>; 223 + 224 + pinctrl-0 = <&usb0_sbu_default>; 225 + pinctrl-names = "default"; 226 + 227 + orientation-switch; 228 + 229 + port { 230 + usb0_sbu_mux: endpoint { 231 + remote-endpoint = <&ucsi0_sbu>; 232 + }; 233 + }; 234 + }; 235 + 236 + usb1-sbu-mux { 237 + compatible = "pericom,pi3usb102", "gpio-sbu-mux"; 238 + 239 + select-gpios = <&tlmm 47 GPIO_ACTIVE_HIGH>; 240 + 241 + pinctrl-0 = <&usb1_sbu_default>; 242 + pinctrl-names = "default"; 243 + 244 + orientation-switch; 245 + 246 + port { 247 + usb1_sbu_mux: endpoint { 248 + remote-endpoint = <&ucsi1_sbu>; 216 249 }; 217 250 }; 218 251 }; ··· 617 582 pinctrl-names = "default"; 618 583 }; 619 584 585 + }; 586 + 587 + &i2c15 { 588 + clock-frequency = <400000>; 589 + 590 + pinctrl-0 = <&i2c15_default>; 591 + pinctrl-names = "default"; 592 + 593 + status = "okay"; 594 + 595 + embedded-controller@38 { 596 + compatible = "huawei,gaokun3-ec"; 597 + reg = <0x38>; 598 + 599 + interrupts-extended = <&tlmm 107 IRQ_TYPE_LEVEL_LOW>; 600 + 601 + #address-cells = <1>; 602 + #size-cells = <0>; 603 + 604 + connector@0 { 605 + compatible = "usb-c-connector"; 606 + reg = <0>; 607 + power-role = "dual"; 608 + data-role = "dual"; 609 + 610 + ports { 611 + #address-cells = <1>; 612 + #size-cells = <0>; 613 + 614 + port@0 { 615 + reg = <0>; 616 + 617 + ucsi0_hs_in: endpoint { 618 + remote-endpoint = <&usb_0_dwc3_hs>; 619 + }; 620 + }; 621 + 622 + port@1 { 623 + reg = <1>; 624 + 625 + ucsi0_ss_in: endpoint { 626 + remote-endpoint = <&usb_0_qmpphy_out>; 627 + }; 628 + }; 629 + 630 + port@2 { 631 + reg = <2>; 632 + 633 + ucsi0_sbu: endpoint { 634 + remote-endpoint = <&usb0_sbu_mux>; 635 + }; 636 + }; 637 + }; 638 + }; 639 + 640 + connector@1 { 641 + compatible = "usb-c-connector"; 642 + reg = <1>; 643 + power-role = "dual"; 644 + data-role = "dual"; 645 + 646 + ports { 647 + #address-cells = <1>; 648 + #size-cells = <0>; 649 + 650 + port@0 { 651 + reg = <0>; 652 + 653 + ucsi1_hs_in: endpoint { 654 + remote-endpoint = <&usb_1_dwc3_hs>; 655 + }; 656 + }; 657 + 658 + port@1 { 659 + reg = <1>; 660 + 661 + ucsi1_ss_in: endpoint { 662 + remote-endpoint = <&usb_1_qmpphy_out>; 663 + }; 664 + }; 665 + 666 + port@2 { 667 + reg = <2>; 668 + 669 + ucsi1_sbu: endpoint { 670 + remote-endpoint = <&usb1_sbu_mux>; 671 + }; 672 + }; 673 + }; 674 + }; 675 + }; 620 676 }; 621 677 622 678 &mdss0 { ··· 1130 1004 dr_mode = "host"; 1131 1005 }; 1132 1006 1007 + &usb_0_dwc3_hs { 1008 + remote-endpoint = <&ucsi0_hs_in>; 1009 + }; 1010 + 1133 1011 &usb_0_hsphy { 1134 1012 vdda-pll-supply = <&vreg_l9d>; 1135 1013 vdda18-supply = <&vreg_l1c>; ··· 1155 1025 remote-endpoint = <&mdss0_dp0_out>; 1156 1026 }; 1157 1027 1028 + &usb_0_qmpphy_out { 1029 + remote-endpoint = <&ucsi0_ss_in>; 1030 + }; 1031 + 1158 1032 &usb_1 { 1159 1033 status = "okay"; 1160 1034 }; 1161 1035 1162 1036 &usb_1_dwc3 { 1163 1037 dr_mode = "host"; 1038 + }; 1039 + 1040 + &usb_1_dwc3_hs { 1041 + remote-endpoint = <&ucsi1_hs_in>; 1164 1042 }; 1165 1043 1166 1044 &usb_1_hsphy { ··· 1190 1052 1191 1053 &usb_1_qmpphy_dp_in { 1192 1054 remote-endpoint = <&mdss0_dp1_out>; 1055 + }; 1056 + 1057 + &usb_1_qmpphy_out { 1058 + remote-endpoint = <&ucsi1_ss_in>; 1193 1059 }; 1194 1060 1195 1061 &usb_2 { ··· 1319 1177 bias-disable; 1320 1178 }; 1321 1179 1180 + i2c15_default: i2c15-default-state { 1181 + pins = "gpio36", "gpio37"; 1182 + function = "qup15"; 1183 + drive-strength = <2>; 1184 + bias-pull-up; 1185 + }; 1186 + 1322 1187 mode_pin_active: mode-pin-state { 1323 1188 pins = "gpio26"; 1324 1189 function = "gpio"; ··· 1448 1299 drive-strength = <2>; 1449 1300 bias-disable; 1450 1301 }; 1302 + }; 1303 + 1304 + usb0_sbu_default: usb0-sbu-state { 1305 + pins = "gpio164"; 1306 + function = "gpio"; 1307 + drive-strength = <16>; 1308 + bias-disable; 1309 + }; 1310 + 1311 + usb1_sbu_default: usb1-sbu-state { 1312 + pins = "gpio47"; 1313 + function = "gpio"; 1314 + drive-strength = <16>; 1315 + bias-disable; 1451 1316 }; 1452 1317 1453 1318 wcd_default: wcd-default-state {
+6 -5
drivers/char/sonypi.c
··· 37 37 #include <linux/kfifo.h> 38 38 #include <linux/platform_device.h> 39 39 #include <linux/gfp.h> 40 + #include <linux/string_choices.h> 40 41 41 42 #include <linux/uaccess.h> 42 43 #include <asm/io.h> ··· 1269 1268 "compat = %s, mask = 0x%08lx, useinput = %s, acpi = %s\n", 1270 1269 sonypi_device.model, 1271 1270 verbose, 1272 - fnkeyinit ? "on" : "off", 1273 - camera ? "on" : "off", 1274 - compat ? "on" : "off", 1271 + str_on_off(fnkeyinit), 1272 + str_on_off(camera), 1273 + str_on_off(compat), 1275 1274 mask, 1276 - useinput ? "on" : "off", 1277 - SONYPI_ACPI_ACTIVE ? "on" : "off"); 1275 + str_on_off(useinput), 1276 + str_on_off(SONYPI_ACPI_ACTIVE)); 1278 1277 printk(KERN_INFO "sonypi: enabled at irq=%d, port1=0x%x, port2=0x%x\n", 1279 1278 sonypi_device.irq, 1280 1279 sonypi_device.ioport1, sonypi_device.ioport2);
+2 -2
drivers/hwmon/hp-wmi-sensors.c
··· 1197 1197 if (time_after(jiffies, info->last_updated + HZ)) { 1198 1198 mutex_lock(&state->lock); 1199 1199 1200 - wobj = hp_wmi_get_wobj(HP_WMI_NUMERIC_SENSOR_GUID, instance); 1200 + wobj = wmidev_block_query(state->wdev, instance); 1201 1201 if (!wobj) { 1202 1202 ret = -EIO; 1203 1203 goto out_unlock; ··· 1745 1745 return -ENOMEM; 1746 1746 1747 1747 for (i = 0, info = info_arr; i < icount; i++, info++) { 1748 - wobj = hp_wmi_get_wobj(HP_WMI_NUMERIC_SENSOR_GUID, i); 1748 + wobj = wmidev_block_query(state->wdev, i); 1749 1749 if (!wobj) 1750 1750 return -EIO; 1751 1751
+21
drivers/platform/arm64/Kconfig
··· 33 33 laptop where this information is not properly exposed via the 34 34 standard ACPI devices. 35 35 36 + config EC_HUAWEI_GAOKUN 37 + tristate "Huawei Matebook E Go Embedded Controller driver" 38 + depends on ARCH_QCOM || COMPILE_TEST 39 + depends on I2C 40 + depends on INPUT 41 + depends on HWMON 42 + select AUXILIARY_BUS 43 + 44 + help 45 + Say Y here to enable the EC driver for the Huawei Matebook E Go 46 + which is a sc8280xp-based 2-in-1 tablet. The driver handles battery 47 + (information, charge control) and USB Type-C DP HPD events as well 48 + as some misc functions like the lid sensor and temperature sensors, 49 + etc. 50 + 51 + This driver provides battery and AC status support for the mentioned 52 + laptop where this information is not properly exposed via the 53 + standard ACPI devices. 54 + 55 + Say M or Y here to include this support. 56 + 36 57 config EC_LENOVO_YOGA_C630 37 58 tristate "Lenovo Yoga C630 Embedded Controller driver" 38 59 depends on ARCH_QCOM || COMPILE_TEST
+1
drivers/platform/arm64/Makefile
··· 6 6 # 7 7 8 8 obj-$(CONFIG_EC_ACER_ASPIRE1) += acer-aspire1-ec.o 9 + obj-$(CONFIG_EC_HUAWEI_GAOKUN) += huawei-gaokun-ec.o 9 10 obj-$(CONFIG_EC_LENOVO_YOGA_C630) += lenovo-yoga-c630.o
+825
drivers/platform/arm64/huawei-gaokun-ec.c
··· 1 + // SPDX-License-Identifier: GPL-2.0-only 2 + /* 3 + * huawei-gaokun-ec - An EC driver for HUAWEI Matebook E Go 4 + * 5 + * Copyright (C) 2024-2025 Pengyu Luo <mitltlatltl@gmail.com> 6 + */ 7 + 8 + #include <linux/auxiliary_bus.h> 9 + #include <linux/cleanup.h> 10 + #include <linux/delay.h> 11 + #include <linux/device.h> 12 + #include <linux/hwmon.h> 13 + #include <linux/hwmon-sysfs.h> 14 + #include <linux/i2c.h> 15 + #include <linux/input.h> 16 + #include <linux/notifier.h> 17 + #include <linux/module.h> 18 + #include <linux/mutex.h> 19 + #include <linux/platform_data/huawei-gaokun-ec.h> 20 + 21 + #define EC_EVENT 0x06 22 + 23 + /* Also can be found in ACPI specification 12.3 */ 24 + #define EC_READ 0x80 25 + #define EC_WRITE 0x81 26 + #define EC_BURST 0x82 27 + #define EC_QUERY 0x84 28 + 29 + #define EC_FN_LOCK_ON 0x5A 30 + #define EC_FN_LOCK_OFF 0x55 31 + #define EC_FN_LOCK_READ 0x6B 32 + #define EC_FN_LOCK_WRITE 0x6C 33 + 34 + #define EC_EVENT_LID 0x81 35 + 36 + #define EC_LID_STATE 0x80 37 + #define EC_LID_OPEN BIT(1) 38 + 39 + #define EC_TEMP_REG 0x61 40 + 41 + #define EC_STANDBY_REG 0xB2 42 + #define EC_STANDBY_ENTER 0xDB 43 + #define EC_STANDBY_EXIT 0xEB 44 + 45 + enum gaokun_ec_smart_charge_cmd { 46 + SMART_CHARGE_DATA_WRITE = 0xE3, 47 + SMART_CHARGE_DATA_READ, 48 + SMART_CHARGE_ENABLE_WRITE, 49 + SMART_CHARGE_ENABLE_READ, 50 + }; 51 + 52 + enum gaokun_ec_ucsi_cmd { 53 + UCSI_REG_WRITE = 0xD2, 54 + UCSI_REG_READ, 55 + UCSI_DATA_WRITE, 56 + UCSI_DATA_READ, 57 + }; 58 + 59 + #define UCSI_REG_SIZE 7 60 + 61 + /* 62 + * For tx, command sequences are arranged as 63 + * {master_cmd, slave_cmd, data_len, data_seq} 64 + */ 65 + #define REQ_HDR_SIZE 3 66 + #define INPUT_SIZE_OFFSET 2 67 + #define REQ_LEN(req) (REQ_HDR_SIZE + (req)[INPUT_SIZE_OFFSET]) 68 + 69 + /* 70 + * For rx, data sequences are arranged as 71 + * {status, data_len(unreliable), data_seq} 72 + */ 73 + #define RESP_HDR_SIZE 2 74 + 75 + #define MKREQ(REG0, REG1, SIZE, ...) \ 76 + { \ 77 + REG0, REG1, SIZE, \ 78 + /* ## will remove comma when SIZE is 0 */ \ 79 + ## __VA_ARGS__, \ 80 + /* make sure len(pkt[3:]) >= SIZE */ \ 81 + [3 + (SIZE)] = 0, \ 82 + } 83 + 84 + #define MKRESP(SIZE) \ 85 + { \ 86 + [RESP_HDR_SIZE + (SIZE) - 1] = 0, \ 87 + } 88 + 89 + /* Possible size 1, 4, 20, 24. Most of the time, the size is 1. */ 90 + static inline void refill_req(u8 *dest, const u8 *src, size_t size) 91 + { 92 + memcpy(dest + REQ_HDR_SIZE, src, size); 93 + } 94 + 95 + static inline void refill_req_byte(u8 *dest, const u8 *src) 96 + { 97 + dest[REQ_HDR_SIZE] = *src; 98 + } 99 + 100 + /* Possible size 1, 2, 4, 7, 20. Most of the time, the size is 1. */ 101 + static inline void extr_resp(u8 *dest, const u8 *src, size_t size) 102 + { 103 + memcpy(dest, src + RESP_HDR_SIZE, size); 104 + } 105 + 106 + static inline void extr_resp_byte(u8 *dest, const u8 *src) 107 + { 108 + *dest = src[RESP_HDR_SIZE]; 109 + } 110 + 111 + static inline void *extr_resp_shallow(const u8 *src) 112 + { 113 + return (void *)(src + RESP_HDR_SIZE); 114 + } 115 + 116 + struct gaokun_ec { 117 + struct i2c_client *client; 118 + struct mutex lock; /* EC transaction lock */ 119 + struct blocking_notifier_head notifier_list; 120 + struct device *hwmon_dev; 121 + struct input_dev *idev; 122 + bool suspended; 123 + }; 124 + 125 + static int gaokun_ec_request(struct gaokun_ec *ec, const u8 *req, 126 + size_t resp_len, u8 *resp) 127 + { 128 + struct i2c_client *client = ec->client; 129 + struct i2c_msg msgs[] = { 130 + { 131 + .addr = client->addr, 132 + .flags = client->flags, 133 + .len = REQ_LEN(req), 134 + .buf = (void *)req, 135 + }, { 136 + .addr = client->addr, 137 + .flags = client->flags | I2C_M_RD, 138 + .len = resp_len, 139 + .buf = resp, 140 + }, 141 + }; 142 + int ret; 143 + 144 + guard(mutex)(&ec->lock); 145 + ret = i2c_transfer(client->adapter, msgs, ARRAY_SIZE(msgs)); 146 + if (ret != ARRAY_SIZE(msgs)) { 147 + dev_err(&client->dev, "I2C transfer error %d\n", ret); 148 + goto out_after_break; 149 + } 150 + 151 + ret = *resp; 152 + if (ret) 153 + dev_err(&client->dev, "EC transaction error %d\n", ret); 154 + 155 + out_after_break: 156 + usleep_range(2000, 2500); /* have a break, ACPI did this */ 157 + 158 + return ret; 159 + } 160 + 161 + /* -------------------------------------------------------------------------- */ 162 + /* Common API */ 163 + 164 + /** 165 + * gaokun_ec_read - Read from EC 166 + * @ec: The gaokun_ec structure 167 + * @req: The sequence to request 168 + * @resp_len: The size to read 169 + * @resp: The buffer to store response sequence 170 + * 171 + * This function is used to read data after writing a magic sequence to EC. 172 + * All EC operations depend on this function. 173 + * 174 + * Huawei uses magic sequences everywhere to complete various functions, all 175 + * these sequences are passed to ECCD(a ACPI method which is quiet similar 176 + * to gaokun_ec_request), there is no good abstraction to generalize these 177 + * sequences, so just wrap it for now. Almost all magic sequences are kept 178 + * in this file. 179 + * 180 + * Return: 0 on success or negative error code. 181 + */ 182 + int gaokun_ec_read(struct gaokun_ec *ec, const u8 *req, 183 + size_t resp_len, u8 *resp) 184 + { 185 + return gaokun_ec_request(ec, req, resp_len, resp); 186 + } 187 + EXPORT_SYMBOL_GPL(gaokun_ec_read); 188 + 189 + /** 190 + * gaokun_ec_write - Write to EC 191 + * @ec: The gaokun_ec structure 192 + * @req: The sequence to request 193 + * 194 + * This function has no big difference from gaokun_ec_read. When caller care 195 + * only write status and no actual data are returned, then use it. 196 + * 197 + * Return: 0 on success or negative error code. 198 + */ 199 + int gaokun_ec_write(struct gaokun_ec *ec, const u8 *req) 200 + { 201 + u8 ec_resp[] = MKRESP(0); 202 + 203 + return gaokun_ec_request(ec, req, sizeof(ec_resp), ec_resp); 204 + } 205 + EXPORT_SYMBOL_GPL(gaokun_ec_write); 206 + 207 + int gaokun_ec_read_byte(struct gaokun_ec *ec, const u8 *req, u8 *byte) 208 + { 209 + int ret; 210 + u8 ec_resp[] = MKRESP(sizeof(*byte)); 211 + 212 + ret = gaokun_ec_read(ec, req, sizeof(ec_resp), ec_resp); 213 + extr_resp_byte(byte, ec_resp); 214 + 215 + return ret; 216 + } 217 + EXPORT_SYMBOL_GPL(gaokun_ec_read_byte); 218 + 219 + /** 220 + * gaokun_ec_register_notify - Register a notifier callback for EC events. 221 + * @ec: The gaokun_ec structure 222 + * @nb: Notifier block pointer to register 223 + * 224 + * Return: 0 on success or negative error code. 225 + */ 226 + int gaokun_ec_register_notify(struct gaokun_ec *ec, struct notifier_block *nb) 227 + { 228 + return blocking_notifier_chain_register(&ec->notifier_list, nb); 229 + } 230 + EXPORT_SYMBOL_GPL(gaokun_ec_register_notify); 231 + 232 + /** 233 + * gaokun_ec_unregister_notify - Unregister notifier callback for EC events. 234 + * @ec: The gaokun_ec structure 235 + * @nb: Notifier block pointer to unregister 236 + * 237 + * Unregister a notifier callback that was previously registered with 238 + * gaokun_ec_register_notify(). 239 + */ 240 + void gaokun_ec_unregister_notify(struct gaokun_ec *ec, struct notifier_block *nb) 241 + { 242 + blocking_notifier_chain_unregister(&ec->notifier_list, nb); 243 + } 244 + EXPORT_SYMBOL_GPL(gaokun_ec_unregister_notify); 245 + 246 + /* -------------------------------------------------------------------------- */ 247 + /* API for PSY */ 248 + 249 + /** 250 + * gaokun_ec_psy_multi_read - Read contiguous registers 251 + * @ec: The gaokun_ec structure 252 + * @reg: The start register 253 + * @resp_len: The number of registers to be read 254 + * @resp: The buffer to store response sequence 255 + * 256 + * Return: 0 on success or negative error code. 257 + */ 258 + int gaokun_ec_psy_multi_read(struct gaokun_ec *ec, u8 reg, 259 + size_t resp_len, u8 *resp) 260 + { 261 + u8 ec_req[] = MKREQ(0x02, EC_READ, 1, 0); 262 + u8 ec_resp[] = MKRESP(1); 263 + int i, ret; 264 + 265 + for (i = 0; i < resp_len; ++i, reg++) { 266 + refill_req_byte(ec_req, &reg); 267 + ret = gaokun_ec_read(ec, ec_req, sizeof(ec_resp), ec_resp); 268 + if (ret) 269 + return ret; 270 + extr_resp_byte(&resp[i], ec_resp); 271 + } 272 + 273 + return 0; 274 + } 275 + EXPORT_SYMBOL_GPL(gaokun_ec_psy_multi_read); 276 + 277 + /* Smart charge */ 278 + 279 + /** 280 + * gaokun_ec_psy_get_smart_charge - Get smart charge data from EC 281 + * @ec: The gaokun_ec structure 282 + * @resp: The buffer to store response sequence (mode, delay, start, end) 283 + * 284 + * Return: 0 on success or negative error code. 285 + */ 286 + int gaokun_ec_psy_get_smart_charge(struct gaokun_ec *ec, 287 + u8 resp[GAOKUN_SMART_CHARGE_DATA_SIZE]) 288 + { 289 + /* GBCM */ 290 + u8 ec_req[] = MKREQ(0x02, SMART_CHARGE_DATA_READ, 0); 291 + u8 ec_resp[] = MKRESP(GAOKUN_SMART_CHARGE_DATA_SIZE); 292 + int ret; 293 + 294 + ret = gaokun_ec_read(ec, ec_req, sizeof(ec_resp), ec_resp); 295 + if (ret) 296 + return ret; 297 + 298 + extr_resp(resp, ec_resp, GAOKUN_SMART_CHARGE_DATA_SIZE); 299 + 300 + return 0; 301 + } 302 + EXPORT_SYMBOL_GPL(gaokun_ec_psy_get_smart_charge); 303 + 304 + static inline bool validate_battery_threshold_range(u8 start, u8 end) 305 + { 306 + return end != 0 && start <= end && end <= 100; 307 + } 308 + 309 + /** 310 + * gaokun_ec_psy_set_smart_charge - Set smart charge data 311 + * @ec: The gaokun_ec structure 312 + * @req: The sequence to request (mode, delay, start, end) 313 + * 314 + * Return: 0 on success or negative error code. 315 + */ 316 + int gaokun_ec_psy_set_smart_charge(struct gaokun_ec *ec, 317 + const u8 req[GAOKUN_SMART_CHARGE_DATA_SIZE]) 318 + { 319 + /* SBCM */ 320 + u8 ec_req[] = MKREQ(0x02, SMART_CHARGE_DATA_WRITE, 321 + GAOKUN_SMART_CHARGE_DATA_SIZE); 322 + 323 + if (!validate_battery_threshold_range(req[2], req[3])) 324 + return -EINVAL; 325 + 326 + refill_req(ec_req, req, GAOKUN_SMART_CHARGE_DATA_SIZE); 327 + 328 + return gaokun_ec_write(ec, ec_req); 329 + } 330 + EXPORT_SYMBOL_GPL(gaokun_ec_psy_set_smart_charge); 331 + 332 + /* Smart charge enable */ 333 + 334 + /** 335 + * gaokun_ec_psy_get_smart_charge_enable - Get smart charge state 336 + * @ec: The gaokun_ec structure 337 + * @on: The state 338 + * 339 + * Return: 0 on success or negative error code. 340 + */ 341 + int gaokun_ec_psy_get_smart_charge_enable(struct gaokun_ec *ec, bool *on) 342 + { 343 + /* GBAC */ 344 + u8 ec_req[] = MKREQ(0x02, SMART_CHARGE_ENABLE_READ, 0); 345 + u8 state; 346 + int ret; 347 + 348 + ret = gaokun_ec_read_byte(ec, ec_req, &state); 349 + if (ret) 350 + return ret; 351 + 352 + *on = !!state; 353 + 354 + return 0; 355 + } 356 + EXPORT_SYMBOL_GPL(gaokun_ec_psy_get_smart_charge_enable); 357 + 358 + /** 359 + * gaokun_ec_psy_set_smart_charge_enable - Set smart charge state 360 + * @ec: The gaokun_ec structure 361 + * @on: The state 362 + * 363 + * Return: 0 on success or negative error code. 364 + */ 365 + int gaokun_ec_psy_set_smart_charge_enable(struct gaokun_ec *ec, bool on) 366 + { 367 + /* SBAC */ 368 + u8 ec_req[] = MKREQ(0x02, SMART_CHARGE_ENABLE_WRITE, 1, on); 369 + 370 + return gaokun_ec_write(ec, ec_req); 371 + } 372 + EXPORT_SYMBOL_GPL(gaokun_ec_psy_set_smart_charge_enable); 373 + 374 + /* -------------------------------------------------------------------------- */ 375 + /* API for UCSI */ 376 + 377 + /** 378 + * gaokun_ec_ucsi_read - Read UCSI data from EC 379 + * @ec: The gaokun_ec structure 380 + * @resp: The buffer to store response sequence 381 + * 382 + * Read CCI and MSGI (used by UCSI subdriver). 383 + * 384 + * Return: 0 on success or negative error code. 385 + */ 386 + int gaokun_ec_ucsi_read(struct gaokun_ec *ec, 387 + u8 resp[GAOKUN_UCSI_READ_SIZE]) 388 + { 389 + u8 ec_req[] = MKREQ(0x03, UCSI_DATA_READ, 0); 390 + u8 ec_resp[] = MKRESP(GAOKUN_UCSI_READ_SIZE); 391 + int ret; 392 + 393 + ret = gaokun_ec_read(ec, ec_req, sizeof(ec_resp), ec_resp); 394 + if (ret) 395 + return ret; 396 + 397 + extr_resp(resp, ec_resp, GAOKUN_UCSI_READ_SIZE); 398 + return 0; 399 + } 400 + EXPORT_SYMBOL_GPL(gaokun_ec_ucsi_read); 401 + 402 + /** 403 + * gaokun_ec_ucsi_write - Write UCSI data to EC 404 + * @ec: The gaokun_ec structure 405 + * @req: The sequence to request 406 + * 407 + * Write CTRL and MSGO (used by UCSI subdriver). 408 + * 409 + * Return: 0 on success or negative error code. 410 + */ 411 + int gaokun_ec_ucsi_write(struct gaokun_ec *ec, 412 + const u8 req[GAOKUN_UCSI_WRITE_SIZE]) 413 + { 414 + u8 ec_req[] = MKREQ(0x03, UCSI_DATA_WRITE, GAOKUN_UCSI_WRITE_SIZE); 415 + 416 + refill_req(ec_req, req, GAOKUN_UCSI_WRITE_SIZE); 417 + 418 + return gaokun_ec_write(ec, ec_req); 419 + } 420 + EXPORT_SYMBOL_GPL(gaokun_ec_ucsi_write); 421 + 422 + /** 423 + * gaokun_ec_ucsi_get_reg - Get UCSI register from EC 424 + * @ec: The gaokun_ec structure 425 + * @ureg: The gaokun ucsi register 426 + * 427 + * Get UCSI register data (used by UCSI subdriver). 428 + * 429 + * Return: 0 on success or negative error code. 430 + */ 431 + int gaokun_ec_ucsi_get_reg(struct gaokun_ec *ec, struct gaokun_ucsi_reg *ureg) 432 + { 433 + u8 ec_req[] = MKREQ(0x03, UCSI_REG_READ, 0); 434 + u8 ec_resp[] = MKRESP(UCSI_REG_SIZE); 435 + int ret; 436 + 437 + ret = gaokun_ec_read(ec, ec_req, sizeof(ec_resp), ec_resp); 438 + if (ret) 439 + return ret; 440 + 441 + extr_resp((u8 *)ureg, ec_resp, UCSI_REG_SIZE); 442 + 443 + return 0; 444 + } 445 + EXPORT_SYMBOL_GPL(gaokun_ec_ucsi_get_reg); 446 + 447 + /** 448 + * gaokun_ec_ucsi_pan_ack - Ack pin assignment notifications from EC 449 + * @ec: The gaokun_ec structure 450 + * @port_id: The port id receiving and handling the notifications 451 + * 452 + * Ack pin assignment notifications (used by UCSI subdriver). 453 + * 454 + * Return: 0 on success or negative error code. 455 + */ 456 + int gaokun_ec_ucsi_pan_ack(struct gaokun_ec *ec, int port_id) 457 + { 458 + u8 ec_req[] = MKREQ(0x03, UCSI_REG_WRITE, 1); 459 + u8 data = 1 << port_id; 460 + 461 + if (port_id == GAOKUN_UCSI_NO_PORT_UPDATE) 462 + data = 0; 463 + 464 + refill_req_byte(ec_req, &data); 465 + 466 + return gaokun_ec_write(ec, ec_req); 467 + } 468 + EXPORT_SYMBOL_GPL(gaokun_ec_ucsi_pan_ack); 469 + 470 + /* -------------------------------------------------------------------------- */ 471 + /* EC Sysfs */ 472 + 473 + /* Fn lock */ 474 + static int gaokun_ec_get_fn_lock(struct gaokun_ec *ec, bool *on) 475 + { 476 + /* GFRS */ 477 + u8 ec_req[] = MKREQ(0x02, EC_FN_LOCK_READ, 0); 478 + int ret; 479 + u8 state; 480 + 481 + ret = gaokun_ec_read_byte(ec, ec_req, &state); 482 + if (ret) 483 + return ret; 484 + 485 + if (state == EC_FN_LOCK_ON) 486 + *on = true; 487 + else if (state == EC_FN_LOCK_OFF) 488 + *on = false; 489 + else 490 + return -EIO; 491 + 492 + return 0; 493 + } 494 + 495 + static int gaokun_ec_set_fn_lock(struct gaokun_ec *ec, bool on) 496 + { 497 + /* SFRS */ 498 + u8 ec_req[] = MKREQ(0x02, EC_FN_LOCK_WRITE, 1, 499 + on ? EC_FN_LOCK_ON : EC_FN_LOCK_OFF); 500 + 501 + return gaokun_ec_write(ec, ec_req); 502 + } 503 + 504 + static ssize_t fn_lock_show(struct device *dev, 505 + struct device_attribute *attr, 506 + char *buf) 507 + { 508 + struct gaokun_ec *ec = dev_get_drvdata(dev); 509 + bool on; 510 + int ret; 511 + 512 + ret = gaokun_ec_get_fn_lock(ec, &on); 513 + if (ret) 514 + return ret; 515 + 516 + return sysfs_emit(buf, "%d\n", on); 517 + } 518 + 519 + static ssize_t fn_lock_store(struct device *dev, 520 + struct device_attribute *attr, 521 + const char *buf, size_t size) 522 + { 523 + struct gaokun_ec *ec = dev_get_drvdata(dev); 524 + bool on; 525 + int ret; 526 + 527 + if (kstrtobool(buf, &on)) 528 + return -EINVAL; 529 + 530 + ret = gaokun_ec_set_fn_lock(ec, on); 531 + if (ret) 532 + return ret; 533 + 534 + return size; 535 + } 536 + 537 + static DEVICE_ATTR_RW(fn_lock); 538 + 539 + static struct attribute *gaokun_ec_attrs[] = { 540 + &dev_attr_fn_lock.attr, 541 + NULL, 542 + }; 543 + ATTRIBUTE_GROUPS(gaokun_ec); 544 + 545 + /* -------------------------------------------------------------------------- */ 546 + /* Thermal Zone HwMon */ 547 + 548 + /* Range from 0 to 0x2C, partially valid */ 549 + static const u8 temp_reg[] = { 550 + 0x05, 0x07, 0x08, 0x0E, 0x0F, 0x12, 0x15, 0x1E, 551 + 0x1F, 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 552 + 0x27, 0x28, 0x29, 0x2A 553 + }; 554 + 555 + static int gaokun_ec_get_temp(struct gaokun_ec *ec, u8 idx, long *temp) 556 + { 557 + /* GTMP */ 558 + u8 ec_req[] = MKREQ(0x02, EC_TEMP_REG, 1, temp_reg[idx]); 559 + u8 ec_resp[] = MKRESP(sizeof(__le16)); 560 + __le16 *tmp; 561 + int ret; 562 + 563 + ret = gaokun_ec_read(ec, ec_req, sizeof(ec_resp), ec_resp); 564 + if (ret) 565 + return ret; 566 + 567 + tmp = (__le16 *)extr_resp_shallow(ec_resp); 568 + *temp = le16_to_cpu(*tmp) * 100; /* convert to HwMon's unit */ 569 + 570 + return 0; 571 + } 572 + 573 + static umode_t 574 + gaokun_ec_hwmon_is_visible(const void *data, enum hwmon_sensor_types type, 575 + u32 attr, int channel) 576 + { 577 + return type == hwmon_temp ? 0444 : 0; 578 + } 579 + 580 + static int 581 + gaokun_ec_hwmon_read(struct device *dev, enum hwmon_sensor_types type, 582 + u32 attr, int channel, long *val) 583 + { 584 + struct gaokun_ec *ec = dev_get_drvdata(dev); 585 + 586 + if (type == hwmon_temp) 587 + return gaokun_ec_get_temp(ec, channel, val); 588 + 589 + return -EINVAL; 590 + } 591 + 592 + static const struct hwmon_ops gaokun_ec_hwmon_ops = { 593 + .is_visible = gaokun_ec_hwmon_is_visible, 594 + .read = gaokun_ec_hwmon_read, 595 + }; 596 + 597 + static u32 gaokun_ec_temp_config[] = { 598 + [0 ... ARRAY_SIZE(temp_reg) - 1] = HWMON_T_INPUT, 599 + 0 600 + }; 601 + 602 + static const struct hwmon_channel_info gaokun_ec_temp = { 603 + .type = hwmon_temp, 604 + .config = gaokun_ec_temp_config, 605 + }; 606 + 607 + static const struct hwmon_channel_info * const gaokun_ec_hwmon_info[] = { 608 + &gaokun_ec_temp, 609 + NULL 610 + }; 611 + 612 + static const struct hwmon_chip_info gaokun_ec_hwmon_chip_info = { 613 + .ops = &gaokun_ec_hwmon_ops, 614 + .info = gaokun_ec_hwmon_info, 615 + }; 616 + 617 + /* -------------------------------------------------------------------------- */ 618 + /* Modern Standby */ 619 + 620 + static int gaokun_ec_suspend(struct device *dev) 621 + { 622 + struct gaokun_ec *ec = dev_get_drvdata(dev); 623 + u8 ec_req[] = MKREQ(0x02, EC_STANDBY_REG, 1, EC_STANDBY_ENTER); 624 + int ret; 625 + 626 + if (ec->suspended) 627 + return 0; 628 + 629 + ret = gaokun_ec_write(ec, ec_req); 630 + if (ret) 631 + return ret; 632 + 633 + ec->suspended = true; 634 + 635 + return 0; 636 + } 637 + 638 + static int gaokun_ec_resume(struct device *dev) 639 + { 640 + struct gaokun_ec *ec = dev_get_drvdata(dev); 641 + u8 ec_req[] = MKREQ(0x02, EC_STANDBY_REG, 1, EC_STANDBY_EXIT); 642 + int ret; 643 + int i; 644 + 645 + if (!ec->suspended) 646 + return 0; 647 + 648 + for (i = 0; i < 3; ++i) { 649 + ret = gaokun_ec_write(ec, ec_req); 650 + if (ret == 0) 651 + break; 652 + 653 + msleep(100); /* EC need time to resume */ 654 + }; 655 + 656 + ec->suspended = false; 657 + 658 + return 0; 659 + } 660 + 661 + static void gaokun_aux_release(struct device *dev) 662 + { 663 + struct auxiliary_device *adev = to_auxiliary_dev(dev); 664 + 665 + kfree(adev); 666 + } 667 + 668 + static void gaokun_aux_remove(void *data) 669 + { 670 + struct auxiliary_device *adev = data; 671 + 672 + auxiliary_device_delete(adev); 673 + auxiliary_device_uninit(adev); 674 + } 675 + 676 + static int gaokun_aux_init(struct device *parent, const char *name, 677 + struct gaokun_ec *ec) 678 + { 679 + struct auxiliary_device *adev; 680 + int ret; 681 + 682 + adev = kzalloc(sizeof(*adev), GFP_KERNEL); 683 + if (!adev) 684 + return -ENOMEM; 685 + 686 + adev->name = name; 687 + adev->id = 0; 688 + adev->dev.parent = parent; 689 + adev->dev.release = gaokun_aux_release; 690 + adev->dev.platform_data = ec; 691 + /* Allow aux devices to access parent's DT nodes directly */ 692 + device_set_of_node_from_dev(&adev->dev, parent); 693 + 694 + ret = auxiliary_device_init(adev); 695 + if (ret) { 696 + kfree(adev); 697 + return ret; 698 + } 699 + 700 + ret = auxiliary_device_add(adev); 701 + if (ret) { 702 + auxiliary_device_uninit(adev); 703 + return ret; 704 + } 705 + 706 + return devm_add_action_or_reset(parent, gaokun_aux_remove, adev); 707 + } 708 + 709 + /* -------------------------------------------------------------------------- */ 710 + /* EC */ 711 + 712 + static irqreturn_t gaokun_ec_irq_handler(int irq, void *data) 713 + { 714 + struct gaokun_ec *ec = data; 715 + u8 ec_req[] = MKREQ(EC_EVENT, EC_QUERY, 0); 716 + u8 status, id; 717 + int ret; 718 + 719 + ret = gaokun_ec_read_byte(ec, ec_req, &id); 720 + if (ret) 721 + return IRQ_HANDLED; 722 + 723 + switch (id) { 724 + case 0x0: /* No event */ 725 + break; 726 + 727 + case EC_EVENT_LID: 728 + gaokun_ec_psy_read_byte(ec, EC_LID_STATE, &status); 729 + status &= EC_LID_OPEN; 730 + input_report_switch(ec->idev, SW_LID, !status); 731 + input_sync(ec->idev); 732 + break; 733 + 734 + default: 735 + blocking_notifier_call_chain(&ec->notifier_list, id, ec); 736 + } 737 + 738 + return IRQ_HANDLED; 739 + } 740 + 741 + static int gaokun_ec_probe(struct i2c_client *client) 742 + { 743 + struct device *dev = &client->dev; 744 + struct gaokun_ec *ec; 745 + int ret; 746 + 747 + ec = devm_kzalloc(dev, sizeof(*ec), GFP_KERNEL); 748 + if (!ec) 749 + return -ENOMEM; 750 + 751 + ret = devm_mutex_init(dev, &ec->lock); 752 + if (ret) 753 + return ret; 754 + 755 + ec->client = client; 756 + i2c_set_clientdata(client, ec); 757 + BLOCKING_INIT_NOTIFIER_HEAD(&ec->notifier_list); 758 + 759 + /* Lid switch */ 760 + ec->idev = devm_input_allocate_device(dev); 761 + if (!ec->idev) 762 + return -ENOMEM; 763 + 764 + ec->idev->name = "LID"; 765 + ec->idev->phys = "gaokun-ec/input0"; 766 + input_set_capability(ec->idev, EV_SW, SW_LID); 767 + 768 + ret = input_register_device(ec->idev); 769 + if (ret) 770 + return dev_err_probe(dev, ret, "Failed to register input device\n"); 771 + 772 + ret = gaokun_aux_init(dev, GAOKUN_DEV_PSY, ec); 773 + if (ret) 774 + return ret; 775 + 776 + ret = gaokun_aux_init(dev, GAOKUN_DEV_UCSI, ec); 777 + if (ret) 778 + return ret; 779 + 780 + ret = devm_request_threaded_irq(dev, client->irq, NULL, 781 + gaokun_ec_irq_handler, IRQF_ONESHOT, 782 + dev_name(dev), ec); 783 + if (ret) 784 + return dev_err_probe(dev, ret, "Failed to request IRQ\n"); 785 + 786 + ec->hwmon_dev = devm_hwmon_device_register_with_info(dev, "gaokun_ec_hwmon", 787 + ec, &gaokun_ec_hwmon_chip_info, NULL); 788 + if (IS_ERR(ec->hwmon_dev)) 789 + return dev_err_probe(dev, PTR_ERR(ec->hwmon_dev), 790 + "Failed to register hwmon device\n"); 791 + 792 + return 0; 793 + } 794 + 795 + static const struct i2c_device_id gaokun_ec_id[] = { 796 + { "gaokun-ec", }, 797 + { } 798 + }; 799 + MODULE_DEVICE_TABLE(i2c, gaokun_ec_id); 800 + 801 + static const struct of_device_id gaokun_ec_of_match[] = { 802 + { .compatible = "huawei,gaokun3-ec", }, 803 + { } 804 + }; 805 + MODULE_DEVICE_TABLE(of, gaokun_ec_of_match); 806 + 807 + static const struct dev_pm_ops gaokun_ec_pm_ops = { 808 + NOIRQ_SYSTEM_SLEEP_PM_OPS(gaokun_ec_suspend, gaokun_ec_resume) 809 + }; 810 + 811 + static struct i2c_driver gaokun_ec_driver = { 812 + .driver = { 813 + .name = "gaokun-ec", 814 + .of_match_table = gaokun_ec_of_match, 815 + .pm = &gaokun_ec_pm_ops, 816 + .dev_groups = gaokun_ec_groups, 817 + }, 818 + .probe = gaokun_ec_probe, 819 + .id_table = gaokun_ec_id, 820 + }; 821 + module_i2c_driver(gaokun_ec_driver); 822 + 823 + MODULE_DESCRIPTION("HUAWEI Matebook E Go EC driver"); 824 + MODULE_AUTHOR("Pengyu Luo <mitltlatltl@gmail.com>"); 825 + MODULE_LICENSE("GPL");
+13
drivers/platform/mellanox/Kconfig
··· 14 14 15 15 if MELLANOX_PLATFORM 16 16 17 + config MLX_PLATFORM 18 + tristate "Mellanox Technologies platform support" 19 + depends on ACPI && I2C && PCI 20 + select REGMAP 21 + help 22 + This option enables system support for the Mellanox Technologies 23 + platform. The Mellanox systems provide data center networking 24 + solutions based on Virtual Protocol Interconnect (VPI) technology 25 + enable seamless connectivity to 56/100Gb/s InfiniBand or 10/40/56GbE 26 + connection. 27 + 28 + If you have a Mellanox system, say Y or M here. 29 + 17 30 config MLXREG_HOTPLUG 18 31 tristate "Mellanox platform hotplug driver support" 19 32 depends on HWMON
+1
drivers/platform/mellanox/Makefile
··· 3 3 # Makefile for linux/drivers/platform/mellanox 4 4 # Mellanox Platform-Specific Drivers 5 5 # 6 + obj-$(CONFIG_MLX_PLATFORM) += mlx-platform.o 6 7 obj-$(CONFIG_MLXBF_BOOTCTL) += mlxbf-bootctl.o 7 8 obj-$(CONFIG_MLXBF_PMC) += mlxbf-pmc.o 8 9 obj-$(CONFIG_MLXBF_TMFIFO) += mlxbf-tmfifo.o
+20
drivers/platform/mellanox/mlxbf-bootctl.c
··· 91 91 static DEFINE_MUTEX(icm_ops_lock); 92 92 static DEFINE_MUTEX(os_up_lock); 93 93 static DEFINE_MUTEX(mfg_ops_lock); 94 + static DEFINE_MUTEX(rtc_ops_lock); 94 95 95 96 /* 96 97 * Objects are stored within the MFG partition per type. ··· 488 487 mutex_unlock(&icm_ops_lock); 489 488 490 489 return res.a0 ? -EPERM : count; 490 + } 491 + 492 + static ssize_t rtc_battery_show(struct device *dev, 493 + struct device_attribute *attr, 494 + char *buf) 495 + { 496 + struct arm_smccc_res res; 497 + 498 + mutex_lock(&rtc_ops_lock); 499 + arm_smccc_smc(MLNX_HANDLE_GET_RTC_LOW_BATT, 0, 0, 0, 0, 500 + 0, 0, 0, &res); 501 + mutex_unlock(&rtc_ops_lock); 502 + 503 + if (res.a0) 504 + return -EPERM; 505 + 506 + return sysfs_emit(buf, "0x%lx\n", res.a1); 491 507 } 492 508 493 509 static ssize_t os_up_store(struct device *dev, ··· 924 906 static DEVICE_ATTR_RW(uuid); 925 907 static DEVICE_ATTR_RW(rev); 926 908 static DEVICE_ATTR_WO(mfg_lock); 909 + static DEVICE_ATTR_RO(rtc_battery); 927 910 928 911 static struct attribute *mlxbf_bootctl_attrs[] = { 929 912 &dev_attr_post_reset_wdog.attr, ··· 944 925 &dev_attr_uuid.attr, 945 926 &dev_attr_rev.attr, 946 927 &dev_attr_mfg_lock.attr, 928 + &dev_attr_rtc_battery.attr, 947 929 NULL 948 930 }; 949 931
+5
drivers/platform/mellanox/mlxbf-bootctl.h
··· 103 103 */ 104 104 #define MLNX_HANDLE_OS_UP 0x82000014 105 105 106 + /* 107 + * SMC function ID to get and clear the RTC low voltage bit 108 + */ 109 + #define MLNX_HANDLE_GET_RTC_LOW_BATT 0x82000023 110 + 106 111 /* SMC function IDs for SiP Service queries */ 107 112 #define MLXBF_BOOTCTL_SIP_SVC_CALL_COUNT 0x8200ff00 108 113 #define MLXBF_BOOTCTL_SIP_SVC_UID 0x8200ff01
+28 -13
drivers/platform/x86/Kconfig
··· 475 475 This is a driver for Lenovo IdeaPad netbooks contains drivers for 476 476 rfkill switch, hotkey, fan control and backlight control. 477 477 478 + config LENOVO_WMI_HOTKEY_UTILITIES 479 + tristate "Lenovo Hotkey Utility WMI extras driver" 480 + depends on ACPI_WMI 481 + select NEW_LEDS 482 + select LEDS_CLASS 483 + imply IDEAPAD_LAPTOP 484 + help 485 + This driver provides WMI support for Lenovo customized hotkeys function, 486 + such as LED control for audio/mic mute event for Ideapad, YOGA, XiaoXin, 487 + Gaming, ThinkBook and so on. 488 + 478 489 config LENOVO_YMC 479 490 tristate "Lenovo Yoga Tablet Mode Control" 480 491 depends on ACPI_WMI ··· 789 778 To compile this driver as a module, choose M here: the module 790 779 will be called barco-p50-gpio. 791 780 781 + config SAMSUNG_GALAXYBOOK 782 + tristate "Samsung Galaxy Book driver" 783 + depends on ACPI 784 + depends on ACPI_BATTERY 785 + depends on INPUT 786 + depends on LEDS_CLASS 787 + depends on SERIO_I8042 788 + select ACPI_PLATFORM_PROFILE 789 + select FW_ATTR_CLASS 790 + help 791 + This is a driver for Samsung Galaxy Book series notebooks. It adds 792 + support for the keyboard backlight control, performance mode control, 793 + function keys, and various firmware attributes. 794 + 795 + For more information about this driver, see 796 + <file:Documentation/admin-guide/laptops/samsung-galaxybook.rst>. 797 + 792 798 config SAMSUNG_LAPTOP 793 799 tristate "Samsung Laptop driver" 794 800 depends on RFKILL || RFKILL = n ··· 1039 1011 1040 1012 To compile this driver as a module, choose M here: the module 1041 1013 will be called serial-multi-instantiate. 1042 - 1043 - config MLX_PLATFORM 1044 - tristate "Mellanox Technologies platform support" 1045 - depends on ACPI && I2C && PCI 1046 - select REGMAP 1047 - help 1048 - This option enables system support for the Mellanox Technologies 1049 - platform. The Mellanox systems provide data center networking 1050 - solutions based on Virtual Protocol Interconnect (VPI) technology 1051 - enable seamless connectivity to 56/100Gb/s InfiniBand or 10/40/56GbE 1052 - connection. 1053 - 1054 - If you have a Mellanox system, say Y or M here. 1055 1014 1056 1015 config TOUCHSCREEN_DMI 1057 1016 bool "DMI based touchscreen configuration info"
+4 -3
drivers/platform/x86/Makefile
··· 61 61 # IBM Thinkpad and Lenovo 62 62 obj-$(CONFIG_IBM_RTL) += ibm_rtl.o 63 63 obj-$(CONFIG_IDEAPAD_LAPTOP) += ideapad-laptop.o 64 + obj-$(CONFIG_LENOVO_WMI_HOTKEY_UTILITIES) += lenovo-wmi-hotkey-utilities.o 64 65 obj-$(CONFIG_LENOVO_YMC) += lenovo-ymc.o 65 66 obj-$(CONFIG_SENSORS_HDAPS) += hdaps.o 66 67 obj-$(CONFIG_THINKPAD_ACPI) += thinkpad_acpi.o ··· 96 95 obj-$(CONFIG_BARCO_P50_GPIO) += barco-p50-gpio.o 97 96 98 97 # Samsung 99 - obj-$(CONFIG_SAMSUNG_LAPTOP) += samsung-laptop.o 100 - obj-$(CONFIG_SAMSUNG_Q10) += samsung-q10.o 98 + obj-$(CONFIG_SAMSUNG_GALAXYBOOK) += samsung-galaxybook.o 99 + obj-$(CONFIG_SAMSUNG_LAPTOP) += samsung-laptop.o 100 + obj-$(CONFIG_SAMSUNG_Q10) += samsung-q10.o 101 101 102 102 # Toshiba 103 103 obj-$(CONFIG_TOSHIBA_BT_RFKILL) += toshiba_bluetooth.o ··· 124 122 # Platform drivers 125 123 obj-$(CONFIG_FW_ATTR_CLASS) += firmware_attributes_class.o 126 124 obj-$(CONFIG_SERIAL_MULTI_INSTANTIATE) += serial-multi-instantiate.o 127 - obj-$(CONFIG_MLX_PLATFORM) += mlx-platform.o 128 125 obj-$(CONFIG_TOUCHSCREEN_DMI) += touchscreen_dmi.o 129 126 obj-$(CONFIG_WIRELESS_HOTKEY) += wireless-hotkey.o 130 127 obj-$(CONFIG_X86_ANDROID_TABLETS) += x86-android-tablets/
+1 -1
drivers/platform/x86/amd/Makefile
··· 5 5 # 6 6 7 7 obj-$(CONFIG_AMD_3D_VCACHE) += amd_3d_vcache.o 8 - amd_3d_vcache-objs := x3d_vcache.o 8 + amd_3d_vcache-y := x3d_vcache.o 9 9 obj-$(CONFIG_AMD_PMC) += pmc/ 10 10 obj-$(CONFIG_AMD_HSMP) += hsmp/ 11 11 obj-$(CONFIG_AMD_PMF) += pmf/
+3 -3
drivers/platform/x86/amd/hsmp/Makefile
··· 5 5 # 6 6 7 7 obj-$(CONFIG_AMD_HSMP) += hsmp_common.o 8 - hsmp_common-objs := hsmp.o 8 + hsmp_common-y := hsmp.o 9 9 obj-$(CONFIG_AMD_HSMP_PLAT) += amd_hsmp.o 10 - amd_hsmp-objs := plat.o 10 + amd_hsmp-y := plat.o 11 11 obj-$(CONFIG_AMD_HSMP_ACPI) += hsmp_acpi.o 12 - hsmp_acpi-objs := acpi.o 12 + hsmp_acpi-y := acpi.o
+3 -3
drivers/platform/x86/amd/pmc/Makefile
··· 4 4 # AMD Power Management Controller Driver 5 5 # 6 6 7 - amd-pmc-objs := pmc.o pmc-quirks.o mp1_stb.o 8 - obj-$(CONFIG_AMD_PMC) += amd-pmc.o 9 - amd-pmc-$(CONFIG_AMD_MP2_STB) += mp2_stb.o 7 + obj-$(CONFIG_AMD_PMC) += amd-pmc.o 8 + amd-pmc-y := pmc.o pmc-quirks.o mp1_stb.o 9 + amd-pmc-$(CONFIG_AMD_MP2_STB) += mp2_stb.o
+16 -97
drivers/platform/x86/amd/pmc/pmc.c
··· 32 32 33 33 #include "pmc.h" 34 34 35 - /* SMU communication registers */ 36 - #define AMD_PMC_REGISTER_RESPONSE 0x980 37 - #define AMD_PMC_REGISTER_ARGUMENT 0x9BC 38 - 39 - /* PMC Scratch Registers */ 40 - #define AMD_PMC_SCRATCH_REG_CZN 0x94 41 - #define AMD_PMC_SCRATCH_REG_YC 0xD14 42 - #define AMD_PMC_SCRATCH_REG_1AH 0xF14 43 - 44 - /* STB Registers */ 45 - #define AMD_PMC_STB_S2IDLE_PREPARE 0xC6000001 46 - #define AMD_PMC_STB_S2IDLE_RESTORE 0xC6000002 47 - #define AMD_PMC_STB_S2IDLE_CHECK 0xC6000003 48 - 49 - /* Base address of SMU for mapping physical address to virtual address */ 50 - #define AMD_PMC_MAPPING_SIZE 0x01000 51 - #define AMD_PMC_BASE_ADDR_OFFSET 0x10000 52 - #define AMD_PMC_BASE_ADDR_LO 0x13B102E8 53 - #define AMD_PMC_BASE_ADDR_HI 0x13B102EC 54 - #define AMD_PMC_BASE_ADDR_LO_MASK GENMASK(15, 0) 55 - #define AMD_PMC_BASE_ADDR_HI_MASK GENMASK(31, 20) 56 - 57 - /* SMU Response Codes */ 58 - #define AMD_PMC_RESULT_OK 0x01 59 - #define AMD_PMC_RESULT_CMD_REJECT_BUSY 0xFC 60 - #define AMD_PMC_RESULT_CMD_REJECT_PREREQ 0xFD 61 - #define AMD_PMC_RESULT_CMD_UNKNOWN 0xFE 62 - #define AMD_PMC_RESULT_FAILED 0xFF 63 - 64 - /* FCH SSC Registers */ 65 - #define FCH_S0I3_ENTRY_TIME_L_OFFSET 0x30 66 - #define FCH_S0I3_ENTRY_TIME_H_OFFSET 0x34 67 - #define FCH_S0I3_EXIT_TIME_L_OFFSET 0x38 68 - #define FCH_S0I3_EXIT_TIME_H_OFFSET 0x3C 69 - #define FCH_SSC_MAPPING_SIZE 0x800 70 - #define FCH_BASE_PHY_ADDR_LOW 0xFED81100 71 - #define FCH_BASE_PHY_ADDR_HIGH 0x00000000 72 - 73 - /* SMU Message Definations */ 74 - #define SMU_MSG_GETSMUVERSION 0x02 75 - #define SMU_MSG_LOG_GETDRAM_ADDR_HI 0x04 76 - #define SMU_MSG_LOG_GETDRAM_ADDR_LO 0x05 77 - #define SMU_MSG_LOG_START 0x06 78 - #define SMU_MSG_LOG_RESET 0x07 79 - #define SMU_MSG_LOG_DUMP_DATA 0x08 80 - #define SMU_MSG_GET_SUP_CONSTRAINTS 0x09 81 - 82 - #define PMC_MSG_DELAY_MIN_US 50 83 - #define RESPONSE_REGISTER_LOOP_MAX 20000 84 - 85 - #define DELAY_MIN_US 2000 86 - #define DELAY_MAX_US 3000 87 - 88 - enum amd_pmc_def { 89 - MSG_TEST = 0x01, 90 - MSG_OS_HINT_PCO, 91 - MSG_OS_HINT_RN, 92 - }; 93 - 94 - struct amd_pmc_bit_map { 95 - const char *name; 96 - u32 bit_mask; 97 - }; 98 - 99 35 static const struct amd_pmc_bit_map soc15_ip_blk_v2[] = { 100 36 {"DISPLAY", BIT(0)}, 101 37 {"CPU", BIT(1)}, ··· 101 165 iowrite32(val, dev->regbase + reg_offset); 102 166 } 103 167 104 - struct smu_metrics { 105 - u32 table_version; 106 - u32 hint_count; 107 - u32 s0i3_last_entry_status; 108 - u32 timein_s0i2; 109 - u64 timeentering_s0i3_lastcapture; 110 - u64 timeentering_s0i3_totaltime; 111 - u64 timeto_resume_to_os_lastcapture; 112 - u64 timeto_resume_to_os_totaltime; 113 - u64 timein_s0i3_lastcapture; 114 - u64 timein_s0i3_totaltime; 115 - u64 timein_swdrips_lastcapture; 116 - u64 timein_swdrips_totaltime; 117 - u64 timecondition_notmet_lastcapture[32]; 118 - u64 timecondition_notmet_totaltime[32]; 119 - } __packed; 120 - 121 168 static void amd_pmc_get_ip_info(struct amd_pmc_dev *dev) 122 169 { 123 170 switch (dev->cpu_id) { ··· 166 247 167 248 static int get_metrics_table(struct amd_pmc_dev *pdev, struct smu_metrics *table) 168 249 { 169 - if (!pdev->smu_virt_addr) { 170 - int ret = amd_pmc_setup_smu_logging(pdev); 250 + int rc; 171 251 172 - if (ret) 173 - return ret; 252 + if (!pdev->smu_virt_addr) { 253 + rc = amd_pmc_setup_smu_logging(pdev); 254 + if (rc) 255 + return rc; 174 256 } 175 257 176 258 if (pdev->cpu_id == AMD_CPU_ID_PCO) ··· 220 300 char *buf) 221 301 { 222 302 struct amd_pmc_dev *dev = dev_get_drvdata(d); 303 + int rc; 223 304 224 305 if (!dev->major) { 225 - int rc = amd_pmc_get_smu_version(dev); 226 - 306 + rc = amd_pmc_get_smu_version(dev); 227 307 if (rc) 228 308 return rc; 229 309 } ··· 234 314 char *buf) 235 315 { 236 316 struct amd_pmc_dev *dev = dev_get_drvdata(d); 317 + int rc; 237 318 238 319 if (!dev->major) { 239 - int rc = amd_pmc_get_smu_version(dev); 240 - 320 + rc = amd_pmc_get_smu_version(dev); 241 321 if (rc) 242 322 return rc; 243 323 } ··· 698 778 static int amd_pmc_suspend_handler(struct device *dev) 699 779 { 700 780 struct amd_pmc_dev *pdev = dev_get_drvdata(dev); 781 + int rc; 701 782 702 783 /* 703 784 * Must be called only from the same set of dev_pm_ops handlers 704 785 * as i8042_pm_suspend() is called: currently just from .suspend. 705 786 */ 706 787 if (pdev->disable_8042_wakeup && !disable_workarounds) { 707 - int rc = amd_pmc_wa_irq1(pdev); 708 - 788 + rc = amd_pmc_wa_irq1(pdev); 709 789 if (rc) { 710 790 dev_err(pdev->dev, "failed to adjust keyboard wakeup: %d\n", rc); 711 791 return rc; ··· 728 808 { PCI_DEVICE(PCI_VENDOR_ID_AMD, AMD_CPU_ID_PCO) }, 729 809 { PCI_DEVICE(PCI_VENDOR_ID_AMD, AMD_CPU_ID_RV) }, 730 810 { PCI_DEVICE(PCI_VENDOR_ID_AMD, AMD_CPU_ID_SP) }, 811 + { PCI_DEVICE(PCI_VENDOR_ID_AMD, AMD_CPU_ID_SHP) }, 731 812 { PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_1AH_M20H_ROOT) }, 732 813 { PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_1AH_M60H_ROOT) }, 733 814 { } ··· 744 823 u32 val; 745 824 746 825 dev->dev = &pdev->dev; 747 - 748 826 rdev = pci_get_domain_bus_and_slot(0, 0, PCI_DEVFN(0, 0)); 749 827 if (!rdev || !pci_match_id(pmc_pci_ids, rdev)) { 750 828 err = -ENODEV; ··· 751 831 } 752 832 753 833 dev->cpu_id = rdev->device; 754 - 755 - if (dev->cpu_id == AMD_CPU_ID_SP) { 834 + if (dev->cpu_id == AMD_CPU_ID_SP || dev->cpu_id == AMD_CPU_ID_SHP) { 756 835 dev_warn_once(dev->dev, "S0i3 is not supported on this hardware\n"); 757 836 err = -ENODEV; 758 837 goto err_pci_dev_put; ··· 766 847 } 767 848 768 849 base_addr_lo = val & AMD_PMC_BASE_ADDR_HI_MASK; 769 - 770 850 err = amd_smn_read(0, AMD_PMC_BASE_ADDR_HI, &val); 771 851 if (err) { 772 852 dev_err(dev->dev, "error reading 0x%x\n", AMD_PMC_BASE_ADDR_HI); ··· 783 865 goto err_pci_dev_put; 784 866 } 785 867 786 - mutex_init(&dev->lock); 868 + err = devm_mutex_init(dev->dev, &dev->lock); 869 + if (err) 870 + goto err_pci_dev_put; 787 871 788 872 /* Get num of IP blocks within the SoC */ 789 873 amd_pmc_get_ip_info(dev); ··· 824 904 pci_dev_put(dev->rdev); 825 905 if (IS_ENABLED(CONFIG_AMD_MP2_STB)) 826 906 amd_mp2_stb_deinit(dev); 827 - mutex_destroy(&dev->lock); 828 907 } 829 908 830 909 static const struct acpi_device_id amd_pmc_acpi_ids[] = {
+82
drivers/platform/x86/amd/pmc/pmc.h
··· 14 14 #include <linux/types.h> 15 15 #include <linux/mutex.h> 16 16 17 + /* SMU communication registers */ 18 + #define AMD_PMC_REGISTER_RESPONSE 0x980 19 + #define AMD_PMC_REGISTER_ARGUMENT 0x9BC 20 + 21 + /* PMC Scratch Registers */ 22 + #define AMD_PMC_SCRATCH_REG_CZN 0x94 23 + #define AMD_PMC_SCRATCH_REG_YC 0xD14 24 + #define AMD_PMC_SCRATCH_REG_1AH 0xF14 25 + 26 + /* STB Registers */ 27 + #define AMD_PMC_STB_S2IDLE_PREPARE 0xC6000001 28 + #define AMD_PMC_STB_S2IDLE_RESTORE 0xC6000002 29 + #define AMD_PMC_STB_S2IDLE_CHECK 0xC6000003 30 + 31 + /* Base address of SMU for mapping physical address to virtual address */ 32 + #define AMD_PMC_MAPPING_SIZE 0x01000 33 + #define AMD_PMC_BASE_ADDR_OFFSET 0x10000 34 + #define AMD_PMC_BASE_ADDR_LO 0x13B102E8 35 + #define AMD_PMC_BASE_ADDR_HI 0x13B102EC 36 + #define AMD_PMC_BASE_ADDR_LO_MASK GENMASK(15, 0) 37 + #define AMD_PMC_BASE_ADDR_HI_MASK GENMASK(31, 20) 38 + 39 + /* SMU Response Codes */ 40 + #define AMD_PMC_RESULT_OK 0x01 41 + #define AMD_PMC_RESULT_CMD_REJECT_BUSY 0xFC 42 + #define AMD_PMC_RESULT_CMD_REJECT_PREREQ 0xFD 43 + #define AMD_PMC_RESULT_CMD_UNKNOWN 0xFE 44 + #define AMD_PMC_RESULT_FAILED 0xFF 45 + 46 + /* FCH SSC Registers */ 47 + #define FCH_S0I3_ENTRY_TIME_L_OFFSET 0x30 48 + #define FCH_S0I3_ENTRY_TIME_H_OFFSET 0x34 49 + #define FCH_S0I3_EXIT_TIME_L_OFFSET 0x38 50 + #define FCH_S0I3_EXIT_TIME_H_OFFSET 0x3C 51 + #define FCH_SSC_MAPPING_SIZE 0x800 52 + #define FCH_BASE_PHY_ADDR_LOW 0xFED81100 53 + #define FCH_BASE_PHY_ADDR_HIGH 0x00000000 54 + 55 + /* SMU Message Definations */ 56 + #define SMU_MSG_GETSMUVERSION 0x02 57 + #define SMU_MSG_LOG_GETDRAM_ADDR_HI 0x04 58 + #define SMU_MSG_LOG_GETDRAM_ADDR_LO 0x05 59 + #define SMU_MSG_LOG_START 0x06 60 + #define SMU_MSG_LOG_RESET 0x07 61 + #define SMU_MSG_LOG_DUMP_DATA 0x08 62 + #define SMU_MSG_GET_SUP_CONSTRAINTS 0x09 63 + 64 + #define PMC_MSG_DELAY_MIN_US 50 65 + #define RESPONSE_REGISTER_LOOP_MAX 20000 66 + 67 + #define DELAY_MIN_US 2000 68 + #define DELAY_MAX_US 3000 69 + 17 70 enum s2d_msg_port { 18 71 MSG_PORT_PMC, 19 72 MSG_PORT_S2D, ··· 118 65 struct stb_arg stb_arg; 119 66 }; 120 67 68 + struct amd_pmc_bit_map { 69 + const char *name; 70 + u32 bit_mask; 71 + }; 72 + 73 + struct smu_metrics { 74 + u32 table_version; 75 + u32 hint_count; 76 + u32 s0i3_last_entry_status; 77 + u32 timein_s0i2; 78 + u64 timeentering_s0i3_lastcapture; 79 + u64 timeentering_s0i3_totaltime; 80 + u64 timeto_resume_to_os_lastcapture; 81 + u64 timeto_resume_to_os_totaltime; 82 + u64 timein_s0i3_lastcapture; 83 + u64 timein_s0i3_totaltime; 84 + u64 timein_swdrips_lastcapture; 85 + u64 timein_swdrips_totaltime; 86 + u64 timecondition_notmet_lastcapture[32]; 87 + u64 timecondition_notmet_totaltime[32]; 88 + } __packed; 89 + 90 + enum amd_pmc_def { 91 + MSG_TEST = 0x01, 92 + MSG_OS_HINT_PCO, 93 + MSG_OS_HINT_RN, 94 + }; 95 + 121 96 void amd_pmc_process_restore_quirks(struct amd_pmc_dev *dev); 122 97 void amd_pmc_quirks_init(struct amd_pmc_dev *dev); 123 98 void amd_mp2_stb_init(struct amd_pmc_dev *dev); ··· 160 79 #define AMD_CPU_ID_CB 0x14D8 161 80 #define AMD_CPU_ID_PS 0x14E8 162 81 #define AMD_CPU_ID_SP 0x14A4 82 + #define AMD_CPU_ID_SHP 0x153A 163 83 #define PCI_DEVICE_ID_AMD_1AH_M20H_ROOT 0x1507 164 84 #define PCI_DEVICE_ID_AMD_1AH_M60H_ROOT 0x1122 165 85 #define PCI_DEVICE_ID_AMD_MP2_STB 0x172c
+4 -4
drivers/platform/x86/amd/pmf/Makefile
··· 4 4 # AMD Platform Management Framework 5 5 # 6 6 7 - obj-$(CONFIG_AMD_PMF) += amd-pmf.o 8 - amd-pmf-objs := core.o acpi.o sps.o \ 9 - auto-mode.o cnqf.o \ 10 - tee-if.o spc.o 7 + obj-$(CONFIG_AMD_PMF) += amd-pmf.o 8 + amd-pmf-y := core.o acpi.o sps.o \ 9 + auto-mode.o cnqf.o \ 10 + tee-if.o spc.o
+1 -1
drivers/platform/x86/amd/pmf/acpi.c
··· 220 220 if (!info) 221 221 return; 222 222 223 - schedule_delayed_work(&dev->heart_beat, msecs_to_jiffies(dev->hb_interval * 1000)); 223 + schedule_delayed_work(&dev->heart_beat, secs_to_jiffies(dev->hb_interval)); 224 224 kfree(info); 225 225 } 226 226
+1 -1
drivers/platform/x86/asus-tf103c-dock.c
··· 856 856 /* 5. Setup irqchip for touchpad IRQ pass-through */ 857 857 dock->tp_irqchip.name = KBUILD_MODNAME; 858 858 859 - dock->tp_irq_domain = irq_domain_add_linear(NULL, 1, &irq_domain_simple_ops, NULL); 859 + dock->tp_irq_domain = irq_domain_create_linear(NULL, 1, &irq_domain_simple_ops, NULL); 860 860 if (!dock->tp_irq_domain) 861 861 return -ENOMEM; 862 862
-1
drivers/platform/x86/compal-laptop.c
··· 69 69 #include <linux/hwmon-sysfs.h> 70 70 #include <linux/power_supply.h> 71 71 #include <linux/sysfs.h> 72 - #include <linux/fb.h> 73 72 #include <acpi/video.h> 74 73 75 74 /* ======= */
+25 -5
drivers/platform/x86/dell/Kconfig
··· 18 18 tristate "Alienware Special feature control" 19 19 default m 20 20 depends on ACPI 21 + depends on ACPI_WMI 22 + depends on DMI 21 23 depends on LEDS_CLASS 22 24 depends on NEW_LEDS 23 - depends on ACPI_WMI 25 + help 26 + This is a driver for controlling Alienware WMI driven features. 27 + 28 + On legacy devices, it exposes an interface for controlling the AlienFX 29 + zones on Alienware machines that don't contain a dedicated 30 + AlienFX USB MCU such as the X51 and X51-R2. 31 + 32 + On newer devices, it exposes the AWCC thermal control interface through 33 + known Kernel APIs. 34 + 35 + config ALIENWARE_WMI_LEGACY 36 + bool "Alienware Legacy WMI device driver" 37 + default y 38 + depends on ALIENWARE_WMI 39 + help 40 + Legacy Alienware WMI driver with AlienFX LED control capabilities. 41 + 42 + config ALIENWARE_WMI_WMAX 43 + bool "Alienware WMAX WMI device driver" 44 + default y 45 + depends on ALIENWARE_WMI 24 46 select ACPI_PLATFORM_PROFILE 25 47 help 26 - This is a driver for controlling Alienware BIOS driven 27 - features. It exposes an interface for controlling the AlienFX 28 - zones on Alienware machines that don't contain a dedicated AlienFX 29 - USB MCU such as the X51 and X51-R2. 48 + Alienware WMI driver with AlienFX LED, HDMI, amplifier, deep sleep and 49 + AWCC thermal control capabilities. 30 50 31 51 config DCDBAS 32 52 tristate "Dell Systems Management Base Driver"
+24 -21
drivers/platform/x86/dell/Makefile
··· 4 4 # Dell x86 Platform-Specific Drivers 5 5 # 6 6 7 - obj-$(CONFIG_ALIENWARE_WMI) += alienware-wmi.o 8 - obj-$(CONFIG_DCDBAS) += dcdbas.o 9 - obj-$(CONFIG_DELL_LAPTOP) += dell-laptop.o 10 - obj-$(CONFIG_DELL_RBTN) += dell-rbtn.o 11 - obj-$(CONFIG_DELL_RBU) += dell_rbu.o 12 - obj-$(CONFIG_DELL_PC) += dell-pc.o 13 - obj-$(CONFIG_DELL_SMBIOS) += dell-smbios.o 14 - dell-smbios-objs := dell-smbios-base.o 15 - dell-smbios-$(CONFIG_DELL_SMBIOS_WMI) += dell-smbios-wmi.o 16 - dell-smbios-$(CONFIG_DELL_SMBIOS_SMM) += dell-smbios-smm.o 17 - obj-$(CONFIG_DELL_SMO8800) += dell-smo8800.o 18 - obj-$(CONFIG_DELL_SMO8800) += dell-lis3lv02d.o 19 - obj-$(CONFIG_DELL_UART_BACKLIGHT) += dell-uart-backlight.o 20 - obj-$(CONFIG_DELL_WMI) += dell-wmi.o 21 - dell-wmi-objs := dell-wmi-base.o 22 - dell-wmi-$(CONFIG_DELL_WMI_PRIVACY) += dell-wmi-privacy.o 23 - obj-$(CONFIG_DELL_WMI_AIO) += dell-wmi-aio.o 24 - obj-$(CONFIG_DELL_WMI_DESCRIPTOR) += dell-wmi-descriptor.o 25 - obj-$(CONFIG_DELL_WMI_DDV) += dell-wmi-ddv.o 26 - obj-$(CONFIG_DELL_WMI_LED) += dell-wmi-led.o 27 - obj-$(CONFIG_DELL_WMI_SYSMAN) += dell-wmi-sysman/ 7 + obj-$(CONFIG_ALIENWARE_WMI) += alienware-wmi.o 8 + alienware-wmi-y := alienware-wmi-base.o 9 + alienware-wmi-$(CONFIG_ALIENWARE_WMI_LEGACY) += alienware-wmi-legacy.o 10 + alienware-wmi-$(CONFIG_ALIENWARE_WMI_WMAX) += alienware-wmi-wmax.o 11 + obj-$(CONFIG_DCDBAS) += dcdbas.o 12 + obj-$(CONFIG_DELL_LAPTOP) += dell-laptop.o 13 + obj-$(CONFIG_DELL_RBTN) += dell-rbtn.o 14 + obj-$(CONFIG_DELL_RBU) += dell_rbu.o 15 + obj-$(CONFIG_DELL_PC) += dell-pc.o 16 + obj-$(CONFIG_DELL_SMBIOS) += dell-smbios.o 17 + dell-smbios-y := dell-smbios-base.o 18 + dell-smbios-$(CONFIG_DELL_SMBIOS_WMI) += dell-smbios-wmi.o 19 + dell-smbios-$(CONFIG_DELL_SMBIOS_SMM) += dell-smbios-smm.o 20 + obj-$(CONFIG_DELL_SMO8800) += dell-smo8800.o 21 + obj-$(CONFIG_DELL_SMO8800) += dell-lis3lv02d.o 22 + obj-$(CONFIG_DELL_UART_BACKLIGHT) += dell-uart-backlight.o 23 + obj-$(CONFIG_DELL_WMI) += dell-wmi.o 24 + dell-wmi-y := dell-wmi-base.o 25 + dell-wmi-$(CONFIG_DELL_WMI_PRIVACY) += dell-wmi-privacy.o 26 + obj-$(CONFIG_DELL_WMI_AIO) += dell-wmi-aio.o 27 + obj-$(CONFIG_DELL_WMI_DESCRIPTOR) += dell-wmi-descriptor.o 28 + obj-$(CONFIG_DELL_WMI_DDV) += dell-wmi-ddv.o 29 + obj-$(CONFIG_DELL_WMI_LED) += dell-wmi-led.o 30 + obj-$(CONFIG_DELL_WMI_SYSMAN) += dell-wmi-sysman/
+491
drivers/platform/x86/dell/alienware-wmi-base.c
··· 1 + // SPDX-License-Identifier: GPL-2.0-or-later 2 + /* 3 + * Alienware special feature control 4 + * 5 + * Copyright (C) 2014 Dell Inc <Dell.Client.Kernel@dell.com> 6 + * Copyright (C) 2025 Kurt Borja <kuurtb@gmail.com> 7 + */ 8 + 9 + #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt 10 + 11 + #include <linux/acpi.h> 12 + #include <linux/cleanup.h> 13 + #include <linux/module.h> 14 + #include <linux/platform_device.h> 15 + #include <linux/dmi.h> 16 + #include <linux/leds.h> 17 + #include "alienware-wmi.h" 18 + 19 + MODULE_AUTHOR("Mario Limonciello <mario.limonciello@outlook.com>"); 20 + MODULE_AUTHOR("Kurt Borja <kuurtb@gmail.com>"); 21 + MODULE_DESCRIPTION("Alienware special feature control"); 22 + MODULE_LICENSE("GPL"); 23 + 24 + struct alienfx_quirks *alienfx; 25 + 26 + static struct alienfx_quirks quirk_inspiron5675 = { 27 + .num_zones = 2, 28 + .hdmi_mux = false, 29 + .amplifier = false, 30 + .deepslp = false, 31 + }; 32 + 33 + static struct alienfx_quirks quirk_unknown = { 34 + .num_zones = 2, 35 + .hdmi_mux = false, 36 + .amplifier = false, 37 + .deepslp = false, 38 + }; 39 + 40 + static struct alienfx_quirks quirk_x51_r1_r2 = { 41 + .num_zones = 3, 42 + .hdmi_mux = false, 43 + .amplifier = false, 44 + .deepslp = false, 45 + }; 46 + 47 + static struct alienfx_quirks quirk_x51_r3 = { 48 + .num_zones = 4, 49 + .hdmi_mux = false, 50 + .amplifier = true, 51 + .deepslp = false, 52 + }; 53 + 54 + static struct alienfx_quirks quirk_asm100 = { 55 + .num_zones = 2, 56 + .hdmi_mux = true, 57 + .amplifier = false, 58 + .deepslp = false, 59 + }; 60 + 61 + static struct alienfx_quirks quirk_asm200 = { 62 + .num_zones = 2, 63 + .hdmi_mux = true, 64 + .amplifier = false, 65 + .deepslp = true, 66 + }; 67 + 68 + static struct alienfx_quirks quirk_asm201 = { 69 + .num_zones = 2, 70 + .hdmi_mux = true, 71 + .amplifier = true, 72 + .deepslp = true, 73 + }; 74 + 75 + static int __init dmi_matched(const struct dmi_system_id *dmi) 76 + { 77 + alienfx = dmi->driver_data; 78 + return 1; 79 + } 80 + 81 + static const struct dmi_system_id alienware_quirks[] __initconst = { 82 + { 83 + .callback = dmi_matched, 84 + .ident = "Alienware ASM100", 85 + .matches = { 86 + DMI_MATCH(DMI_SYS_VENDOR, "Alienware"), 87 + DMI_MATCH(DMI_PRODUCT_NAME, "ASM100"), 88 + }, 89 + .driver_data = &quirk_asm100, 90 + }, 91 + { 92 + .callback = dmi_matched, 93 + .ident = "Alienware ASM200", 94 + .matches = { 95 + DMI_MATCH(DMI_SYS_VENDOR, "Alienware"), 96 + DMI_MATCH(DMI_PRODUCT_NAME, "ASM200"), 97 + }, 98 + .driver_data = &quirk_asm200, 99 + }, 100 + { 101 + .callback = dmi_matched, 102 + .ident = "Alienware ASM201", 103 + .matches = { 104 + DMI_MATCH(DMI_SYS_VENDOR, "Alienware"), 105 + DMI_MATCH(DMI_PRODUCT_NAME, "ASM201"), 106 + }, 107 + .driver_data = &quirk_asm201, 108 + }, 109 + { 110 + .callback = dmi_matched, 111 + .ident = "Alienware X51 R1", 112 + .matches = { 113 + DMI_MATCH(DMI_SYS_VENDOR, "Alienware"), 114 + DMI_MATCH(DMI_PRODUCT_NAME, "Alienware X51"), 115 + }, 116 + .driver_data = &quirk_x51_r1_r2, 117 + }, 118 + { 119 + .callback = dmi_matched, 120 + .ident = "Alienware X51 R2", 121 + .matches = { 122 + DMI_MATCH(DMI_SYS_VENDOR, "Alienware"), 123 + DMI_MATCH(DMI_PRODUCT_NAME, "Alienware X51 R2"), 124 + }, 125 + .driver_data = &quirk_x51_r1_r2, 126 + }, 127 + { 128 + .callback = dmi_matched, 129 + .ident = "Alienware X51 R3", 130 + .matches = { 131 + DMI_MATCH(DMI_SYS_VENDOR, "Alienware"), 132 + DMI_MATCH(DMI_PRODUCT_NAME, "Alienware X51 R3"), 133 + }, 134 + .driver_data = &quirk_x51_r3, 135 + }, 136 + { 137 + .callback = dmi_matched, 138 + .ident = "Dell Inc. Inspiron 5675", 139 + .matches = { 140 + DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."), 141 + DMI_MATCH(DMI_PRODUCT_NAME, "Inspiron 5675"), 142 + }, 143 + .driver_data = &quirk_inspiron5675, 144 + }, 145 + {} 146 + }; 147 + 148 + u8 alienware_interface; 149 + 150 + int alienware_wmi_command(struct wmi_device *wdev, u32 method_id, 151 + void *in_args, size_t in_size, u32 *out_data) 152 + { 153 + struct acpi_buffer out = {ACPI_ALLOCATE_BUFFER, NULL}; 154 + struct acpi_buffer in = {in_size, in_args}; 155 + acpi_status ret; 156 + 157 + ret = wmidev_evaluate_method(wdev, 0, method_id, &in, out_data ? &out : NULL); 158 + if (ACPI_FAILURE(ret)) 159 + return -EIO; 160 + 161 + union acpi_object *obj __free(kfree) = out.pointer; 162 + 163 + if (out_data) { 164 + if (obj && obj->type == ACPI_TYPE_INTEGER) 165 + *out_data = (u32)obj->integer.value; 166 + else 167 + return -ENOMSG; 168 + } 169 + 170 + return 0; 171 + } 172 + 173 + /* 174 + * Helpers used for zone control 175 + */ 176 + static int parse_rgb(const char *buf, struct color_platform *colors) 177 + { 178 + long unsigned int rgb; 179 + int ret; 180 + union color_union { 181 + struct color_platform cp; 182 + int package; 183 + } repackager; 184 + 185 + ret = kstrtoul(buf, 16, &rgb); 186 + if (ret) 187 + return ret; 188 + 189 + /* RGB triplet notation is 24-bit hexadecimal */ 190 + if (rgb > 0xFFFFFF) 191 + return -EINVAL; 192 + 193 + repackager.package = rgb & 0x0f0f0f0f; 194 + pr_debug("alienware-wmi: r: %d g:%d b: %d\n", 195 + repackager.cp.red, repackager.cp.green, repackager.cp.blue); 196 + *colors = repackager.cp; 197 + return 0; 198 + } 199 + 200 + /* 201 + * Individual RGB zone control 202 + */ 203 + static ssize_t zone_show(struct device *dev, struct device_attribute *attr, 204 + char *buf, u8 location) 205 + { 206 + struct alienfx_priv *priv = dev_get_drvdata(dev); 207 + struct color_platform *colors = &priv->colors[location]; 208 + 209 + return sprintf(buf, "red: %d, green: %d, blue: %d\n", 210 + colors->red, colors->green, colors->blue); 211 + 212 + } 213 + 214 + static ssize_t zone_store(struct device *dev, struct device_attribute *attr, 215 + const char *buf, size_t count, u8 location) 216 + { 217 + struct alienfx_priv *priv = dev_get_drvdata(dev); 218 + struct color_platform *colors = &priv->colors[location]; 219 + struct alienfx_platdata *pdata = dev_get_platdata(dev); 220 + int ret; 221 + 222 + ret = parse_rgb(buf, colors); 223 + if (ret) 224 + return ret; 225 + 226 + ret = pdata->ops.upd_led(priv, pdata->wdev, location); 227 + 228 + return ret ? ret : count; 229 + } 230 + 231 + static ssize_t zone00_show(struct device *dev, struct device_attribute *attr, 232 + char *buf) 233 + { 234 + return zone_show(dev, attr, buf, 0); 235 + } 236 + 237 + static ssize_t zone00_store(struct device *dev, struct device_attribute *attr, 238 + const char *buf, size_t count) 239 + { 240 + return zone_store(dev, attr, buf, count, 0); 241 + } 242 + 243 + static DEVICE_ATTR_RW(zone00); 244 + 245 + static ssize_t zone01_show(struct device *dev, struct device_attribute *attr, 246 + char *buf) 247 + { 248 + return zone_show(dev, attr, buf, 1); 249 + } 250 + 251 + static ssize_t zone01_store(struct device *dev, struct device_attribute *attr, 252 + const char *buf, size_t count) 253 + { 254 + return zone_store(dev, attr, buf, count, 1); 255 + } 256 + 257 + static DEVICE_ATTR_RW(zone01); 258 + 259 + static ssize_t zone02_show(struct device *dev, struct device_attribute *attr, 260 + char *buf) 261 + { 262 + return zone_show(dev, attr, buf, 2); 263 + } 264 + 265 + static ssize_t zone02_store(struct device *dev, struct device_attribute *attr, 266 + const char *buf, size_t count) 267 + { 268 + return zone_store(dev, attr, buf, count, 2); 269 + } 270 + 271 + static DEVICE_ATTR_RW(zone02); 272 + 273 + static ssize_t zone03_show(struct device *dev, struct device_attribute *attr, 274 + char *buf) 275 + { 276 + return zone_show(dev, attr, buf, 3); 277 + } 278 + 279 + static ssize_t zone03_store(struct device *dev, struct device_attribute *attr, 280 + const char *buf, size_t count) 281 + { 282 + return zone_store(dev, attr, buf, count, 3); 283 + } 284 + 285 + static DEVICE_ATTR_RW(zone03); 286 + 287 + /* 288 + * Lighting control state device attribute (Global) 289 + */ 290 + static ssize_t lighting_control_state_show(struct device *dev, 291 + struct device_attribute *attr, 292 + char *buf) 293 + { 294 + struct alienfx_priv *priv = dev_get_drvdata(dev); 295 + 296 + if (priv->lighting_control_state == LEGACY_BOOTING) 297 + return sysfs_emit(buf, "[booting] running suspend\n"); 298 + else if (priv->lighting_control_state == LEGACY_SUSPEND) 299 + return sysfs_emit(buf, "booting running [suspend]\n"); 300 + 301 + return sysfs_emit(buf, "booting [running] suspend\n"); 302 + } 303 + 304 + static ssize_t lighting_control_state_store(struct device *dev, 305 + struct device_attribute *attr, 306 + const char *buf, size_t count) 307 + { 308 + struct alienfx_priv *priv = dev_get_drvdata(dev); 309 + u8 val; 310 + 311 + if (strcmp(buf, "booting\n") == 0) 312 + val = LEGACY_BOOTING; 313 + else if (strcmp(buf, "suspend\n") == 0) 314 + val = LEGACY_SUSPEND; 315 + else if (alienware_interface == LEGACY) 316 + val = LEGACY_RUNNING; 317 + else 318 + val = WMAX_RUNNING; 319 + 320 + priv->lighting_control_state = val; 321 + pr_debug("alienware-wmi: updated control state to %d\n", 322 + priv->lighting_control_state); 323 + 324 + return count; 325 + } 326 + 327 + static DEVICE_ATTR_RW(lighting_control_state); 328 + 329 + static umode_t zone_attr_visible(struct kobject *kobj, 330 + struct attribute *attr, int n) 331 + { 332 + if (n < alienfx->num_zones + 1) 333 + return attr->mode; 334 + 335 + return 0; 336 + } 337 + 338 + static bool zone_group_visible(struct kobject *kobj) 339 + { 340 + return alienfx->num_zones > 0; 341 + } 342 + DEFINE_SYSFS_GROUP_VISIBLE(zone); 343 + 344 + static struct attribute *zone_attrs[] = { 345 + &dev_attr_lighting_control_state.attr, 346 + &dev_attr_zone00.attr, 347 + &dev_attr_zone01.attr, 348 + &dev_attr_zone02.attr, 349 + &dev_attr_zone03.attr, 350 + NULL 351 + }; 352 + 353 + static struct attribute_group zone_attribute_group = { 354 + .name = "rgb_zones", 355 + .is_visible = SYSFS_GROUP_VISIBLE(zone), 356 + .attrs = zone_attrs, 357 + }; 358 + 359 + /* 360 + * LED Brightness (Global) 361 + */ 362 + static void global_led_set(struct led_classdev *led_cdev, 363 + enum led_brightness brightness) 364 + { 365 + struct alienfx_priv *priv = container_of(led_cdev, struct alienfx_priv, 366 + global_led); 367 + struct alienfx_platdata *pdata = dev_get_platdata(&priv->pdev->dev); 368 + int ret; 369 + 370 + priv->global_brightness = brightness; 371 + 372 + ret = pdata->ops.upd_brightness(priv, pdata->wdev, brightness); 373 + if (ret) 374 + pr_err("LED brightness update failed\n"); 375 + } 376 + 377 + static enum led_brightness global_led_get(struct led_classdev *led_cdev) 378 + { 379 + struct alienfx_priv *priv = container_of(led_cdev, struct alienfx_priv, 380 + global_led); 381 + 382 + return priv->global_brightness; 383 + } 384 + 385 + /* 386 + * Platform Driver 387 + */ 388 + static int alienfx_probe(struct platform_device *pdev) 389 + { 390 + struct alienfx_priv *priv; 391 + 392 + priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL); 393 + if (!priv) 394 + return -ENOMEM; 395 + 396 + if (alienware_interface == WMAX) 397 + priv->lighting_control_state = WMAX_RUNNING; 398 + else 399 + priv->lighting_control_state = LEGACY_RUNNING; 400 + 401 + priv->pdev = pdev; 402 + priv->global_led.name = "alienware::global_brightness"; 403 + priv->global_led.brightness_set = global_led_set; 404 + priv->global_led.brightness_get = global_led_get; 405 + priv->global_led.max_brightness = 0x0F; 406 + priv->global_brightness = priv->global_led.max_brightness; 407 + platform_set_drvdata(pdev, priv); 408 + 409 + return devm_led_classdev_register(&pdev->dev, &priv->global_led); 410 + } 411 + 412 + static const struct attribute_group *alienfx_groups[] = { 413 + &zone_attribute_group, 414 + WMAX_DEV_GROUPS 415 + NULL 416 + }; 417 + 418 + static struct platform_driver platform_driver = { 419 + .driver = { 420 + .name = "alienware-wmi", 421 + .dev_groups = alienfx_groups, 422 + }, 423 + .probe = alienfx_probe, 424 + }; 425 + 426 + static void alienware_alienfx_remove(void *data) 427 + { 428 + struct platform_device *pdev = data; 429 + 430 + platform_device_unregister(pdev); 431 + } 432 + 433 + int alienware_alienfx_setup(struct alienfx_platdata *pdata) 434 + { 435 + struct device *dev = &pdata->wdev->dev; 436 + struct platform_device *pdev; 437 + int ret; 438 + 439 + pdev = platform_device_register_data(NULL, "alienware-wmi", 440 + PLATFORM_DEVID_NONE, pdata, 441 + sizeof(*pdata)); 442 + if (IS_ERR(pdev)) 443 + return PTR_ERR(pdev); 444 + 445 + dev_set_drvdata(dev, pdev); 446 + ret = devm_add_action_or_reset(dev, alienware_alienfx_remove, pdev); 447 + if (ret) 448 + return ret; 449 + 450 + return 0; 451 + } 452 + 453 + static int __init alienware_wmi_init(void) 454 + { 455 + int ret; 456 + 457 + dmi_check_system(alienware_quirks); 458 + if (!alienfx) 459 + alienfx = &quirk_unknown; 460 + 461 + ret = platform_driver_register(&platform_driver); 462 + if (ret < 0) 463 + return ret; 464 + 465 + if (wmi_has_guid(WMAX_CONTROL_GUID)) { 466 + alienware_interface = WMAX; 467 + ret = alienware_wmax_wmi_init(); 468 + } else { 469 + alienware_interface = LEGACY; 470 + ret = alienware_legacy_wmi_init(); 471 + } 472 + 473 + if (ret < 0) 474 + platform_driver_unregister(&platform_driver); 475 + 476 + return ret; 477 + } 478 + 479 + module_init(alienware_wmi_init); 480 + 481 + static void __exit alienware_wmi_exit(void) 482 + { 483 + if (alienware_interface == WMAX) 484 + alienware_wmax_wmi_exit(); 485 + else 486 + alienware_legacy_wmi_exit(); 487 + 488 + platform_driver_unregister(&platform_driver); 489 + } 490 + 491 + module_exit(alienware_wmi_exit);
+95
drivers/platform/x86/dell/alienware-wmi-legacy.c
··· 1 + // SPDX-License-Identifier: GPL-2.0-or-later 2 + /* 3 + * Alienware LEGACY WMI device driver 4 + * 5 + * Copyright (C) 2025 Kurt Borja <kuurtb@gmail.com> 6 + */ 7 + 8 + #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt 9 + 10 + #include <linux/wmi.h> 11 + #include "alienware-wmi.h" 12 + 13 + struct legacy_led_args { 14 + struct color_platform colors; 15 + u8 brightness; 16 + u8 state; 17 + } __packed; 18 + 19 + 20 + /* 21 + * Legacy WMI driver 22 + */ 23 + static int legacy_wmi_update_led(struct alienfx_priv *priv, 24 + struct wmi_device *wdev, u8 location) 25 + { 26 + struct legacy_led_args legacy_args = { 27 + .colors = priv->colors[location], 28 + .brightness = priv->global_brightness, 29 + .state = 0, 30 + }; 31 + struct acpi_buffer input; 32 + acpi_status status; 33 + 34 + if (legacy_args.state != LEGACY_RUNNING) { 35 + legacy_args.state = priv->lighting_control_state; 36 + 37 + input.length = sizeof(legacy_args); 38 + input.pointer = &legacy_args; 39 + 40 + status = wmi_evaluate_method(LEGACY_POWER_CONTROL_GUID, 0, 41 + location + 1, &input, NULL); 42 + if (ACPI_FAILURE(status)) 43 + return -EIO; 44 + 45 + return 0; 46 + } 47 + 48 + return alienware_wmi_command(wdev, location + 1, &legacy_args, 49 + sizeof(legacy_args), NULL); 50 + } 51 + 52 + static int legacy_wmi_update_brightness(struct alienfx_priv *priv, 53 + struct wmi_device *wdev, u8 brightness) 54 + { 55 + return legacy_wmi_update_led(priv, wdev, 0); 56 + } 57 + 58 + static int legacy_wmi_probe(struct wmi_device *wdev, const void *context) 59 + { 60 + struct alienfx_platdata pdata = { 61 + .wdev = wdev, 62 + .ops = { 63 + .upd_led = legacy_wmi_update_led, 64 + .upd_brightness = legacy_wmi_update_brightness, 65 + }, 66 + }; 67 + 68 + return alienware_alienfx_setup(&pdata); 69 + } 70 + 71 + static const struct wmi_device_id alienware_legacy_device_id_table[] = { 72 + { LEGACY_CONTROL_GUID, NULL }, 73 + { }, 74 + }; 75 + MODULE_DEVICE_TABLE(wmi, alienware_legacy_device_id_table); 76 + 77 + static struct wmi_driver alienware_legacy_wmi_driver = { 78 + .driver = { 79 + .name = "alienware-wmi-alienfx", 80 + .probe_type = PROBE_PREFER_ASYNCHRONOUS, 81 + }, 82 + .id_table = alienware_legacy_device_id_table, 83 + .probe = legacy_wmi_probe, 84 + .no_singleton = true, 85 + }; 86 + 87 + int __init alienware_legacy_wmi_init(void) 88 + { 89 + return wmi_driver_register(&alienware_legacy_wmi_driver); 90 + } 91 + 92 + void __exit alienware_legacy_wmi_exit(void) 93 + { 94 + wmi_driver_unregister(&alienware_legacy_wmi_driver); 95 + }
+768
drivers/platform/x86/dell/alienware-wmi-wmax.c
··· 1 + // SPDX-License-Identifier: GPL-2.0-or-later 2 + /* 3 + * Alienware WMAX WMI device driver 4 + * 5 + * Copyright (C) 2014 Dell Inc <Dell.Client.Kernel@dell.com> 6 + * Copyright (C) 2025 Kurt Borja <kuurtb@gmail.com> 7 + */ 8 + 9 + #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt 10 + 11 + #include <linux/bitfield.h> 12 + #include <linux/bits.h> 13 + #include <linux/dmi.h> 14 + #include <linux/moduleparam.h> 15 + #include <linux/platform_profile.h> 16 + #include <linux/wmi.h> 17 + #include "alienware-wmi.h" 18 + 19 + #define WMAX_METHOD_HDMI_SOURCE 0x1 20 + #define WMAX_METHOD_HDMI_STATUS 0x2 21 + #define WMAX_METHOD_HDMI_CABLE 0x5 22 + #define WMAX_METHOD_AMPLIFIER_CABLE 0x6 23 + #define WMAX_METHOD_DEEP_SLEEP_CONTROL 0x0B 24 + #define WMAX_METHOD_DEEP_SLEEP_STATUS 0x0C 25 + #define WMAX_METHOD_BRIGHTNESS 0x3 26 + #define WMAX_METHOD_ZONE_CONTROL 0x4 27 + #define WMAX_METHOD_THERMAL_INFORMATION 0x14 28 + #define WMAX_METHOD_THERMAL_CONTROL 0x15 29 + #define WMAX_METHOD_GAME_SHIFT_STATUS 0x25 30 + 31 + #define WMAX_THERMAL_MODE_GMODE 0xAB 32 + 33 + #define WMAX_FAILURE_CODE 0xFFFFFFFF 34 + #define WMAX_THERMAL_TABLE_MASK GENMASK(7, 4) 35 + #define WMAX_THERMAL_MODE_MASK GENMASK(3, 0) 36 + #define WMAX_SENSOR_ID_MASK BIT(8) 37 + 38 + static bool force_platform_profile; 39 + module_param_unsafe(force_platform_profile, bool, 0); 40 + MODULE_PARM_DESC(force_platform_profile, "Forces auto-detecting thermal profiles without checking if WMI thermal backend is available"); 41 + 42 + static bool force_gmode; 43 + module_param_unsafe(force_gmode, bool, 0); 44 + MODULE_PARM_DESC(force_gmode, "Forces G-Mode when performance profile is selected"); 45 + 46 + struct awcc_quirks { 47 + bool pprof; 48 + bool gmode; 49 + }; 50 + 51 + static struct awcc_quirks g_series_quirks = { 52 + .pprof = true, 53 + .gmode = true, 54 + }; 55 + 56 + static struct awcc_quirks generic_quirks = { 57 + .pprof = true, 58 + .gmode = false, 59 + }; 60 + 61 + static struct awcc_quirks empty_quirks; 62 + 63 + static const struct dmi_system_id awcc_dmi_table[] __initconst = { 64 + { 65 + .ident = "Alienware m16 R1 AMD", 66 + .matches = { 67 + DMI_MATCH(DMI_SYS_VENDOR, "Alienware"), 68 + DMI_MATCH(DMI_PRODUCT_NAME, "Alienware m16 R1 AMD"), 69 + }, 70 + .driver_data = &generic_quirks, 71 + }, 72 + { 73 + .ident = "Alienware m17 R5", 74 + .matches = { 75 + DMI_MATCH(DMI_SYS_VENDOR, "Alienware"), 76 + DMI_MATCH(DMI_PRODUCT_NAME, "Alienware m17 R5 AMD"), 77 + }, 78 + .driver_data = &generic_quirks, 79 + }, 80 + { 81 + .ident = "Alienware m18 R2", 82 + .matches = { 83 + DMI_MATCH(DMI_SYS_VENDOR, "Alienware"), 84 + DMI_MATCH(DMI_PRODUCT_NAME, "Alienware m18 R2"), 85 + }, 86 + .driver_data = &generic_quirks, 87 + }, 88 + { 89 + .ident = "Alienware x15 R1", 90 + .matches = { 91 + DMI_MATCH(DMI_SYS_VENDOR, "Alienware"), 92 + DMI_MATCH(DMI_PRODUCT_NAME, "Alienware x15 R1"), 93 + }, 94 + .driver_data = &generic_quirks, 95 + }, 96 + { 97 + .ident = "Alienware x17 R2", 98 + .matches = { 99 + DMI_MATCH(DMI_SYS_VENDOR, "Alienware"), 100 + DMI_MATCH(DMI_PRODUCT_NAME, "Alienware x17 R2"), 101 + }, 102 + .driver_data = &generic_quirks, 103 + }, 104 + { 105 + .ident = "Dell Inc. G15 5510", 106 + .matches = { 107 + DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."), 108 + DMI_MATCH(DMI_PRODUCT_NAME, "Dell G15 5510"), 109 + }, 110 + .driver_data = &g_series_quirks, 111 + }, 112 + { 113 + .ident = "Dell Inc. G15 5511", 114 + .matches = { 115 + DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."), 116 + DMI_MATCH(DMI_PRODUCT_NAME, "Dell G15 5511"), 117 + }, 118 + .driver_data = &g_series_quirks, 119 + }, 120 + { 121 + .ident = "Dell Inc. G15 5515", 122 + .matches = { 123 + DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."), 124 + DMI_MATCH(DMI_PRODUCT_NAME, "Dell G15 5515"), 125 + }, 126 + .driver_data = &g_series_quirks, 127 + }, 128 + { 129 + .ident = "Dell Inc. G3 3500", 130 + .matches = { 131 + DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."), 132 + DMI_MATCH(DMI_PRODUCT_NAME, "G3 3500"), 133 + }, 134 + .driver_data = &g_series_quirks, 135 + }, 136 + { 137 + .ident = "Dell Inc. G3 3590", 138 + .matches = { 139 + DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."), 140 + DMI_MATCH(DMI_PRODUCT_NAME, "G3 3590"), 141 + }, 142 + .driver_data = &g_series_quirks, 143 + }, 144 + { 145 + .ident = "Dell Inc. G5 5500", 146 + .matches = { 147 + DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."), 148 + DMI_MATCH(DMI_PRODUCT_NAME, "G5 5500"), 149 + }, 150 + .driver_data = &g_series_quirks, 151 + }, 152 + }; 153 + 154 + enum WMAX_THERMAL_INFORMATION_OPERATIONS { 155 + WMAX_OPERATION_SYS_DESCRIPTION = 0x02, 156 + WMAX_OPERATION_LIST_IDS = 0x03, 157 + WMAX_OPERATION_CURRENT_PROFILE = 0x0B, 158 + }; 159 + 160 + enum WMAX_THERMAL_CONTROL_OPERATIONS { 161 + WMAX_OPERATION_ACTIVATE_PROFILE = 0x01, 162 + }; 163 + 164 + enum WMAX_GAME_SHIFT_STATUS_OPERATIONS { 165 + WMAX_OPERATION_TOGGLE_GAME_SHIFT = 0x01, 166 + WMAX_OPERATION_GET_GAME_SHIFT_STATUS = 0x02, 167 + }; 168 + 169 + enum WMAX_THERMAL_TABLES { 170 + WMAX_THERMAL_TABLE_BASIC = 0x90, 171 + WMAX_THERMAL_TABLE_USTT = 0xA0, 172 + }; 173 + 174 + enum wmax_thermal_mode { 175 + THERMAL_MODE_USTT_BALANCED, 176 + THERMAL_MODE_USTT_BALANCED_PERFORMANCE, 177 + THERMAL_MODE_USTT_COOL, 178 + THERMAL_MODE_USTT_QUIET, 179 + THERMAL_MODE_USTT_PERFORMANCE, 180 + THERMAL_MODE_USTT_LOW_POWER, 181 + THERMAL_MODE_BASIC_QUIET, 182 + THERMAL_MODE_BASIC_BALANCED, 183 + THERMAL_MODE_BASIC_BALANCED_PERFORMANCE, 184 + THERMAL_MODE_BASIC_PERFORMANCE, 185 + THERMAL_MODE_LAST, 186 + }; 187 + 188 + struct wmax_led_args { 189 + u32 led_mask; 190 + struct color_platform colors; 191 + u8 state; 192 + } __packed; 193 + 194 + struct wmax_brightness_args { 195 + u32 led_mask; 196 + u32 percentage; 197 + }; 198 + 199 + struct wmax_basic_args { 200 + u8 arg; 201 + }; 202 + 203 + struct wmax_u32_args { 204 + u8 operation; 205 + u8 arg1; 206 + u8 arg2; 207 + u8 arg3; 208 + }; 209 + 210 + struct awcc_priv { 211 + struct wmi_device *wdev; 212 + struct device *ppdev; 213 + enum wmax_thermal_mode supported_thermal_profiles[PLATFORM_PROFILE_LAST]; 214 + }; 215 + 216 + static const enum platform_profile_option wmax_mode_to_platform_profile[THERMAL_MODE_LAST] = { 217 + [THERMAL_MODE_USTT_BALANCED] = PLATFORM_PROFILE_BALANCED, 218 + [THERMAL_MODE_USTT_BALANCED_PERFORMANCE] = PLATFORM_PROFILE_BALANCED_PERFORMANCE, 219 + [THERMAL_MODE_USTT_COOL] = PLATFORM_PROFILE_COOL, 220 + [THERMAL_MODE_USTT_QUIET] = PLATFORM_PROFILE_QUIET, 221 + [THERMAL_MODE_USTT_PERFORMANCE] = PLATFORM_PROFILE_PERFORMANCE, 222 + [THERMAL_MODE_USTT_LOW_POWER] = PLATFORM_PROFILE_LOW_POWER, 223 + [THERMAL_MODE_BASIC_QUIET] = PLATFORM_PROFILE_QUIET, 224 + [THERMAL_MODE_BASIC_BALANCED] = PLATFORM_PROFILE_BALANCED, 225 + [THERMAL_MODE_BASIC_BALANCED_PERFORMANCE] = PLATFORM_PROFILE_BALANCED_PERFORMANCE, 226 + [THERMAL_MODE_BASIC_PERFORMANCE] = PLATFORM_PROFILE_PERFORMANCE, 227 + }; 228 + 229 + static struct awcc_quirks *awcc; 230 + 231 + /* 232 + * The HDMI mux sysfs node indicates the status of the HDMI input mux. 233 + * It can toggle between standard system GPU output and HDMI input. 234 + */ 235 + static ssize_t cable_show(struct device *dev, struct device_attribute *attr, 236 + char *buf) 237 + { 238 + struct alienfx_platdata *pdata = dev_get_platdata(dev); 239 + struct wmax_basic_args in_args = { 240 + .arg = 0, 241 + }; 242 + u32 out_data; 243 + int ret; 244 + 245 + ret = alienware_wmi_command(pdata->wdev, WMAX_METHOD_HDMI_CABLE, 246 + &in_args, sizeof(in_args), &out_data); 247 + if (!ret) { 248 + if (out_data == 0) 249 + return sysfs_emit(buf, "[unconnected] connected unknown\n"); 250 + else if (out_data == 1) 251 + return sysfs_emit(buf, "unconnected [connected] unknown\n"); 252 + } 253 + 254 + pr_err("alienware-wmi: unknown HDMI cable status: %d\n", ret); 255 + return sysfs_emit(buf, "unconnected connected [unknown]\n"); 256 + } 257 + 258 + static ssize_t source_show(struct device *dev, struct device_attribute *attr, 259 + char *buf) 260 + { 261 + struct alienfx_platdata *pdata = dev_get_platdata(dev); 262 + struct wmax_basic_args in_args = { 263 + .arg = 0, 264 + }; 265 + u32 out_data; 266 + int ret; 267 + 268 + ret = alienware_wmi_command(pdata->wdev, WMAX_METHOD_HDMI_STATUS, 269 + &in_args, sizeof(in_args), &out_data); 270 + if (!ret) { 271 + if (out_data == 1) 272 + return sysfs_emit(buf, "[input] gpu unknown\n"); 273 + else if (out_data == 2) 274 + return sysfs_emit(buf, "input [gpu] unknown\n"); 275 + } 276 + 277 + pr_err("alienware-wmi: unknown HDMI source status: %u\n", ret); 278 + return sysfs_emit(buf, "input gpu [unknown]\n"); 279 + } 280 + 281 + static ssize_t source_store(struct device *dev, struct device_attribute *attr, 282 + const char *buf, size_t count) 283 + { 284 + struct alienfx_platdata *pdata = dev_get_platdata(dev); 285 + struct wmax_basic_args args; 286 + int ret; 287 + 288 + if (strcmp(buf, "gpu\n") == 0) 289 + args.arg = 1; 290 + else if (strcmp(buf, "input\n") == 0) 291 + args.arg = 2; 292 + else 293 + args.arg = 3; 294 + pr_debug("alienware-wmi: setting hdmi to %d : %s", args.arg, buf); 295 + 296 + ret = alienware_wmi_command(pdata->wdev, WMAX_METHOD_HDMI_SOURCE, &args, 297 + sizeof(args), NULL); 298 + if (ret < 0) 299 + pr_err("alienware-wmi: HDMI toggle failed: results: %u\n", ret); 300 + 301 + return count; 302 + } 303 + 304 + static DEVICE_ATTR_RO(cable); 305 + static DEVICE_ATTR_RW(source); 306 + 307 + static bool hdmi_group_visible(struct kobject *kobj) 308 + { 309 + return alienware_interface == WMAX && alienfx->hdmi_mux; 310 + } 311 + DEFINE_SIMPLE_SYSFS_GROUP_VISIBLE(hdmi); 312 + 313 + static struct attribute *hdmi_attrs[] = { 314 + &dev_attr_cable.attr, 315 + &dev_attr_source.attr, 316 + NULL, 317 + }; 318 + 319 + const struct attribute_group wmax_hdmi_attribute_group = { 320 + .name = "hdmi", 321 + .is_visible = SYSFS_GROUP_VISIBLE(hdmi), 322 + .attrs = hdmi_attrs, 323 + }; 324 + 325 + /* 326 + * Alienware GFX amplifier support 327 + * - Currently supports reading cable status 328 + * - Leaving expansion room to possibly support dock/undock events later 329 + */ 330 + static ssize_t status_show(struct device *dev, struct device_attribute *attr, 331 + char *buf) 332 + { 333 + struct alienfx_platdata *pdata = dev_get_platdata(dev); 334 + struct wmax_basic_args in_args = { 335 + .arg = 0, 336 + }; 337 + u32 out_data; 338 + int ret; 339 + 340 + ret = alienware_wmi_command(pdata->wdev, WMAX_METHOD_AMPLIFIER_CABLE, 341 + &in_args, sizeof(in_args), &out_data); 342 + if (!ret) { 343 + if (out_data == 0) 344 + return sysfs_emit(buf, "[unconnected] connected unknown\n"); 345 + else if (out_data == 1) 346 + return sysfs_emit(buf, "unconnected [connected] unknown\n"); 347 + } 348 + 349 + pr_err("alienware-wmi: unknown amplifier cable status: %d\n", ret); 350 + return sysfs_emit(buf, "unconnected connected [unknown]\n"); 351 + } 352 + 353 + static DEVICE_ATTR_RO(status); 354 + 355 + static bool amplifier_group_visible(struct kobject *kobj) 356 + { 357 + return alienware_interface == WMAX && alienfx->amplifier; 358 + } 359 + DEFINE_SIMPLE_SYSFS_GROUP_VISIBLE(amplifier); 360 + 361 + static struct attribute *amplifier_attrs[] = { 362 + &dev_attr_status.attr, 363 + NULL, 364 + }; 365 + 366 + const struct attribute_group wmax_amplifier_attribute_group = { 367 + .name = "amplifier", 368 + .is_visible = SYSFS_GROUP_VISIBLE(amplifier), 369 + .attrs = amplifier_attrs, 370 + }; 371 + 372 + /* 373 + * Deep Sleep Control support 374 + * - Modifies BIOS setting for deep sleep control allowing extra wakeup events 375 + */ 376 + static ssize_t deepsleep_show(struct device *dev, struct device_attribute *attr, 377 + char *buf) 378 + { 379 + struct alienfx_platdata *pdata = dev_get_platdata(dev); 380 + struct wmax_basic_args in_args = { 381 + .arg = 0, 382 + }; 383 + u32 out_data; 384 + int ret; 385 + 386 + ret = alienware_wmi_command(pdata->wdev, WMAX_METHOD_DEEP_SLEEP_STATUS, 387 + &in_args, sizeof(in_args), &out_data); 388 + if (!ret) { 389 + if (out_data == 0) 390 + return sysfs_emit(buf, "[disabled] s5 s5_s4\n"); 391 + else if (out_data == 1) 392 + return sysfs_emit(buf, "disabled [s5] s5_s4\n"); 393 + else if (out_data == 2) 394 + return sysfs_emit(buf, "disabled s5 [s5_s4]\n"); 395 + } 396 + 397 + pr_err("alienware-wmi: unknown deep sleep status: %d\n", ret); 398 + return sysfs_emit(buf, "disabled s5 s5_s4 [unknown]\n"); 399 + } 400 + 401 + static ssize_t deepsleep_store(struct device *dev, struct device_attribute *attr, 402 + const char *buf, size_t count) 403 + { 404 + struct alienfx_platdata *pdata = dev_get_platdata(dev); 405 + struct wmax_basic_args args; 406 + int ret; 407 + 408 + if (strcmp(buf, "disabled\n") == 0) 409 + args.arg = 0; 410 + else if (strcmp(buf, "s5\n") == 0) 411 + args.arg = 1; 412 + else 413 + args.arg = 2; 414 + pr_debug("alienware-wmi: setting deep sleep to %d : %s", args.arg, buf); 415 + 416 + ret = alienware_wmi_command(pdata->wdev, WMAX_METHOD_DEEP_SLEEP_CONTROL, 417 + &args, sizeof(args), NULL); 418 + if (!ret) 419 + pr_err("alienware-wmi: deep sleep control failed: results: %u\n", ret); 420 + 421 + return count; 422 + } 423 + 424 + static DEVICE_ATTR_RW(deepsleep); 425 + 426 + static bool deepsleep_group_visible(struct kobject *kobj) 427 + { 428 + return alienware_interface == WMAX && alienfx->deepslp; 429 + } 430 + DEFINE_SIMPLE_SYSFS_GROUP_VISIBLE(deepsleep); 431 + 432 + static struct attribute *deepsleep_attrs[] = { 433 + &dev_attr_deepsleep.attr, 434 + NULL, 435 + }; 436 + 437 + const struct attribute_group wmax_deepsleep_attribute_group = { 438 + .name = "deepsleep", 439 + .is_visible = SYSFS_GROUP_VISIBLE(deepsleep), 440 + .attrs = deepsleep_attrs, 441 + }; 442 + 443 + /* 444 + * Thermal Profile control 445 + * - Provides thermal profile control through the Platform Profile API 446 + */ 447 + static bool is_wmax_thermal_code(u32 code) 448 + { 449 + if (code & WMAX_SENSOR_ID_MASK) 450 + return false; 451 + 452 + if ((code & WMAX_THERMAL_MODE_MASK) >= THERMAL_MODE_LAST) 453 + return false; 454 + 455 + if ((code & WMAX_THERMAL_TABLE_MASK) == WMAX_THERMAL_TABLE_BASIC && 456 + (code & WMAX_THERMAL_MODE_MASK) >= THERMAL_MODE_BASIC_QUIET) 457 + return true; 458 + 459 + if ((code & WMAX_THERMAL_TABLE_MASK) == WMAX_THERMAL_TABLE_USTT && 460 + (code & WMAX_THERMAL_MODE_MASK) <= THERMAL_MODE_USTT_LOW_POWER) 461 + return true; 462 + 463 + return false; 464 + } 465 + 466 + static int wmax_thermal_information(struct wmi_device *wdev, u8 operation, 467 + u8 arg, u32 *out_data) 468 + { 469 + struct wmax_u32_args in_args = { 470 + .operation = operation, 471 + .arg1 = arg, 472 + .arg2 = 0, 473 + .arg3 = 0, 474 + }; 475 + int ret; 476 + 477 + ret = alienware_wmi_command(wdev, WMAX_METHOD_THERMAL_INFORMATION, 478 + &in_args, sizeof(in_args), out_data); 479 + if (ret < 0) 480 + return ret; 481 + 482 + if (*out_data == WMAX_FAILURE_CODE) 483 + return -EBADRQC; 484 + 485 + return 0; 486 + } 487 + 488 + static int wmax_thermal_control(struct wmi_device *wdev, u8 profile) 489 + { 490 + struct wmax_u32_args in_args = { 491 + .operation = WMAX_OPERATION_ACTIVATE_PROFILE, 492 + .arg1 = profile, 493 + .arg2 = 0, 494 + .arg3 = 0, 495 + }; 496 + u32 out_data; 497 + int ret; 498 + 499 + ret = alienware_wmi_command(wdev, WMAX_METHOD_THERMAL_CONTROL, 500 + &in_args, sizeof(in_args), &out_data); 501 + if (ret) 502 + return ret; 503 + 504 + if (out_data == WMAX_FAILURE_CODE) 505 + return -EBADRQC; 506 + 507 + return 0; 508 + } 509 + 510 + static int wmax_game_shift_status(struct wmi_device *wdev, u8 operation, 511 + u32 *out_data) 512 + { 513 + struct wmax_u32_args in_args = { 514 + .operation = operation, 515 + .arg1 = 0, 516 + .arg2 = 0, 517 + .arg3 = 0, 518 + }; 519 + int ret; 520 + 521 + ret = alienware_wmi_command(wdev, WMAX_METHOD_GAME_SHIFT_STATUS, 522 + &in_args, sizeof(in_args), out_data); 523 + if (ret < 0) 524 + return ret; 525 + 526 + if (*out_data == WMAX_FAILURE_CODE) 527 + return -EOPNOTSUPP; 528 + 529 + return 0; 530 + } 531 + 532 + static int thermal_profile_get(struct device *dev, 533 + enum platform_profile_option *profile) 534 + { 535 + struct awcc_priv *priv = dev_get_drvdata(dev); 536 + u32 out_data; 537 + int ret; 538 + 539 + ret = wmax_thermal_information(priv->wdev, WMAX_OPERATION_CURRENT_PROFILE, 540 + 0, &out_data); 541 + 542 + if (ret < 0) 543 + return ret; 544 + 545 + if (out_data == WMAX_THERMAL_MODE_GMODE) { 546 + *profile = PLATFORM_PROFILE_PERFORMANCE; 547 + return 0; 548 + } 549 + 550 + if (!is_wmax_thermal_code(out_data)) 551 + return -ENODATA; 552 + 553 + out_data &= WMAX_THERMAL_MODE_MASK; 554 + *profile = wmax_mode_to_platform_profile[out_data]; 555 + 556 + return 0; 557 + } 558 + 559 + static int thermal_profile_set(struct device *dev, 560 + enum platform_profile_option profile) 561 + { 562 + struct awcc_priv *priv = dev_get_drvdata(dev); 563 + 564 + if (awcc->gmode) { 565 + u32 gmode_status; 566 + int ret; 567 + 568 + ret = wmax_game_shift_status(priv->wdev, 569 + WMAX_OPERATION_GET_GAME_SHIFT_STATUS, 570 + &gmode_status); 571 + 572 + if (ret < 0) 573 + return ret; 574 + 575 + if ((profile == PLATFORM_PROFILE_PERFORMANCE && !gmode_status) || 576 + (profile != PLATFORM_PROFILE_PERFORMANCE && gmode_status)) { 577 + ret = wmax_game_shift_status(priv->wdev, 578 + WMAX_OPERATION_TOGGLE_GAME_SHIFT, 579 + &gmode_status); 580 + 581 + if (ret < 0) 582 + return ret; 583 + } 584 + } 585 + 586 + return wmax_thermal_control(priv->wdev, 587 + priv->supported_thermal_profiles[profile]); 588 + } 589 + 590 + static int thermal_profile_probe(void *drvdata, unsigned long *choices) 591 + { 592 + enum platform_profile_option profile; 593 + struct awcc_priv *priv = drvdata; 594 + enum wmax_thermal_mode mode; 595 + u8 sys_desc[4]; 596 + u32 first_mode; 597 + u32 out_data; 598 + int ret; 599 + 600 + ret = wmax_thermal_information(priv->wdev, WMAX_OPERATION_SYS_DESCRIPTION, 601 + 0, (u32 *) &sys_desc); 602 + if (ret < 0) 603 + return ret; 604 + 605 + first_mode = sys_desc[0] + sys_desc[1]; 606 + 607 + for (u32 i = 0; i < sys_desc[3]; i++) { 608 + ret = wmax_thermal_information(priv->wdev, WMAX_OPERATION_LIST_IDS, 609 + i + first_mode, &out_data); 610 + 611 + if (ret == -EIO) 612 + return ret; 613 + 614 + if (ret == -EBADRQC) 615 + break; 616 + 617 + if (!is_wmax_thermal_code(out_data)) 618 + continue; 619 + 620 + mode = out_data & WMAX_THERMAL_MODE_MASK; 621 + profile = wmax_mode_to_platform_profile[mode]; 622 + priv->supported_thermal_profiles[profile] = out_data; 623 + 624 + set_bit(profile, choices); 625 + } 626 + 627 + if (bitmap_empty(choices, PLATFORM_PROFILE_LAST)) 628 + return -ENODEV; 629 + 630 + if (awcc->gmode) { 631 + priv->supported_thermal_profiles[PLATFORM_PROFILE_PERFORMANCE] = 632 + WMAX_THERMAL_MODE_GMODE; 633 + 634 + set_bit(PLATFORM_PROFILE_PERFORMANCE, choices); 635 + } 636 + 637 + return 0; 638 + } 639 + 640 + static const struct platform_profile_ops awcc_platform_profile_ops = { 641 + .probe = thermal_profile_probe, 642 + .profile_get = thermal_profile_get, 643 + .profile_set = thermal_profile_set, 644 + }; 645 + 646 + static int awcc_platform_profile_init(struct wmi_device *wdev) 647 + { 648 + struct awcc_priv *priv = dev_get_drvdata(&wdev->dev); 649 + 650 + priv->ppdev = devm_platform_profile_register(&wdev->dev, "alienware-wmi", 651 + priv, &awcc_platform_profile_ops); 652 + 653 + return PTR_ERR_OR_ZERO(priv->ppdev); 654 + } 655 + 656 + static int alienware_awcc_setup(struct wmi_device *wdev) 657 + { 658 + struct awcc_priv *priv; 659 + int ret; 660 + 661 + priv = devm_kzalloc(&wdev->dev, sizeof(*priv), GFP_KERNEL); 662 + if (!priv) 663 + return -ENOMEM; 664 + 665 + priv->wdev = wdev; 666 + dev_set_drvdata(&wdev->dev, priv); 667 + 668 + if (awcc->pprof) { 669 + ret = awcc_platform_profile_init(wdev); 670 + if (ret) 671 + return ret; 672 + } 673 + 674 + return 0; 675 + } 676 + 677 + /* 678 + * WMAX WMI driver 679 + */ 680 + static int wmax_wmi_update_led(struct alienfx_priv *priv, 681 + struct wmi_device *wdev, u8 location) 682 + { 683 + struct wmax_led_args in_args = { 684 + .led_mask = 1 << location, 685 + .colors = priv->colors[location], 686 + .state = priv->lighting_control_state, 687 + }; 688 + 689 + return alienware_wmi_command(wdev, WMAX_METHOD_ZONE_CONTROL, &in_args, 690 + sizeof(in_args), NULL); 691 + } 692 + 693 + static int wmax_wmi_update_brightness(struct alienfx_priv *priv, 694 + struct wmi_device *wdev, u8 brightness) 695 + { 696 + struct wmax_brightness_args in_args = { 697 + .led_mask = 0xFF, 698 + .percentage = brightness, 699 + }; 700 + 701 + return alienware_wmi_command(wdev, WMAX_METHOD_BRIGHTNESS, &in_args, 702 + sizeof(in_args), NULL); 703 + } 704 + 705 + static int wmax_wmi_probe(struct wmi_device *wdev, const void *context) 706 + { 707 + struct alienfx_platdata pdata = { 708 + .wdev = wdev, 709 + .ops = { 710 + .upd_led = wmax_wmi_update_led, 711 + .upd_brightness = wmax_wmi_update_brightness, 712 + }, 713 + }; 714 + int ret; 715 + 716 + if (awcc) 717 + ret = alienware_awcc_setup(wdev); 718 + else 719 + ret = alienware_alienfx_setup(&pdata); 720 + 721 + return ret; 722 + } 723 + 724 + static const struct wmi_device_id alienware_wmax_device_id_table[] = { 725 + { WMAX_CONTROL_GUID, NULL }, 726 + { }, 727 + }; 728 + MODULE_DEVICE_TABLE(wmi, alienware_wmax_device_id_table); 729 + 730 + static struct wmi_driver alienware_wmax_wmi_driver = { 731 + .driver = { 732 + .name = "alienware-wmi-wmax", 733 + .probe_type = PROBE_PREFER_ASYNCHRONOUS, 734 + }, 735 + .id_table = alienware_wmax_device_id_table, 736 + .probe = wmax_wmi_probe, 737 + .no_singleton = true, 738 + }; 739 + 740 + int __init alienware_wmax_wmi_init(void) 741 + { 742 + const struct dmi_system_id *id; 743 + 744 + id = dmi_first_match(awcc_dmi_table); 745 + if (id) 746 + awcc = id->driver_data; 747 + 748 + if (force_platform_profile) { 749 + if (!awcc) 750 + awcc = &empty_quirks; 751 + 752 + awcc->pprof = true; 753 + } 754 + 755 + if (force_gmode) { 756 + if (awcc) 757 + awcc->gmode = true; 758 + else 759 + pr_warn("force_gmode requires platform profile support\n"); 760 + } 761 + 762 + return wmi_driver_register(&alienware_wmax_wmi_driver); 763 + } 764 + 765 + void __exit alienware_wmax_wmi_exit(void) 766 + { 767 + wmi_driver_unregister(&alienware_wmax_wmi_driver); 768 + }
-1249
drivers/platform/x86/dell/alienware-wmi.c
··· 1 - // SPDX-License-Identifier: GPL-2.0-or-later 2 - /* 3 - * Alienware AlienFX control 4 - * 5 - * Copyright (C) 2014 Dell Inc <Dell.Client.Kernel@dell.com> 6 - */ 7 - 8 - #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt 9 - 10 - #include <linux/acpi.h> 11 - #include <linux/bitfield.h> 12 - #include <linux/bits.h> 13 - #include <linux/module.h> 14 - #include <linux/platform_device.h> 15 - #include <linux/platform_profile.h> 16 - #include <linux/dmi.h> 17 - #include <linux/leds.h> 18 - 19 - #define LEGACY_CONTROL_GUID "A90597CE-A997-11DA-B012-B622A1EF5492" 20 - #define LEGACY_POWER_CONTROL_GUID "A80593CE-A997-11DA-B012-B622A1EF5492" 21 - #define WMAX_CONTROL_GUID "A70591CE-A997-11DA-B012-B622A1EF5492" 22 - 23 - #define WMAX_METHOD_HDMI_SOURCE 0x1 24 - #define WMAX_METHOD_HDMI_STATUS 0x2 25 - #define WMAX_METHOD_BRIGHTNESS 0x3 26 - #define WMAX_METHOD_ZONE_CONTROL 0x4 27 - #define WMAX_METHOD_HDMI_CABLE 0x5 28 - #define WMAX_METHOD_AMPLIFIER_CABLE 0x6 29 - #define WMAX_METHOD_DEEP_SLEEP_CONTROL 0x0B 30 - #define WMAX_METHOD_DEEP_SLEEP_STATUS 0x0C 31 - #define WMAX_METHOD_THERMAL_INFORMATION 0x14 32 - #define WMAX_METHOD_THERMAL_CONTROL 0x15 33 - #define WMAX_METHOD_GAME_SHIFT_STATUS 0x25 34 - 35 - #define WMAX_THERMAL_MODE_GMODE 0xAB 36 - 37 - #define WMAX_FAILURE_CODE 0xFFFFFFFF 38 - 39 - MODULE_AUTHOR("Mario Limonciello <mario.limonciello@outlook.com>"); 40 - MODULE_DESCRIPTION("Alienware special feature control"); 41 - MODULE_LICENSE("GPL"); 42 - MODULE_ALIAS("wmi:" LEGACY_CONTROL_GUID); 43 - MODULE_ALIAS("wmi:" WMAX_CONTROL_GUID); 44 - 45 - static bool force_platform_profile; 46 - module_param_unsafe(force_platform_profile, bool, 0); 47 - MODULE_PARM_DESC(force_platform_profile, "Forces auto-detecting thermal profiles without checking if WMI thermal backend is available"); 48 - 49 - static bool force_gmode; 50 - module_param_unsafe(force_gmode, bool, 0); 51 - MODULE_PARM_DESC(force_gmode, "Forces G-Mode when performance profile is selected"); 52 - 53 - enum INTERFACE_FLAGS { 54 - LEGACY, 55 - WMAX, 56 - }; 57 - 58 - enum LEGACY_CONTROL_STATES { 59 - LEGACY_RUNNING = 1, 60 - LEGACY_BOOTING = 0, 61 - LEGACY_SUSPEND = 3, 62 - }; 63 - 64 - enum WMAX_CONTROL_STATES { 65 - WMAX_RUNNING = 0xFF, 66 - WMAX_BOOTING = 0, 67 - WMAX_SUSPEND = 3, 68 - }; 69 - 70 - enum WMAX_THERMAL_INFORMATION_OPERATIONS { 71 - WMAX_OPERATION_SYS_DESCRIPTION = 0x02, 72 - WMAX_OPERATION_LIST_IDS = 0x03, 73 - WMAX_OPERATION_CURRENT_PROFILE = 0x0B, 74 - }; 75 - 76 - enum WMAX_THERMAL_CONTROL_OPERATIONS { 77 - WMAX_OPERATION_ACTIVATE_PROFILE = 0x01, 78 - }; 79 - 80 - enum WMAX_GAME_SHIFT_STATUS_OPERATIONS { 81 - WMAX_OPERATION_TOGGLE_GAME_SHIFT = 0x01, 82 - WMAX_OPERATION_GET_GAME_SHIFT_STATUS = 0x02, 83 - }; 84 - 85 - enum WMAX_THERMAL_TABLES { 86 - WMAX_THERMAL_TABLE_BASIC = 0x90, 87 - WMAX_THERMAL_TABLE_USTT = 0xA0, 88 - }; 89 - 90 - enum wmax_thermal_mode { 91 - THERMAL_MODE_USTT_BALANCED, 92 - THERMAL_MODE_USTT_BALANCED_PERFORMANCE, 93 - THERMAL_MODE_USTT_COOL, 94 - THERMAL_MODE_USTT_QUIET, 95 - THERMAL_MODE_USTT_PERFORMANCE, 96 - THERMAL_MODE_USTT_LOW_POWER, 97 - THERMAL_MODE_BASIC_QUIET, 98 - THERMAL_MODE_BASIC_BALANCED, 99 - THERMAL_MODE_BASIC_BALANCED_PERFORMANCE, 100 - THERMAL_MODE_BASIC_PERFORMANCE, 101 - THERMAL_MODE_LAST, 102 - }; 103 - 104 - static const enum platform_profile_option wmax_mode_to_platform_profile[THERMAL_MODE_LAST] = { 105 - [THERMAL_MODE_USTT_BALANCED] = PLATFORM_PROFILE_BALANCED, 106 - [THERMAL_MODE_USTT_BALANCED_PERFORMANCE] = PLATFORM_PROFILE_BALANCED_PERFORMANCE, 107 - [THERMAL_MODE_USTT_COOL] = PLATFORM_PROFILE_COOL, 108 - [THERMAL_MODE_USTT_QUIET] = PLATFORM_PROFILE_QUIET, 109 - [THERMAL_MODE_USTT_PERFORMANCE] = PLATFORM_PROFILE_PERFORMANCE, 110 - [THERMAL_MODE_USTT_LOW_POWER] = PLATFORM_PROFILE_LOW_POWER, 111 - [THERMAL_MODE_BASIC_QUIET] = PLATFORM_PROFILE_QUIET, 112 - [THERMAL_MODE_BASIC_BALANCED] = PLATFORM_PROFILE_BALANCED, 113 - [THERMAL_MODE_BASIC_BALANCED_PERFORMANCE] = PLATFORM_PROFILE_BALANCED_PERFORMANCE, 114 - [THERMAL_MODE_BASIC_PERFORMANCE] = PLATFORM_PROFILE_PERFORMANCE, 115 - }; 116 - 117 - struct quirk_entry { 118 - u8 num_zones; 119 - u8 hdmi_mux; 120 - u8 amplifier; 121 - u8 deepslp; 122 - bool thermal; 123 - bool gmode; 124 - }; 125 - 126 - static struct quirk_entry *quirks; 127 - 128 - 129 - static struct quirk_entry quirk_inspiron5675 = { 130 - .num_zones = 2, 131 - .hdmi_mux = 0, 132 - .amplifier = 0, 133 - .deepslp = 0, 134 - .thermal = false, 135 - .gmode = false, 136 - }; 137 - 138 - static struct quirk_entry quirk_unknown = { 139 - .num_zones = 2, 140 - .hdmi_mux = 0, 141 - .amplifier = 0, 142 - .deepslp = 0, 143 - .thermal = false, 144 - .gmode = false, 145 - }; 146 - 147 - static struct quirk_entry quirk_x51_r1_r2 = { 148 - .num_zones = 3, 149 - .hdmi_mux = 0, 150 - .amplifier = 0, 151 - .deepslp = 0, 152 - .thermal = false, 153 - .gmode = false, 154 - }; 155 - 156 - static struct quirk_entry quirk_x51_r3 = { 157 - .num_zones = 4, 158 - .hdmi_mux = 0, 159 - .amplifier = 1, 160 - .deepslp = 0, 161 - .thermal = false, 162 - .gmode = false, 163 - }; 164 - 165 - static struct quirk_entry quirk_asm100 = { 166 - .num_zones = 2, 167 - .hdmi_mux = 1, 168 - .amplifier = 0, 169 - .deepslp = 0, 170 - .thermal = false, 171 - .gmode = false, 172 - }; 173 - 174 - static struct quirk_entry quirk_asm200 = { 175 - .num_zones = 2, 176 - .hdmi_mux = 1, 177 - .amplifier = 0, 178 - .deepslp = 1, 179 - .thermal = false, 180 - .gmode = false, 181 - }; 182 - 183 - static struct quirk_entry quirk_asm201 = { 184 - .num_zones = 2, 185 - .hdmi_mux = 1, 186 - .amplifier = 1, 187 - .deepslp = 1, 188 - .thermal = false, 189 - .gmode = false, 190 - }; 191 - 192 - static struct quirk_entry quirk_g_series = { 193 - .num_zones = 0, 194 - .hdmi_mux = 0, 195 - .amplifier = 0, 196 - .deepslp = 0, 197 - .thermal = true, 198 - .gmode = true, 199 - }; 200 - 201 - static struct quirk_entry quirk_x_series = { 202 - .num_zones = 0, 203 - .hdmi_mux = 0, 204 - .amplifier = 0, 205 - .deepslp = 0, 206 - .thermal = true, 207 - .gmode = false, 208 - }; 209 - 210 - static int __init dmi_matched(const struct dmi_system_id *dmi) 211 - { 212 - quirks = dmi->driver_data; 213 - return 1; 214 - } 215 - 216 - static const struct dmi_system_id alienware_quirks[] __initconst = { 217 - { 218 - .callback = dmi_matched, 219 - .ident = "Alienware ASM100", 220 - .matches = { 221 - DMI_MATCH(DMI_SYS_VENDOR, "Alienware"), 222 - DMI_MATCH(DMI_PRODUCT_NAME, "ASM100"), 223 - }, 224 - .driver_data = &quirk_asm100, 225 - }, 226 - { 227 - .callback = dmi_matched, 228 - .ident = "Alienware ASM200", 229 - .matches = { 230 - DMI_MATCH(DMI_SYS_VENDOR, "Alienware"), 231 - DMI_MATCH(DMI_PRODUCT_NAME, "ASM200"), 232 - }, 233 - .driver_data = &quirk_asm200, 234 - }, 235 - { 236 - .callback = dmi_matched, 237 - .ident = "Alienware ASM201", 238 - .matches = { 239 - DMI_MATCH(DMI_SYS_VENDOR, "Alienware"), 240 - DMI_MATCH(DMI_PRODUCT_NAME, "ASM201"), 241 - }, 242 - .driver_data = &quirk_asm201, 243 - }, 244 - { 245 - .callback = dmi_matched, 246 - .ident = "Alienware m16 R1 AMD", 247 - .matches = { 248 - DMI_MATCH(DMI_SYS_VENDOR, "Alienware"), 249 - DMI_MATCH(DMI_PRODUCT_NAME, "Alienware m16 R1 AMD"), 250 - }, 251 - .driver_data = &quirk_x_series, 252 - }, 253 - { 254 - .callback = dmi_matched, 255 - .ident = "Alienware m17 R5", 256 - .matches = { 257 - DMI_MATCH(DMI_SYS_VENDOR, "Alienware"), 258 - DMI_MATCH(DMI_PRODUCT_NAME, "Alienware m17 R5 AMD"), 259 - }, 260 - .driver_data = &quirk_x_series, 261 - }, 262 - { 263 - .callback = dmi_matched, 264 - .ident = "Alienware m18 R2", 265 - .matches = { 266 - DMI_MATCH(DMI_SYS_VENDOR, "Alienware"), 267 - DMI_MATCH(DMI_PRODUCT_NAME, "Alienware m18 R2"), 268 - }, 269 - .driver_data = &quirk_x_series, 270 - }, 271 - { 272 - .callback = dmi_matched, 273 - .ident = "Alienware x15 R1", 274 - .matches = { 275 - DMI_MATCH(DMI_SYS_VENDOR, "Alienware"), 276 - DMI_MATCH(DMI_PRODUCT_NAME, "Alienware x15 R1"), 277 - }, 278 - .driver_data = &quirk_x_series, 279 - }, 280 - { 281 - .callback = dmi_matched, 282 - .ident = "Alienware x17 R2", 283 - .matches = { 284 - DMI_MATCH(DMI_SYS_VENDOR, "Alienware"), 285 - DMI_MATCH(DMI_PRODUCT_NAME, "Alienware x17 R2"), 286 - }, 287 - .driver_data = &quirk_x_series, 288 - }, 289 - { 290 - .callback = dmi_matched, 291 - .ident = "Alienware X51 R1", 292 - .matches = { 293 - DMI_MATCH(DMI_SYS_VENDOR, "Alienware"), 294 - DMI_MATCH(DMI_PRODUCT_NAME, "Alienware X51"), 295 - }, 296 - .driver_data = &quirk_x51_r1_r2, 297 - }, 298 - { 299 - .callback = dmi_matched, 300 - .ident = "Alienware X51 R2", 301 - .matches = { 302 - DMI_MATCH(DMI_SYS_VENDOR, "Alienware"), 303 - DMI_MATCH(DMI_PRODUCT_NAME, "Alienware X51 R2"), 304 - }, 305 - .driver_data = &quirk_x51_r1_r2, 306 - }, 307 - { 308 - .callback = dmi_matched, 309 - .ident = "Alienware X51 R3", 310 - .matches = { 311 - DMI_MATCH(DMI_SYS_VENDOR, "Alienware"), 312 - DMI_MATCH(DMI_PRODUCT_NAME, "Alienware X51 R3"), 313 - }, 314 - .driver_data = &quirk_x51_r3, 315 - }, 316 - { 317 - .callback = dmi_matched, 318 - .ident = "Dell Inc. G15 5510", 319 - .matches = { 320 - DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."), 321 - DMI_MATCH(DMI_PRODUCT_NAME, "Dell G15 5510"), 322 - }, 323 - .driver_data = &quirk_g_series, 324 - }, 325 - { 326 - .callback = dmi_matched, 327 - .ident = "Dell Inc. G15 5511", 328 - .matches = { 329 - DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."), 330 - DMI_MATCH(DMI_PRODUCT_NAME, "Dell G15 5511"), 331 - }, 332 - .driver_data = &quirk_g_series, 333 - }, 334 - { 335 - .callback = dmi_matched, 336 - .ident = "Dell Inc. G15 5515", 337 - .matches = { 338 - DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."), 339 - DMI_MATCH(DMI_PRODUCT_NAME, "Dell G15 5515"), 340 - }, 341 - .driver_data = &quirk_g_series, 342 - }, 343 - { 344 - .callback = dmi_matched, 345 - .ident = "Dell Inc. G3 3500", 346 - .matches = { 347 - DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."), 348 - DMI_MATCH(DMI_PRODUCT_NAME, "G3 3500"), 349 - }, 350 - .driver_data = &quirk_g_series, 351 - }, 352 - { 353 - .callback = dmi_matched, 354 - .ident = "Dell Inc. G3 3590", 355 - .matches = { 356 - DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."), 357 - DMI_MATCH(DMI_PRODUCT_NAME, "G3 3590"), 358 - }, 359 - .driver_data = &quirk_g_series, 360 - }, 361 - { 362 - .callback = dmi_matched, 363 - .ident = "Dell Inc. G5 5500", 364 - .matches = { 365 - DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."), 366 - DMI_MATCH(DMI_PRODUCT_NAME, "G5 5500"), 367 - }, 368 - .driver_data = &quirk_g_series, 369 - }, 370 - { 371 - .callback = dmi_matched, 372 - .ident = "Dell Inc. Inspiron 5675", 373 - .matches = { 374 - DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."), 375 - DMI_MATCH(DMI_PRODUCT_NAME, "Inspiron 5675"), 376 - }, 377 - .driver_data = &quirk_inspiron5675, 378 - }, 379 - {} 380 - }; 381 - 382 - struct color_platform { 383 - u8 blue; 384 - u8 green; 385 - u8 red; 386 - } __packed; 387 - 388 - struct wmax_brightness_args { 389 - u32 led_mask; 390 - u32 percentage; 391 - }; 392 - 393 - struct wmax_basic_args { 394 - u8 arg; 395 - }; 396 - 397 - struct legacy_led_args { 398 - struct color_platform colors; 399 - u8 brightness; 400 - u8 state; 401 - } __packed; 402 - 403 - struct wmax_led_args { 404 - u32 led_mask; 405 - struct color_platform colors; 406 - u8 state; 407 - } __packed; 408 - 409 - struct wmax_u32_args { 410 - u8 operation; 411 - u8 arg1; 412 - u8 arg2; 413 - u8 arg3; 414 - }; 415 - 416 - static struct platform_device *platform_device; 417 - static struct color_platform colors[4]; 418 - static enum wmax_thermal_mode supported_thermal_profiles[PLATFORM_PROFILE_LAST]; 419 - 420 - static u8 interface; 421 - static u8 lighting_control_state; 422 - static u8 global_brightness; 423 - 424 - /* 425 - * Helpers used for zone control 426 - */ 427 - static int parse_rgb(const char *buf, struct color_platform *colors) 428 - { 429 - long unsigned int rgb; 430 - int ret; 431 - union color_union { 432 - struct color_platform cp; 433 - int package; 434 - } repackager; 435 - 436 - ret = kstrtoul(buf, 16, &rgb); 437 - if (ret) 438 - return ret; 439 - 440 - /* RGB triplet notation is 24-bit hexadecimal */ 441 - if (rgb > 0xFFFFFF) 442 - return -EINVAL; 443 - 444 - repackager.package = rgb & 0x0f0f0f0f; 445 - pr_debug("alienware-wmi: r: %d g:%d b: %d\n", 446 - repackager.cp.red, repackager.cp.green, repackager.cp.blue); 447 - *colors = repackager.cp; 448 - return 0; 449 - } 450 - 451 - /* 452 - * Individual RGB zone control 453 - */ 454 - static int alienware_update_led(u8 location) 455 - { 456 - int method_id; 457 - acpi_status status; 458 - char *guid; 459 - struct acpi_buffer input; 460 - struct legacy_led_args legacy_args; 461 - struct wmax_led_args wmax_basic_args; 462 - if (interface == WMAX) { 463 - wmax_basic_args.led_mask = 1 << location; 464 - wmax_basic_args.colors = colors[location]; 465 - wmax_basic_args.state = lighting_control_state; 466 - guid = WMAX_CONTROL_GUID; 467 - method_id = WMAX_METHOD_ZONE_CONTROL; 468 - 469 - input.length = sizeof(wmax_basic_args); 470 - input.pointer = &wmax_basic_args; 471 - } else { 472 - legacy_args.colors = colors[location]; 473 - legacy_args.brightness = global_brightness; 474 - legacy_args.state = 0; 475 - if (lighting_control_state == LEGACY_BOOTING || 476 - lighting_control_state == LEGACY_SUSPEND) { 477 - guid = LEGACY_POWER_CONTROL_GUID; 478 - legacy_args.state = lighting_control_state; 479 - } else 480 - guid = LEGACY_CONTROL_GUID; 481 - method_id = location + 1; 482 - 483 - input.length = sizeof(legacy_args); 484 - input.pointer = &legacy_args; 485 - } 486 - pr_debug("alienware-wmi: guid %s method %d\n", guid, method_id); 487 - 488 - status = wmi_evaluate_method(guid, 0, method_id, &input, NULL); 489 - if (ACPI_FAILURE(status)) 490 - pr_err("alienware-wmi: zone set failure: %u\n", status); 491 - return ACPI_FAILURE(status); 492 - } 493 - 494 - static ssize_t zone_show(struct device *dev, struct device_attribute *attr, 495 - char *buf, u8 location) 496 - { 497 - return sprintf(buf, "red: %d, green: %d, blue: %d\n", 498 - colors[location].red, colors[location].green, 499 - colors[location].blue); 500 - 501 - } 502 - 503 - static ssize_t zone_store(struct device *dev, struct device_attribute *attr, 504 - const char *buf, size_t count, u8 location) 505 - { 506 - int ret; 507 - 508 - ret = parse_rgb(buf, &colors[location]); 509 - if (ret) 510 - return ret; 511 - 512 - ret = alienware_update_led(location); 513 - 514 - return ret ? ret : count; 515 - } 516 - 517 - static ssize_t zone00_show(struct device *dev, struct device_attribute *attr, 518 - char *buf) 519 - { 520 - return zone_show(dev, attr, buf, 0); 521 - } 522 - 523 - static ssize_t zone00_store(struct device *dev, struct device_attribute *attr, 524 - const char *buf, size_t count) 525 - { 526 - return zone_store(dev, attr, buf, count, 0); 527 - } 528 - 529 - static DEVICE_ATTR_RW(zone00); 530 - 531 - static ssize_t zone01_show(struct device *dev, struct device_attribute *attr, 532 - char *buf) 533 - { 534 - return zone_show(dev, attr, buf, 1); 535 - } 536 - 537 - static ssize_t zone01_store(struct device *dev, struct device_attribute *attr, 538 - const char *buf, size_t count) 539 - { 540 - return zone_store(dev, attr, buf, count, 1); 541 - } 542 - 543 - static DEVICE_ATTR_RW(zone01); 544 - 545 - static ssize_t zone02_show(struct device *dev, struct device_attribute *attr, 546 - char *buf) 547 - { 548 - return zone_show(dev, attr, buf, 2); 549 - } 550 - 551 - static ssize_t zone02_store(struct device *dev, struct device_attribute *attr, 552 - const char *buf, size_t count) 553 - { 554 - return zone_store(dev, attr, buf, count, 2); 555 - } 556 - 557 - static DEVICE_ATTR_RW(zone02); 558 - 559 - static ssize_t zone03_show(struct device *dev, struct device_attribute *attr, 560 - char *buf) 561 - { 562 - return zone_show(dev, attr, buf, 3); 563 - } 564 - 565 - static ssize_t zone03_store(struct device *dev, struct device_attribute *attr, 566 - const char *buf, size_t count) 567 - { 568 - return zone_store(dev, attr, buf, count, 3); 569 - } 570 - 571 - static DEVICE_ATTR_RW(zone03); 572 - 573 - /* 574 - * Lighting control state device attribute (Global) 575 - */ 576 - static ssize_t lighting_control_state_show(struct device *dev, 577 - struct device_attribute *attr, 578 - char *buf) 579 - { 580 - if (lighting_control_state == LEGACY_BOOTING) 581 - return sysfs_emit(buf, "[booting] running suspend\n"); 582 - else if (lighting_control_state == LEGACY_SUSPEND) 583 - return sysfs_emit(buf, "booting running [suspend]\n"); 584 - 585 - return sysfs_emit(buf, "booting [running] suspend\n"); 586 - } 587 - 588 - static ssize_t lighting_control_state_store(struct device *dev, 589 - struct device_attribute *attr, 590 - const char *buf, size_t count) 591 - { 592 - u8 val; 593 - 594 - if (strcmp(buf, "booting\n") == 0) 595 - val = LEGACY_BOOTING; 596 - else if (strcmp(buf, "suspend\n") == 0) 597 - val = LEGACY_SUSPEND; 598 - else if (interface == LEGACY) 599 - val = LEGACY_RUNNING; 600 - else 601 - val = WMAX_RUNNING; 602 - 603 - lighting_control_state = val; 604 - pr_debug("alienware-wmi: updated control state to %d\n", 605 - lighting_control_state); 606 - 607 - return count; 608 - } 609 - 610 - static DEVICE_ATTR_RW(lighting_control_state); 611 - 612 - static umode_t zone_attr_visible(struct kobject *kobj, 613 - struct attribute *attr, int n) 614 - { 615 - if (n < quirks->num_zones + 1) 616 - return attr->mode; 617 - 618 - return 0; 619 - } 620 - 621 - static bool zone_group_visible(struct kobject *kobj) 622 - { 623 - return quirks->num_zones > 0; 624 - } 625 - DEFINE_SYSFS_GROUP_VISIBLE(zone); 626 - 627 - static struct attribute *zone_attrs[] = { 628 - &dev_attr_lighting_control_state.attr, 629 - &dev_attr_zone00.attr, 630 - &dev_attr_zone01.attr, 631 - &dev_attr_zone02.attr, 632 - &dev_attr_zone03.attr, 633 - NULL 634 - }; 635 - 636 - static struct attribute_group zone_attribute_group = { 637 - .name = "rgb_zones", 638 - .is_visible = SYSFS_GROUP_VISIBLE(zone), 639 - .attrs = zone_attrs, 640 - }; 641 - 642 - /* 643 - * LED Brightness (Global) 644 - */ 645 - static int wmax_brightness(int brightness) 646 - { 647 - acpi_status status; 648 - struct acpi_buffer input; 649 - struct wmax_brightness_args args = { 650 - .led_mask = 0xFF, 651 - .percentage = brightness, 652 - }; 653 - input.length = sizeof(args); 654 - input.pointer = &args; 655 - status = wmi_evaluate_method(WMAX_CONTROL_GUID, 0, 656 - WMAX_METHOD_BRIGHTNESS, &input, NULL); 657 - if (ACPI_FAILURE(status)) 658 - pr_err("alienware-wmi: brightness set failure: %u\n", status); 659 - return ACPI_FAILURE(status); 660 - } 661 - 662 - static void global_led_set(struct led_classdev *led_cdev, 663 - enum led_brightness brightness) 664 - { 665 - int ret; 666 - global_brightness = brightness; 667 - if (interface == WMAX) 668 - ret = wmax_brightness(brightness); 669 - else 670 - ret = alienware_update_led(0); 671 - if (ret) 672 - pr_err("LED brightness update failed\n"); 673 - } 674 - 675 - static enum led_brightness global_led_get(struct led_classdev *led_cdev) 676 - { 677 - return global_brightness; 678 - } 679 - 680 - static struct led_classdev global_led = { 681 - .brightness_set = global_led_set, 682 - .brightness_get = global_led_get, 683 - .name = "alienware::global_brightness", 684 - }; 685 - 686 - static int alienware_zone_init(struct platform_device *dev) 687 - { 688 - if (interface == WMAX) { 689 - lighting_control_state = WMAX_RUNNING; 690 - } else if (interface == LEGACY) { 691 - lighting_control_state = LEGACY_RUNNING; 692 - } 693 - global_led.max_brightness = 0x0F; 694 - global_brightness = global_led.max_brightness; 695 - 696 - return led_classdev_register(&dev->dev, &global_led); 697 - } 698 - 699 - static void alienware_zone_exit(struct platform_device *dev) 700 - { 701 - if (!quirks->num_zones) 702 - return; 703 - 704 - led_classdev_unregister(&global_led); 705 - } 706 - 707 - static acpi_status alienware_wmax_command(void *in_args, size_t in_size, 708 - u32 command, u32 *out_data) 709 - { 710 - acpi_status status; 711 - union acpi_object *obj; 712 - struct acpi_buffer input; 713 - struct acpi_buffer output; 714 - 715 - input.length = in_size; 716 - input.pointer = in_args; 717 - if (out_data) { 718 - output.length = ACPI_ALLOCATE_BUFFER; 719 - output.pointer = NULL; 720 - status = wmi_evaluate_method(WMAX_CONTROL_GUID, 0, 721 - command, &input, &output); 722 - if (ACPI_SUCCESS(status)) { 723 - obj = (union acpi_object *)output.pointer; 724 - if (obj && obj->type == ACPI_TYPE_INTEGER) 725 - *out_data = (u32)obj->integer.value; 726 - } 727 - kfree(output.pointer); 728 - } else { 729 - status = wmi_evaluate_method(WMAX_CONTROL_GUID, 0, 730 - command, &input, NULL); 731 - } 732 - return status; 733 - } 734 - 735 - /* 736 - * The HDMI mux sysfs node indicates the status of the HDMI input mux. 737 - * It can toggle between standard system GPU output and HDMI input. 738 - */ 739 - static ssize_t cable_show(struct device *dev, struct device_attribute *attr, 740 - char *buf) 741 - { 742 - struct wmax_basic_args in_args = { 743 - .arg = 0, 744 - }; 745 - acpi_status status; 746 - u32 out_data; 747 - 748 - status = 749 - alienware_wmax_command(&in_args, sizeof(in_args), 750 - WMAX_METHOD_HDMI_CABLE, &out_data); 751 - if (ACPI_SUCCESS(status)) { 752 - if (out_data == 0) 753 - return sysfs_emit(buf, "[unconnected] connected unknown\n"); 754 - else if (out_data == 1) 755 - return sysfs_emit(buf, "unconnected [connected] unknown\n"); 756 - } 757 - pr_err("alienware-wmi: unknown HDMI cable status: %d\n", status); 758 - return sysfs_emit(buf, "unconnected connected [unknown]\n"); 759 - } 760 - 761 - static ssize_t source_show(struct device *dev, struct device_attribute *attr, 762 - char *buf) 763 - { 764 - struct wmax_basic_args in_args = { 765 - .arg = 0, 766 - }; 767 - acpi_status status; 768 - u32 out_data; 769 - 770 - status = 771 - alienware_wmax_command(&in_args, sizeof(in_args), 772 - WMAX_METHOD_HDMI_STATUS, &out_data); 773 - 774 - if (ACPI_SUCCESS(status)) { 775 - if (out_data == 1) 776 - return sysfs_emit(buf, "[input] gpu unknown\n"); 777 - else if (out_data == 2) 778 - return sysfs_emit(buf, "input [gpu] unknown\n"); 779 - } 780 - pr_err("alienware-wmi: unknown HDMI source status: %u\n", status); 781 - return sysfs_emit(buf, "input gpu [unknown]\n"); 782 - } 783 - 784 - static ssize_t source_store(struct device *dev, struct device_attribute *attr, 785 - const char *buf, size_t count) 786 - { 787 - struct wmax_basic_args args; 788 - acpi_status status; 789 - 790 - if (strcmp(buf, "gpu\n") == 0) 791 - args.arg = 1; 792 - else if (strcmp(buf, "input\n") == 0) 793 - args.arg = 2; 794 - else 795 - args.arg = 3; 796 - pr_debug("alienware-wmi: setting hdmi to %d : %s", args.arg, buf); 797 - 798 - status = alienware_wmax_command(&args, sizeof(args), 799 - WMAX_METHOD_HDMI_SOURCE, NULL); 800 - 801 - if (ACPI_FAILURE(status)) 802 - pr_err("alienware-wmi: HDMI toggle failed: results: %u\n", 803 - status); 804 - return count; 805 - } 806 - 807 - static DEVICE_ATTR_RO(cable); 808 - static DEVICE_ATTR_RW(source); 809 - 810 - static bool hdmi_group_visible(struct kobject *kobj) 811 - { 812 - return quirks->hdmi_mux; 813 - } 814 - DEFINE_SIMPLE_SYSFS_GROUP_VISIBLE(hdmi); 815 - 816 - static struct attribute *hdmi_attrs[] = { 817 - &dev_attr_cable.attr, 818 - &dev_attr_source.attr, 819 - NULL, 820 - }; 821 - 822 - static const struct attribute_group hdmi_attribute_group = { 823 - .name = "hdmi", 824 - .is_visible = SYSFS_GROUP_VISIBLE(hdmi), 825 - .attrs = hdmi_attrs, 826 - }; 827 - 828 - /* 829 - * Alienware GFX amplifier support 830 - * - Currently supports reading cable status 831 - * - Leaving expansion room to possibly support dock/undock events later 832 - */ 833 - static ssize_t status_show(struct device *dev, struct device_attribute *attr, 834 - char *buf) 835 - { 836 - struct wmax_basic_args in_args = { 837 - .arg = 0, 838 - }; 839 - acpi_status status; 840 - u32 out_data; 841 - 842 - status = 843 - alienware_wmax_command(&in_args, sizeof(in_args), 844 - WMAX_METHOD_AMPLIFIER_CABLE, &out_data); 845 - if (ACPI_SUCCESS(status)) { 846 - if (out_data == 0) 847 - return sysfs_emit(buf, "[unconnected] connected unknown\n"); 848 - else if (out_data == 1) 849 - return sysfs_emit(buf, "unconnected [connected] unknown\n"); 850 - } 851 - pr_err("alienware-wmi: unknown amplifier cable status: %d\n", status); 852 - return sysfs_emit(buf, "unconnected connected [unknown]\n"); 853 - } 854 - 855 - static DEVICE_ATTR_RO(status); 856 - 857 - static bool amplifier_group_visible(struct kobject *kobj) 858 - { 859 - return quirks->amplifier; 860 - } 861 - DEFINE_SIMPLE_SYSFS_GROUP_VISIBLE(amplifier); 862 - 863 - static struct attribute *amplifier_attrs[] = { 864 - &dev_attr_status.attr, 865 - NULL, 866 - }; 867 - 868 - static const struct attribute_group amplifier_attribute_group = { 869 - .name = "amplifier", 870 - .is_visible = SYSFS_GROUP_VISIBLE(amplifier), 871 - .attrs = amplifier_attrs, 872 - }; 873 - 874 - /* 875 - * Deep Sleep Control support 876 - * - Modifies BIOS setting for deep sleep control allowing extra wakeup events 877 - */ 878 - static ssize_t deepsleep_show(struct device *dev, struct device_attribute *attr, 879 - char *buf) 880 - { 881 - struct wmax_basic_args in_args = { 882 - .arg = 0, 883 - }; 884 - acpi_status status; 885 - u32 out_data; 886 - 887 - status = alienware_wmax_command(&in_args, sizeof(in_args), 888 - WMAX_METHOD_DEEP_SLEEP_STATUS, &out_data); 889 - if (ACPI_SUCCESS(status)) { 890 - if (out_data == 0) 891 - return sysfs_emit(buf, "[disabled] s5 s5_s4\n"); 892 - else if (out_data == 1) 893 - return sysfs_emit(buf, "disabled [s5] s5_s4\n"); 894 - else if (out_data == 2) 895 - return sysfs_emit(buf, "disabled s5 [s5_s4]\n"); 896 - } 897 - pr_err("alienware-wmi: unknown deep sleep status: %d\n", status); 898 - return sysfs_emit(buf, "disabled s5 s5_s4 [unknown]\n"); 899 - } 900 - 901 - static ssize_t deepsleep_store(struct device *dev, struct device_attribute *attr, 902 - const char *buf, size_t count) 903 - { 904 - struct wmax_basic_args args; 905 - acpi_status status; 906 - 907 - if (strcmp(buf, "disabled\n") == 0) 908 - args.arg = 0; 909 - else if (strcmp(buf, "s5\n") == 0) 910 - args.arg = 1; 911 - else 912 - args.arg = 2; 913 - pr_debug("alienware-wmi: setting deep sleep to %d : %s", args.arg, buf); 914 - 915 - status = alienware_wmax_command(&args, sizeof(args), 916 - WMAX_METHOD_DEEP_SLEEP_CONTROL, NULL); 917 - 918 - if (ACPI_FAILURE(status)) 919 - pr_err("alienware-wmi: deep sleep control failed: results: %u\n", 920 - status); 921 - return count; 922 - } 923 - 924 - static DEVICE_ATTR_RW(deepsleep); 925 - 926 - static bool deepsleep_group_visible(struct kobject *kobj) 927 - { 928 - return quirks->deepslp; 929 - } 930 - DEFINE_SIMPLE_SYSFS_GROUP_VISIBLE(deepsleep); 931 - 932 - static struct attribute *deepsleep_attrs[] = { 933 - &dev_attr_deepsleep.attr, 934 - NULL, 935 - }; 936 - 937 - static const struct attribute_group deepsleep_attribute_group = { 938 - .name = "deepsleep", 939 - .is_visible = SYSFS_GROUP_VISIBLE(deepsleep), 940 - .attrs = deepsleep_attrs, 941 - }; 942 - 943 - /* 944 - * Thermal Profile control 945 - * - Provides thermal profile control through the Platform Profile API 946 - */ 947 - #define WMAX_THERMAL_TABLE_MASK GENMASK(7, 4) 948 - #define WMAX_THERMAL_MODE_MASK GENMASK(3, 0) 949 - #define WMAX_SENSOR_ID_MASK BIT(8) 950 - 951 - static bool is_wmax_thermal_code(u32 code) 952 - { 953 - if (code & WMAX_SENSOR_ID_MASK) 954 - return false; 955 - 956 - if ((code & WMAX_THERMAL_MODE_MASK) >= THERMAL_MODE_LAST) 957 - return false; 958 - 959 - if ((code & WMAX_THERMAL_TABLE_MASK) == WMAX_THERMAL_TABLE_BASIC && 960 - (code & WMAX_THERMAL_MODE_MASK) >= THERMAL_MODE_BASIC_QUIET) 961 - return true; 962 - 963 - if ((code & WMAX_THERMAL_TABLE_MASK) == WMAX_THERMAL_TABLE_USTT && 964 - (code & WMAX_THERMAL_MODE_MASK) <= THERMAL_MODE_USTT_LOW_POWER) 965 - return true; 966 - 967 - return false; 968 - } 969 - 970 - static int wmax_thermal_information(u8 operation, u8 arg, u32 *out_data) 971 - { 972 - struct wmax_u32_args in_args = { 973 - .operation = operation, 974 - .arg1 = arg, 975 - .arg2 = 0, 976 - .arg3 = 0, 977 - }; 978 - acpi_status status; 979 - 980 - status = alienware_wmax_command(&in_args, sizeof(in_args), 981 - WMAX_METHOD_THERMAL_INFORMATION, 982 - out_data); 983 - 984 - if (ACPI_FAILURE(status)) 985 - return -EIO; 986 - 987 - if (*out_data == WMAX_FAILURE_CODE) 988 - return -EBADRQC; 989 - 990 - return 0; 991 - } 992 - 993 - static int wmax_thermal_control(u8 profile) 994 - { 995 - struct wmax_u32_args in_args = { 996 - .operation = WMAX_OPERATION_ACTIVATE_PROFILE, 997 - .arg1 = profile, 998 - .arg2 = 0, 999 - .arg3 = 0, 1000 - }; 1001 - acpi_status status; 1002 - u32 out_data; 1003 - 1004 - status = alienware_wmax_command(&in_args, sizeof(in_args), 1005 - WMAX_METHOD_THERMAL_CONTROL, 1006 - &out_data); 1007 - 1008 - if (ACPI_FAILURE(status)) 1009 - return -EIO; 1010 - 1011 - if (out_data == WMAX_FAILURE_CODE) 1012 - return -EBADRQC; 1013 - 1014 - return 0; 1015 - } 1016 - 1017 - static int wmax_game_shift_status(u8 operation, u32 *out_data) 1018 - { 1019 - struct wmax_u32_args in_args = { 1020 - .operation = operation, 1021 - .arg1 = 0, 1022 - .arg2 = 0, 1023 - .arg3 = 0, 1024 - }; 1025 - acpi_status status; 1026 - 1027 - status = alienware_wmax_command(&in_args, sizeof(in_args), 1028 - WMAX_METHOD_GAME_SHIFT_STATUS, 1029 - out_data); 1030 - 1031 - if (ACPI_FAILURE(status)) 1032 - return -EIO; 1033 - 1034 - if (*out_data == WMAX_FAILURE_CODE) 1035 - return -EOPNOTSUPP; 1036 - 1037 - return 0; 1038 - } 1039 - 1040 - static int thermal_profile_get(struct device *dev, 1041 - enum platform_profile_option *profile) 1042 - { 1043 - u32 out_data; 1044 - int ret; 1045 - 1046 - ret = wmax_thermal_information(WMAX_OPERATION_CURRENT_PROFILE, 1047 - 0, &out_data); 1048 - 1049 - if (ret < 0) 1050 - return ret; 1051 - 1052 - if (out_data == WMAX_THERMAL_MODE_GMODE) { 1053 - *profile = PLATFORM_PROFILE_PERFORMANCE; 1054 - return 0; 1055 - } 1056 - 1057 - if (!is_wmax_thermal_code(out_data)) 1058 - return -ENODATA; 1059 - 1060 - out_data &= WMAX_THERMAL_MODE_MASK; 1061 - *profile = wmax_mode_to_platform_profile[out_data]; 1062 - 1063 - return 0; 1064 - } 1065 - 1066 - static int thermal_profile_set(struct device *dev, 1067 - enum platform_profile_option profile) 1068 - { 1069 - if (quirks->gmode) { 1070 - u32 gmode_status; 1071 - int ret; 1072 - 1073 - ret = wmax_game_shift_status(WMAX_OPERATION_GET_GAME_SHIFT_STATUS, 1074 - &gmode_status); 1075 - 1076 - if (ret < 0) 1077 - return ret; 1078 - 1079 - if ((profile == PLATFORM_PROFILE_PERFORMANCE && !gmode_status) || 1080 - (profile != PLATFORM_PROFILE_PERFORMANCE && gmode_status)) { 1081 - ret = wmax_game_shift_status(WMAX_OPERATION_TOGGLE_GAME_SHIFT, 1082 - &gmode_status); 1083 - 1084 - if (ret < 0) 1085 - return ret; 1086 - } 1087 - } 1088 - 1089 - return wmax_thermal_control(supported_thermal_profiles[profile]); 1090 - } 1091 - 1092 - static int thermal_profile_probe(void *drvdata, unsigned long *choices) 1093 - { 1094 - enum platform_profile_option profile; 1095 - enum wmax_thermal_mode mode; 1096 - u8 sys_desc[4]; 1097 - u32 first_mode; 1098 - u32 out_data; 1099 - int ret; 1100 - 1101 - ret = wmax_thermal_information(WMAX_OPERATION_SYS_DESCRIPTION, 1102 - 0, (u32 *) &sys_desc); 1103 - if (ret < 0) 1104 - return ret; 1105 - 1106 - first_mode = sys_desc[0] + sys_desc[1]; 1107 - 1108 - for (u32 i = 0; i < sys_desc[3]; i++) { 1109 - ret = wmax_thermal_information(WMAX_OPERATION_LIST_IDS, 1110 - i + first_mode, &out_data); 1111 - 1112 - if (ret == -EIO) 1113 - return ret; 1114 - 1115 - if (ret == -EBADRQC) 1116 - break; 1117 - 1118 - if (!is_wmax_thermal_code(out_data)) 1119 - continue; 1120 - 1121 - mode = out_data & WMAX_THERMAL_MODE_MASK; 1122 - profile = wmax_mode_to_platform_profile[mode]; 1123 - supported_thermal_profiles[profile] = out_data; 1124 - 1125 - set_bit(profile, choices); 1126 - } 1127 - 1128 - if (bitmap_empty(choices, PLATFORM_PROFILE_LAST)) 1129 - return -ENODEV; 1130 - 1131 - if (quirks->gmode) { 1132 - supported_thermal_profiles[PLATFORM_PROFILE_PERFORMANCE] = 1133 - WMAX_THERMAL_MODE_GMODE; 1134 - 1135 - set_bit(PLATFORM_PROFILE_PERFORMANCE, choices); 1136 - } 1137 - 1138 - return 0; 1139 - } 1140 - 1141 - static const struct platform_profile_ops awcc_platform_profile_ops = { 1142 - .probe = thermal_profile_probe, 1143 - .profile_get = thermal_profile_get, 1144 - .profile_set = thermal_profile_set, 1145 - }; 1146 - 1147 - static int create_thermal_profile(struct platform_device *platform_device) 1148 - { 1149 - struct device *ppdev; 1150 - 1151 - ppdev = devm_platform_profile_register(&platform_device->dev, "alienware-wmi", 1152 - NULL, &awcc_platform_profile_ops); 1153 - 1154 - return PTR_ERR_OR_ZERO(ppdev); 1155 - } 1156 - 1157 - /* 1158 - * Platform Driver 1159 - */ 1160 - static const struct attribute_group *alienfx_groups[] = { 1161 - &zone_attribute_group, 1162 - &hdmi_attribute_group, 1163 - &amplifier_attribute_group, 1164 - &deepsleep_attribute_group, 1165 - NULL 1166 - }; 1167 - 1168 - static struct platform_driver platform_driver = { 1169 - .driver = { 1170 - .name = "alienware-wmi", 1171 - .dev_groups = alienfx_groups, 1172 - }, 1173 - }; 1174 - 1175 - static int __init alienware_wmi_init(void) 1176 - { 1177 - int ret; 1178 - 1179 - if (wmi_has_guid(LEGACY_CONTROL_GUID)) 1180 - interface = LEGACY; 1181 - else if (wmi_has_guid(WMAX_CONTROL_GUID)) 1182 - interface = WMAX; 1183 - else { 1184 - pr_warn("alienware-wmi: No known WMI GUID found\n"); 1185 - return -ENODEV; 1186 - } 1187 - 1188 - dmi_check_system(alienware_quirks); 1189 - if (quirks == NULL) 1190 - quirks = &quirk_unknown; 1191 - 1192 - if (force_platform_profile) 1193 - quirks->thermal = true; 1194 - 1195 - if (force_gmode) { 1196 - if (quirks->thermal) 1197 - quirks->gmode = true; 1198 - else 1199 - pr_warn("force_gmode requires platform profile support\n"); 1200 - } 1201 - 1202 - ret = platform_driver_register(&platform_driver); 1203 - if (ret) 1204 - goto fail_platform_driver; 1205 - platform_device = platform_device_alloc("alienware-wmi", PLATFORM_DEVID_NONE); 1206 - if (!platform_device) { 1207 - ret = -ENOMEM; 1208 - goto fail_platform_device1; 1209 - } 1210 - ret = platform_device_add(platform_device); 1211 - if (ret) 1212 - goto fail_platform_device2; 1213 - 1214 - if (quirks->thermal) { 1215 - ret = create_thermal_profile(platform_device); 1216 - if (ret) 1217 - goto fail_prep_thermal_profile; 1218 - } 1219 - 1220 - if (quirks->num_zones > 0) { 1221 - ret = alienware_zone_init(platform_device); 1222 - if (ret) 1223 - goto fail_prep_zones; 1224 - } 1225 - 1226 - return 0; 1227 - 1228 - fail_prep_zones: 1229 - alienware_zone_exit(platform_device); 1230 - fail_prep_thermal_profile: 1231 - platform_device_del(platform_device); 1232 - fail_platform_device2: 1233 - platform_device_put(platform_device); 1234 - fail_platform_device1: 1235 - platform_driver_unregister(&platform_driver); 1236 - fail_platform_driver: 1237 - return ret; 1238 - } 1239 - 1240 - module_init(alienware_wmi_init); 1241 - 1242 - static void __exit alienware_wmi_exit(void) 1243 - { 1244 - alienware_zone_exit(platform_device); 1245 - platform_device_unregister(platform_device); 1246 - platform_driver_unregister(&platform_driver); 1247 - } 1248 - 1249 - module_exit(alienware_wmi_exit);
+117
drivers/platform/x86/dell/alienware-wmi.h
··· 1 + /* SPDX-License-Identifier: GPL-2.0-or-later */ 2 + /* 3 + * Alienware WMI special features driver 4 + * 5 + * Copyright (C) 2014 Dell Inc <Dell.Client.Kernel@dell.com> 6 + * Copyright (C) 2024 Kurt Borja <kuurtb@gmail.com> 7 + */ 8 + 9 + #ifndef _ALIENWARE_WMI_H_ 10 + #define _ALIENWARE_WMI_H_ 11 + 12 + #include <linux/leds.h> 13 + #include <linux/platform_device.h> 14 + #include <linux/wmi.h> 15 + 16 + #define LEGACY_CONTROL_GUID "A90597CE-A997-11DA-B012-B622A1EF5492" 17 + #define LEGACY_POWER_CONTROL_GUID "A80593CE-A997-11DA-B012-B622A1EF5492" 18 + #define WMAX_CONTROL_GUID "A70591CE-A997-11DA-B012-B622A1EF5492" 19 + 20 + enum INTERFACE_FLAGS { 21 + LEGACY, 22 + WMAX, 23 + }; 24 + 25 + enum LEGACY_CONTROL_STATES { 26 + LEGACY_RUNNING = 1, 27 + LEGACY_BOOTING = 0, 28 + LEGACY_SUSPEND = 3, 29 + }; 30 + 31 + enum WMAX_CONTROL_STATES { 32 + WMAX_RUNNING = 0xFF, 33 + WMAX_BOOTING = 0, 34 + WMAX_SUSPEND = 3, 35 + }; 36 + 37 + struct alienfx_quirks { 38 + u8 num_zones; 39 + bool hdmi_mux; 40 + bool amplifier; 41 + bool deepslp; 42 + }; 43 + 44 + struct color_platform { 45 + u8 blue; 46 + u8 green; 47 + u8 red; 48 + } __packed; 49 + 50 + struct alienfx_priv { 51 + struct platform_device *pdev; 52 + struct led_classdev global_led; 53 + struct color_platform colors[4]; 54 + u8 global_brightness; 55 + u8 lighting_control_state; 56 + }; 57 + 58 + struct alienfx_ops { 59 + int (*upd_led)(struct alienfx_priv *priv, struct wmi_device *wdev, 60 + u8 location); 61 + int (*upd_brightness)(struct alienfx_priv *priv, struct wmi_device *wdev, 62 + u8 brightness); 63 + }; 64 + 65 + struct alienfx_platdata { 66 + struct wmi_device *wdev; 67 + struct alienfx_ops ops; 68 + }; 69 + 70 + extern u8 alienware_interface; 71 + extern struct alienfx_quirks *alienfx; 72 + 73 + int alienware_wmi_command(struct wmi_device *wdev, u32 method_id, 74 + void *in_args, size_t in_size, u32 *out_data); 75 + 76 + int alienware_alienfx_setup(struct alienfx_platdata *pdata); 77 + 78 + #if IS_ENABLED(CONFIG_ALIENWARE_WMI_LEGACY) 79 + int __init alienware_legacy_wmi_init(void); 80 + void __exit alienware_legacy_wmi_exit(void); 81 + #else 82 + static inline int alienware_legacy_wmi_init(void) 83 + { 84 + return -ENODEV; 85 + } 86 + 87 + static inline void alienware_legacy_wmi_exit(void) 88 + { 89 + } 90 + #endif 91 + 92 + #if IS_ENABLED(CONFIG_ALIENWARE_WMI_WMAX) 93 + extern const struct attribute_group wmax_hdmi_attribute_group; 94 + extern const struct attribute_group wmax_amplifier_attribute_group; 95 + extern const struct attribute_group wmax_deepsleep_attribute_group; 96 + 97 + #define WMAX_DEV_GROUPS &wmax_hdmi_attribute_group, \ 98 + &wmax_amplifier_attribute_group, \ 99 + &wmax_deepsleep_attribute_group, 100 + 101 + int __init alienware_wmax_wmi_init(void); 102 + void __exit alienware_wmax_wmi_exit(void); 103 + #else 104 + #define WMAX_DEV_GROUPS 105 + 106 + static inline int alienware_wmax_wmi_init(void) 107 + { 108 + return -ENODEV; 109 + } 110 + 111 + 112 + static inline void alienware_wmax_wmi_exit(void) 113 + { 114 + } 115 + #endif 116 + 117 + #endif
+1 -1
drivers/platform/x86/dell/dell-uart-backlight.c
··· 325 325 return PTR_ERR_OR_ZERO(dell_bl->bl); 326 326 } 327 327 328 - struct serdev_device_driver dell_uart_bl_serdev_driver = { 328 + static struct serdev_device_driver dell_uart_bl_serdev_driver = { 329 329 .probe = dell_uart_bl_serdev_probe, 330 330 .driver = { 331 331 .name = KBUILD_MODNAME,
+46 -38
drivers/platform/x86/dell/dell-wmi-ddv.c
··· 104 104 105 105 struct dell_wmi_ddv_data { 106 106 struct acpi_battery_hook hook; 107 - struct device_attribute temp_attr; 108 107 struct device_attribute eppid_attr; 109 108 struct dell_wmi_ddv_sensors fans; 110 109 struct dell_wmi_ddv_sensors temps; ··· 650 651 return kstrtou32(uid_str, 10, index); 651 652 } 652 653 653 - static ssize_t temp_show(struct device *dev, struct device_attribute *attr, char *buf) 654 - { 655 - struct dell_wmi_ddv_data *data = container_of(attr, struct dell_wmi_ddv_data, temp_attr); 656 - u32 index, value; 657 - int ret; 658 - 659 - ret = dell_wmi_ddv_battery_index(to_acpi_device(dev->parent), &index); 660 - if (ret < 0) 661 - return ret; 662 - 663 - ret = dell_wmi_ddv_query_integer(data->wdev, DELL_DDV_BATTERY_TEMPERATURE, index, &value); 664 - if (ret < 0) 665 - return ret; 666 - 667 - /* Use 2731 instead of 2731.5 to avoid unnecessary rounding */ 668 - return sysfs_emit(buf, "%d\n", value - 2731); 669 - } 670 - 671 654 static ssize_t eppid_show(struct device *dev, struct device_attribute *attr, char *buf) 672 655 { 673 656 struct dell_wmi_ddv_data *data = container_of(attr, struct dell_wmi_ddv_data, eppid_attr); ··· 676 695 return ret; 677 696 } 678 697 698 + static int dell_wmi_ddv_get_property(struct power_supply *psy, const struct power_supply_ext *ext, 699 + void *drvdata, enum power_supply_property psp, 700 + union power_supply_propval *val) 701 + { 702 + struct dell_wmi_ddv_data *data = drvdata; 703 + u32 index, value; 704 + int ret; 705 + 706 + ret = dell_wmi_ddv_battery_index(to_acpi_device(psy->dev.parent), &index); 707 + if (ret < 0) 708 + return ret; 709 + 710 + switch (psp) { 711 + case POWER_SUPPLY_PROP_TEMP: 712 + ret = dell_wmi_ddv_query_integer(data->wdev, DELL_DDV_BATTERY_TEMPERATURE, index, 713 + &value); 714 + if (ret < 0) 715 + return ret; 716 + 717 + /* Use 2732 instead of 2731.5 to avoid unnecessary rounding and to emulate 718 + * the behaviour of the OEM application which seems to round down the result. 719 + */ 720 + val->intval = value - 2732; 721 + return 0; 722 + default: 723 + return -EINVAL; 724 + } 725 + } 726 + 727 + static const enum power_supply_property dell_wmi_ddv_properties[] = { 728 + POWER_SUPPLY_PROP_TEMP, 729 + }; 730 + 731 + static const struct power_supply_ext dell_wmi_ddv_extension = { 732 + .name = DRIVER_NAME, 733 + .properties = dell_wmi_ddv_properties, 734 + .num_properties = ARRAY_SIZE(dell_wmi_ddv_properties), 735 + .get_property = dell_wmi_ddv_get_property, 736 + }; 737 + 679 738 static int dell_wmi_ddv_add_battery(struct power_supply *battery, struct acpi_battery_hook *hook) 680 739 { 681 740 struct dell_wmi_ddv_data *data = container_of(hook, struct dell_wmi_ddv_data, hook); ··· 727 706 if (ret < 0) 728 707 return 0; 729 708 730 - ret = device_create_file(&battery->dev, &data->temp_attr); 709 + ret = device_create_file(&battery->dev, &data->eppid_attr); 731 710 if (ret < 0) 732 711 return ret; 733 712 734 - ret = device_create_file(&battery->dev, &data->eppid_attr); 713 + ret = power_supply_register_extension(battery, &dell_wmi_ddv_extension, &data->wdev->dev, 714 + data); 735 715 if (ret < 0) { 736 - device_remove_file(&battery->dev, &data->temp_attr); 716 + device_remove_file(&battery->dev, &data->eppid_attr); 737 717 738 718 return ret; 739 719 } ··· 746 724 { 747 725 struct dell_wmi_ddv_data *data = container_of(hook, struct dell_wmi_ddv_data, hook); 748 726 749 - device_remove_file(&battery->dev, &data->temp_attr); 750 727 device_remove_file(&battery->dev, &data->eppid_attr); 728 + power_supply_unregister_extension(battery, &dell_wmi_ddv_extension); 751 729 752 730 return 0; 753 - } 754 - 755 - static void dell_wmi_ddv_battery_remove(void *data) 756 - { 757 - struct acpi_battery_hook *hook = data; 758 - 759 - battery_hook_unregister(hook); 760 731 } 761 732 762 733 static int dell_wmi_ddv_battery_add(struct dell_wmi_ddv_data *data) ··· 758 743 data->hook.add_battery = dell_wmi_ddv_add_battery; 759 744 data->hook.remove_battery = dell_wmi_ddv_remove_battery; 760 745 761 - sysfs_attr_init(&data->temp_attr.attr); 762 - data->temp_attr.attr.name = "temp"; 763 - data->temp_attr.attr.mode = 0444; 764 - data->temp_attr.show = temp_show; 765 - 766 746 sysfs_attr_init(&data->eppid_attr.attr); 767 747 data->eppid_attr.attr.name = "eppid"; 768 748 data->eppid_attr.attr.mode = 0444; 769 749 data->eppid_attr.show = eppid_show; 770 750 771 - battery_hook_register(&data->hook); 772 - 773 - return devm_add_action_or_reset(&data->wdev->dev, dell_wmi_ddv_battery_remove, &data->hook); 751 + return devm_battery_hook_register(&data->wdev->dev, &data->hook); 774 752 } 775 753 776 754 static int dell_wmi_ddv_buffer_read(struct seq_file *seq, enum dell_ddv_method method)
+1 -1
drivers/platform/x86/dell/dell-wmi-sysman/Makefile
··· 1 1 obj-$(CONFIG_DELL_WMI_SYSMAN) += dell-wmi-sysman.o 2 - dell-wmi-sysman-objs := sysman.o \ 2 + dell-wmi-sysman-y := sysman.o \ 3 3 enum-attributes.o \ 4 4 int-attributes.o \ 5 5 string-attributes.o \
+1 -1
drivers/platform/x86/hp/hp-bioscfg/Makefile
··· 1 1 obj-$(CONFIG_HP_BIOSCFG) := hp-bioscfg.o 2 2 3 - hp-bioscfg-objs := bioscfg.o \ 3 + hp-bioscfg-y := bioscfg.o \ 4 4 biosattr-interface.o \ 5 5 enum-attributes.o \ 6 6 int-attributes.o \
+6 -9
drivers/platform/x86/hp/hp-bioscfg/bioscfg.c
··· 388 388 */ 389 389 int hp_get_instance_count(const char *guid_string) 390 390 { 391 - union acpi_object *wmi_obj = NULL; 392 - int i = 0; 391 + int ret; 393 392 394 - do { 395 - kfree(wmi_obj); 396 - wmi_obj = hp_get_wmiobj_pointer(i, guid_string); 397 - i++; 398 - } while (wmi_obj); 393 + ret = wmi_instance_count(guid_string); 394 + if (ret < 0) 395 + return 0; 399 396 400 - return i - 1; 397 + return ret; 401 398 } 402 399 403 400 /** ··· 445 448 return -ENOMEM; 446 449 447 450 for (i = 0; i < input_len; i += 5) { 448 - strncpy(tmp, input + i, strlen(tmp)); 451 + strscpy(tmp, input + i); 449 452 if (kstrtol(tmp, 16, &ch) == 0) { 450 453 // escape char 451 454 if (ch == '\\' ||
+2 -21
drivers/platform/x86/ideapad-laptop.c
··· 854 854 .is_visible = ideapad_is_visible, 855 855 .attrs = ideapad_attributes 856 856 }; 857 + __ATTRIBUTE_GROUPS(ideapad_attribute); 857 858 858 859 /* 859 860 * DYTC Platform profile ··· 1243 1242 1244 1243 rfkill_unregister(priv->rfk[dev]); 1245 1244 rfkill_destroy(priv->rfk[dev]); 1246 - } 1247 - 1248 - /* 1249 - * Platform device 1250 - */ 1251 - static int ideapad_sysfs_init(struct ideapad_private *priv) 1252 - { 1253 - return device_add_group(&priv->platform_device->dev, 1254 - &ideapad_attribute_group); 1255 - } 1256 - 1257 - static void ideapad_sysfs_exit(struct ideapad_private *priv) 1258 - { 1259 - device_remove_group(&priv->platform_device->dev, 1260 - &ideapad_attribute_group); 1261 1245 } 1262 1246 1263 1247 /* ··· 2161 2175 2162 2176 ideapad_check_features(priv); 2163 2177 2164 - err = ideapad_sysfs_init(priv); 2165 - if (err) 2166 - return err; 2167 - 2168 2178 ideapad_debugfs_init(priv); 2169 2179 2170 2180 err = ideapad_input_init(priv); ··· 2247 2265 2248 2266 input_failed: 2249 2267 ideapad_debugfs_exit(priv); 2250 - ideapad_sysfs_exit(priv); 2251 2268 2252 2269 return err; 2253 2270 } ··· 2274 2293 ideapad_kbd_bl_exit(priv); 2275 2294 ideapad_input_exit(priv); 2276 2295 ideapad_debugfs_exit(priv); 2277 - ideapad_sysfs_exit(priv); 2278 2296 } 2279 2297 2280 2298 #ifdef CONFIG_PM_SLEEP ··· 2305 2325 .name = "ideapad_acpi", 2306 2326 .pm = &ideapad_pm, 2307 2327 .acpi_match_table = ACPI_PTR(ideapad_device_ids), 2328 + .dev_groups = ideapad_attribute_groups, 2308 2329 }, 2309 2330 }; 2310 2331
+1 -1
drivers/platform/x86/intel/ifs/Makefile
··· 1 1 obj-$(CONFIG_INTEL_IFS) += intel_ifs.o 2 2 3 - intel_ifs-objs := core.o load.o runtest.o sysfs.o 3 + intel_ifs-y := core.o load.o runtest.o sysfs.o
+24 -24
drivers/platform/x86/intel/int3472/discrete.c
··· 56 56 57 57 static int skl_int3472_fill_gpiod_lookup(struct gpiod_lookup *table_entry, 58 58 struct acpi_resource_gpio *agpio, 59 - const char *func, unsigned long gpio_flags) 59 + const char *con_id, unsigned long gpio_flags) 60 60 { 61 61 char *path = agpio->resource_source.string_ptr; 62 62 struct acpi_device *adev; ··· 71 71 if (!adev) 72 72 return -ENODEV; 73 73 74 - *table_entry = GPIO_LOOKUP(acpi_dev_name(adev), agpio->pin_table[0], func, gpio_flags); 74 + *table_entry = GPIO_LOOKUP(acpi_dev_name(adev), agpio->pin_table[0], con_id, gpio_flags); 75 75 76 76 return 0; 77 77 } 78 78 79 79 static int skl_int3472_map_gpio_to_sensor(struct int3472_discrete_device *int3472, 80 80 struct acpi_resource_gpio *agpio, 81 - const char *func, unsigned long gpio_flags) 81 + const char *con_id, unsigned long gpio_flags) 82 82 { 83 83 int ret; 84 84 ··· 88 88 } 89 89 90 90 ret = skl_int3472_fill_gpiod_lookup(&int3472->gpios.table[int3472->n_sensor_gpios], 91 - agpio, func, gpio_flags); 91 + agpio, con_id, gpio_flags); 92 92 if (ret) 93 93 return ret; 94 94 ··· 101 101 static struct gpio_desc * 102 102 skl_int3472_gpiod_get_from_temp_lookup(struct int3472_discrete_device *int3472, 103 103 struct acpi_resource_gpio *agpio, 104 - const char *func, unsigned long gpio_flags) 104 + const char *con_id, unsigned long gpio_flags) 105 105 { 106 106 struct gpio_desc *desc; 107 107 int ret; ··· 112 112 return ERR_PTR(-ENOMEM); 113 113 114 114 lookup->dev_id = dev_name(int3472->dev); 115 - ret = skl_int3472_fill_gpiod_lookup(&lookup->table[0], agpio, func, gpio_flags); 115 + ret = skl_int3472_fill_gpiod_lookup(&lookup->table[0], agpio, con_id, gpio_flags); 116 116 if (ret) 117 117 return ERR_PTR(ret); 118 118 119 119 gpiod_add_lookup_table(lookup); 120 - desc = devm_gpiod_get(int3472->dev, func, GPIOD_OUT_LOW); 120 + desc = devm_gpiod_get(int3472->dev, con_id, GPIOD_OUT_LOW); 121 121 gpiod_remove_lookup_table(lookup); 122 122 123 123 return desc; ··· 129 129 * @hid: The ACPI HID of the device without the instance number e.g. INT347E 130 130 * @type_from: The GPIO type from ACPI ?SDT 131 131 * @type_to: The assigned GPIO type, typically same as @type_from 132 - * @func: The function, e.g. "enable" 132 + * @con_id: The name of the GPIO for the device 133 133 * @polarity_low: GPIO_ACTIVE_LOW true if the @polarity_low is true, 134 134 * GPIO_ACTIVE_HIGH otherwise 135 135 */ ··· 138 138 u8 type_from; 139 139 u8 type_to; 140 140 bool polarity_low; 141 - const char *func; 141 + const char *con_id; 142 142 }; 143 143 144 144 static const struct int3472_gpio_map int3472_gpio_map[] = { 145 145 { "INT347E", INT3472_GPIO_TYPE_RESET, INT3472_GPIO_TYPE_RESET, false, "enable" }, 146 146 }; 147 147 148 - static void int3472_get_func_and_polarity(struct acpi_device *adev, u8 *type, 149 - const char **func, unsigned long *gpio_flags) 148 + static void int3472_get_con_id_and_polarity(struct acpi_device *adev, u8 *type, 149 + const char **con_id, unsigned long *gpio_flags) 150 150 { 151 151 unsigned int i; 152 152 ··· 165 165 *type = int3472_gpio_map[i].type_to; 166 166 *gpio_flags = int3472_gpio_map[i].polarity_low ? 167 167 GPIO_ACTIVE_LOW : GPIO_ACTIVE_HIGH; 168 - *func = int3472_gpio_map[i].func; 168 + *con_id = int3472_gpio_map[i].con_id; 169 169 return; 170 170 } 171 171 172 172 switch (*type) { 173 173 case INT3472_GPIO_TYPE_RESET: 174 - *func = "reset"; 174 + *con_id = "reset"; 175 175 *gpio_flags = GPIO_ACTIVE_LOW; 176 176 break; 177 177 case INT3472_GPIO_TYPE_POWERDOWN: 178 - *func = "powerdown"; 178 + *con_id = "powerdown"; 179 179 *gpio_flags = GPIO_ACTIVE_LOW; 180 180 break; 181 181 case INT3472_GPIO_TYPE_CLK_ENABLE: 182 - *func = "clk-enable"; 182 + *con_id = "clk-enable"; 183 183 *gpio_flags = GPIO_ACTIVE_HIGH; 184 184 break; 185 185 case INT3472_GPIO_TYPE_PRIVACY_LED: 186 - *func = "privacy-led"; 186 + *con_id = "privacy-led"; 187 187 *gpio_flags = GPIO_ACTIVE_HIGH; 188 188 break; 189 189 case INT3472_GPIO_TYPE_POWER_ENABLE: 190 - *func = "power-enable"; 190 + *con_id = "power-enable"; 191 191 *gpio_flags = GPIO_ACTIVE_HIGH; 192 192 break; 193 193 default: 194 - *func = "unknown"; 194 + *con_id = "unknown"; 195 195 *gpio_flags = GPIO_ACTIVE_HIGH; 196 196 break; 197 197 } ··· 238 238 union acpi_object *obj; 239 239 struct gpio_desc *gpio; 240 240 const char *err_msg; 241 - const char *func; 241 + const char *con_id; 242 242 unsigned long gpio_flags; 243 243 int ret; 244 244 ··· 262 262 263 263 type = FIELD_GET(INT3472_GPIO_DSM_TYPE, obj->integer.value); 264 264 265 - int3472_get_func_and_polarity(int3472->sensor, &type, &func, &gpio_flags); 265 + int3472_get_con_id_and_polarity(int3472->sensor, &type, &con_id, &gpio_flags); 266 266 267 267 pin = FIELD_GET(INT3472_GPIO_DSM_PIN, obj->integer.value); 268 268 /* Pin field is not really used under Windows and wraps around at 8 bits */ 269 269 if (pin != (agpio->pin_table[0] & 0xff)) 270 270 dev_dbg(int3472->dev, FW_BUG "%s %s pin number mismatch _DSM %d resource %d\n", 271 - func, agpio->resource_source.string_ptr, pin, agpio->pin_table[0]); 271 + con_id, agpio->resource_source.string_ptr, pin, agpio->pin_table[0]); 272 272 273 273 active_value = FIELD_GET(INT3472_GPIO_DSM_SENSOR_ON_VAL, obj->integer.value); 274 274 if (!active_value) 275 275 gpio_flags ^= GPIO_ACTIVE_LOW; 276 276 277 - dev_dbg(int3472->dev, "%s %s pin %d active-%s\n", func, 277 + dev_dbg(int3472->dev, "%s %s pin %d active-%s\n", con_id, 278 278 agpio->resource_source.string_ptr, agpio->pin_table[0], 279 279 str_high_low(gpio_flags == GPIO_ACTIVE_HIGH)); 280 280 281 281 switch (type) { 282 282 case INT3472_GPIO_TYPE_RESET: 283 283 case INT3472_GPIO_TYPE_POWERDOWN: 284 - ret = skl_int3472_map_gpio_to_sensor(int3472, agpio, func, gpio_flags); 284 + ret = skl_int3472_map_gpio_to_sensor(int3472, agpio, con_id, gpio_flags); 285 285 if (ret) 286 286 err_msg = "Failed to map GPIO pin to sensor\n"; 287 287 ··· 289 289 case INT3472_GPIO_TYPE_CLK_ENABLE: 290 290 case INT3472_GPIO_TYPE_PRIVACY_LED: 291 291 case INT3472_GPIO_TYPE_POWER_ENABLE: 292 - gpio = skl_int3472_gpiod_get_from_temp_lookup(int3472, agpio, func, gpio_flags); 292 + gpio = skl_int3472_gpiod_get_from_temp_lookup(int3472, agpio, con_id, gpio_flags); 293 293 if (IS_ERR(gpio)) { 294 294 ret = PTR_ERR(gpio); 295 295 err_msg = "Failed to get GPIO\n";
+1 -1
drivers/platform/x86/intel/pmc/Makefile
··· 4 4 # 5 5 6 6 intel_pmc_core-y := core.o core_ssram.o spt.o cnp.o \ 7 - icl.o tgl.o adl.o mtl.o arl.o lnl.o 7 + icl.o tgl.o adl.o mtl.o arl.o lnl.o ptl.o 8 8 obj-$(CONFIG_INTEL_PMC_CORE) += intel_pmc_core.o 9 9 intel_pmc_core_pltdrv-y := pltdrv.o 10 10 obj-$(CONFIG_INTEL_PMC_CORE) += intel_pmc_core_pltdrv.o
+22 -34
drivers/platform/x86/intel/pmc/adl.c
··· 11 11 #include "core.h" 12 12 13 13 /* Alder Lake: PGD PFET Enable Ack Status Register(s) bitmap */ 14 - const struct pmc_bit_map adl_pfear_map[] = { 14 + static const struct pmc_bit_map adl_pfear_map[] = { 15 15 {"SPI/eSPI", BIT(2)}, 16 16 {"XHCI", BIT(3)}, 17 17 {"SPA", BIT(4)}, ··· 54 54 {} 55 55 }; 56 56 57 - const struct pmc_bit_map *ext_adl_pfear_map[] = { 57 + static const struct pmc_bit_map *ext_adl_pfear_map[] = { 58 58 /* 59 59 * Check intel_pmc_core_ids[] users of cnp_reg_map for 60 60 * a list of core SoCs using this. ··· 63 63 NULL 64 64 }; 65 65 66 - const struct pmc_bit_map adl_ltr_show_map[] = { 66 + static const struct pmc_bit_map adl_ltr_show_map[] = { 67 67 {"SOUTHPORT_A", CNP_PMC_LTR_SPA}, 68 68 {"SOUTHPORT_B", CNP_PMC_LTR_SPB}, 69 69 {"SATA", CNP_PMC_LTR_SATA}, ··· 100 100 {} 101 101 }; 102 102 103 - const struct pmc_bit_map adl_clocksource_status_map[] = { 103 + static const struct pmc_bit_map adl_clocksource_status_map[] = { 104 104 {"CLKPART1_OFF_STS", BIT(0)}, 105 105 {"CLKPART2_OFF_STS", BIT(1)}, 106 106 {"CLKPART3_OFF_STS", BIT(2)}, ··· 128 128 {} 129 129 }; 130 130 131 - const struct pmc_bit_map adl_power_gating_status_0_map[] = { 131 + static const struct pmc_bit_map adl_power_gating_status_0_map[] = { 132 132 {"PMC_PGD0_PG_STS", BIT(0)}, 133 133 {"DMI_PGD0_PG_STS", BIT(1)}, 134 134 {"ESPISPI_PGD0_PG_STS", BIT(2)}, ··· 158 158 {} 159 159 }; 160 160 161 - const struct pmc_bit_map adl_power_gating_status_1_map[] = { 161 + static const struct pmc_bit_map adl_power_gating_status_1_map[] = { 162 162 {"USBR0_PGD0_PG_STS", BIT(0)}, 163 163 {"SMT1_PGD0_PG_STS", BIT(2)}, 164 164 {"CSMERTC_PGD0_PG_STS", BIT(6)}, ··· 170 170 {} 171 171 }; 172 172 173 - const struct pmc_bit_map adl_power_gating_status_2_map[] = { 173 + static const struct pmc_bit_map adl_power_gating_status_2_map[] = { 174 174 {"THC0_PGD0_PG_STS", BIT(7)}, 175 175 {"THC1_PGD0_PG_STS", BIT(8)}, 176 176 {"SPF_PGD0_PG_STS", BIT(14)}, 177 177 {} 178 178 }; 179 179 180 - const struct pmc_bit_map adl_d3_status_0_map[] = { 180 + static const struct pmc_bit_map adl_d3_status_0_map[] = { 181 181 {"ISH_D3_STS", BIT(2)}, 182 182 {"LPSS_D3_STS", BIT(3)}, 183 183 {"XDCI_D3_STS", BIT(4)}, ··· 193 193 {} 194 194 }; 195 195 196 - const struct pmc_bit_map adl_d3_status_1_map[] = { 196 + static const struct pmc_bit_map adl_d3_status_1_map[] = { 197 197 {"GBE_D3_STS", BIT(19)}, 198 198 {"CNVI_D3_STS", BIT(27)}, 199 199 {} 200 200 }; 201 201 202 - const struct pmc_bit_map adl_d3_status_2_map[] = { 202 + static const struct pmc_bit_map adl_d3_status_2_map[] = { 203 203 {"CSMERTC_D3_STS", BIT(1)}, 204 204 {"CSE_D3_STS", BIT(4)}, 205 205 {"KVMCC_D3_STS", BIT(5)}, ··· 210 210 {} 211 211 }; 212 212 213 - const struct pmc_bit_map adl_d3_status_3_map[] = { 213 + static const struct pmc_bit_map adl_d3_status_3_map[] = { 214 214 {"THC0_D3_STS", BIT(14)}, 215 215 {"THC1_D3_STS", BIT(15)}, 216 216 {} 217 217 }; 218 218 219 - const struct pmc_bit_map adl_vnn_req_status_0_map[] = { 219 + static const struct pmc_bit_map adl_vnn_req_status_0_map[] = { 220 220 {"ISH_VNN_REQ_STS", BIT(2)}, 221 221 {"ESPISPI_VNN_REQ_STS", BIT(18)}, 222 222 {"DSP_VNN_REQ_STS", BIT(19)}, 223 223 {} 224 224 }; 225 225 226 - const struct pmc_bit_map adl_vnn_req_status_1_map[] = { 226 + static const struct pmc_bit_map adl_vnn_req_status_1_map[] = { 227 227 {"NPK_VNN_REQ_STS", BIT(4)}, 228 228 {"EXI_VNN_REQ_STS", BIT(9)}, 229 229 {"GBE_VNN_REQ_STS", BIT(19)}, ··· 232 232 {} 233 233 }; 234 234 235 - const struct pmc_bit_map adl_vnn_req_status_2_map[] = { 235 + static const struct pmc_bit_map adl_vnn_req_status_2_map[] = { 236 236 {"CSMERTC_VNN_REQ_STS", BIT(1)}, 237 237 {"CSE_VNN_REQ_STS", BIT(4)}, 238 238 {"SMT1_VNN_REQ_STS", BIT(8)}, ··· 245 245 {} 246 246 }; 247 247 248 - const struct pmc_bit_map adl_vnn_req_status_3_map[] = { 248 + static const struct pmc_bit_map adl_vnn_req_status_3_map[] = { 249 249 {"GPIOCOM5_VNN_REQ_STS", BIT(11)}, 250 250 {} 251 251 }; 252 252 253 - const struct pmc_bit_map adl_vnn_misc_status_map[] = { 253 + static const struct pmc_bit_map adl_vnn_misc_status_map[] = { 254 254 {"CPU_C10_REQ_STS", BIT(0)}, 255 255 {"PCIe_LPM_En_REQ_STS", BIT(3)}, 256 256 {"ITH_REQ_STS", BIT(5)}, ··· 265 265 {} 266 266 }; 267 267 268 - const struct pmc_bit_map *adl_lpm_maps[] = { 268 + static const struct pmc_bit_map *adl_lpm_maps[] = { 269 269 adl_clocksource_status_map, 270 270 adl_power_gating_status_0_map, 271 271 adl_power_gating_status_1_map, ··· 311 311 .pson_residency_counter_step = TGL_PSON_RES_COUNTER_STEP, 312 312 }; 313 313 314 - int adl_core_init(struct pmc_dev *pmcdev) 315 - { 316 - struct pmc *pmc = pmcdev->pmcs[PMC_IDX_MAIN]; 317 - int ret; 318 - 319 - pmcdev->suspend = cnl_suspend; 320 - pmcdev->resume = cnl_resume; 321 - 322 - pmc->map = &adl_reg_map; 323 - ret = get_primary_reg_base(pmc); 324 - if (ret) 325 - return ret; 326 - 327 - pmc_core_get_low_power_modes(pmcdev); 328 - 329 - return 0; 330 - } 314 + struct pmc_dev_info adl_pmc_dev = { 315 + .map = &adl_reg_map, 316 + .suspend = cnl_suspend, 317 + .resume = cnl_resume, 318 + };
+78 -63
drivers/platform/x86/intel/pmc/arl.c
··· 16 16 #define IOEP_LPM_REQ_GUID 0x5077612 17 17 #define SOCS_LPM_REQ_GUID 0x8478657 18 18 #define PCHS_LPM_REQ_GUID 0x9684572 19 + #define SOCM_LPM_REQ_GUID 0x2625030 19 20 20 21 static const u8 ARL_LPM_REG_INDEX[] = {0, 4, 5, 6, 8, 9, 10, 11, 12, 13, 14, 15, 16, 20}; 21 22 22 - const struct pmc_bit_map arl_socs_ltr_show_map[] = { 23 + static const struct pmc_bit_map arl_socs_ltr_show_map[] = { 23 24 {"SOUTHPORT_A", CNP_PMC_LTR_SPA}, 24 25 {"SOUTHPORT_B", CNP_PMC_LTR_SPB}, 25 26 {"SATA", CNP_PMC_LTR_SATA}, ··· 60 59 {} 61 60 }; 62 61 63 - const struct pmc_bit_map arl_socs_clocksource_status_map[] = { 62 + static const struct pmc_bit_map arl_socs_clocksource_status_map[] = { 64 63 {"AON2_OFF_STS", BIT(0)}, 65 64 {"AON3_OFF_STS", BIT(1)}, 66 65 {"AON4_OFF_STS", BIT(2)}, ··· 88 87 {} 89 88 }; 90 89 91 - const struct pmc_bit_map arl_socs_power_gating_status_0_map[] = { 90 + static const struct pmc_bit_map arl_socs_power_gating_status_0_map[] = { 92 91 {"PMC_PGD0_PG_STS", BIT(0)}, 93 92 {"DMI_PGD0_PG_STS", BIT(1)}, 94 93 {"ESPISPI_PGD0_PG_STS", BIT(2)}, ··· 124 123 {} 125 124 }; 126 125 127 - const struct pmc_bit_map arl_socs_power_gating_status_1_map[] = { 126 + static const struct pmc_bit_map arl_socs_power_gating_status_1_map[] = { 128 127 {"USBR0_PGD0_PG_STS", BIT(0)}, 129 128 {"SUSRAM_PGD0_PG_STS", BIT(1)}, 130 129 {"SMT1_PGD0_PG_STS", BIT(2)}, ··· 160 159 {} 161 160 }; 162 161 163 - const struct pmc_bit_map arl_socs_power_gating_status_2_map[] = { 162 + static const struct pmc_bit_map arl_socs_power_gating_status_2_map[] = { 164 163 {"PSF8_PGD0_PG_STS", BIT(0)}, 165 164 {"FIA_PGD0_PG_STS", BIT(1)}, 166 165 {"SOC_D2D_PGD3_PG_STS", BIT(2)}, ··· 188 187 {} 189 188 }; 190 189 191 - const struct pmc_bit_map arl_socs_d3_status_2_map[] = { 190 + static const struct pmc_bit_map arl_socs_d3_status_2_map[] = { 192 191 {"CSMERTC_D3_STS", BIT(1)}, 193 192 {"SUSRAM_D3_STS", BIT(2)}, 194 193 {"CSE_D3_STS", BIT(4)}, ··· 207 206 {} 208 207 }; 209 208 210 - const struct pmc_bit_map arl_socs_d3_status_3_map[] = { 209 + static const struct pmc_bit_map arl_socs_d3_status_3_map[] = { 211 210 {"GBETSN_D3_STS", BIT(13)}, 212 211 {"THC0_D3_STS", BIT(14)}, 213 212 {"THC1_D3_STS", BIT(15)}, ··· 215 214 {} 216 215 }; 217 216 218 - const struct pmc_bit_map arl_socs_vnn_req_status_3_map[] = { 217 + static const struct pmc_bit_map arl_socs_vnn_req_status_3_map[] = { 219 218 {"DTS0_VNN_REQ_STS", BIT(7)}, 220 219 {"GPIOCOM5_VNN_REQ_STS", BIT(11)}, 221 220 {} 222 221 }; 223 222 224 - const struct pmc_bit_map *arl_socs_lpm_maps[] = { 223 + static const struct pmc_bit_map *arl_socs_lpm_maps[] = { 225 224 arl_socs_clocksource_status_map, 226 225 arl_socs_power_gating_status_0_map, 227 226 arl_socs_power_gating_status_1_map, ··· 239 238 NULL 240 239 }; 241 240 242 - const struct pmc_bit_map arl_socs_pfear_map[] = { 241 + static const struct pmc_bit_map arl_socs_pfear_map[] = { 243 242 {"RSVD64", BIT(0)}, 244 243 {"RSVD65", BIT(1)}, 245 244 {"RSVD66", BIT(2)}, ··· 250 249 {} 251 250 }; 252 251 253 - const struct pmc_bit_map *ext_arl_socs_pfear_map[] = { 252 + static const struct pmc_bit_map *ext_arl_socs_pfear_map[] = { 254 253 mtl_socm_pfear_map, 255 254 arl_socs_pfear_map, 256 255 NULL 257 256 }; 258 257 259 - const struct pmc_reg_map arl_socs_reg_map = { 258 + static const struct pmc_reg_map arl_socs_reg_map = { 260 259 .pfear_sts = ext_arl_socs_pfear_map, 261 260 .ppfear_buckets = ARL_SOCS_PPFEAR_NUM_ENTRIES, 262 261 .pm_read_disable_bit = CNP_PMC_READ_DISABLE_BIT, ··· 284 283 .pson_residency_counter_step = TGL_PSON_RES_COUNTER_STEP, 285 284 }; 286 285 287 - const struct pmc_bit_map arl_pchs_ltr_show_map[] = { 286 + static const struct pmc_bit_map arl_pchs_ltr_show_map[] = { 288 287 {"SOUTHPORT_A", CNP_PMC_LTR_SPA}, 289 288 {"SOUTHPORT_B", CNP_PMC_LTR_SPB}, 290 289 {"SATA", CNP_PMC_LTR_SATA}, ··· 324 323 {} 325 324 }; 326 325 327 - const struct pmc_bit_map arl_pchs_clocksource_status_map[] = { 326 + static const struct pmc_bit_map arl_pchs_clocksource_status_map[] = { 328 327 {"AON2_OFF_STS", BIT(0)}, 329 328 {"AON3_OFF_STS", BIT(1)}, 330 329 {"AON4_OFF_STS", BIT(2)}, ··· 359 358 {} 360 359 }; 361 360 362 - const struct pmc_bit_map arl_pchs_power_gating_status_0_map[] = { 361 + static const struct pmc_bit_map arl_pchs_power_gating_status_0_map[] = { 363 362 {"PMC_PGD0_PG_STS", BIT(0)}, 364 363 {"DMI_PGD0_PG_STS", BIT(1)}, 365 364 {"ESPISPI_PGD0_PG_STS", BIT(2)}, ··· 395 394 {} 396 395 }; 397 396 398 - const struct pmc_bit_map arl_pchs_power_gating_status_1_map[] = { 397 + static const struct pmc_bit_map arl_pchs_power_gating_status_1_map[] = { 399 398 {"USBR0_PGD0_PG_STS", BIT(0)}, 400 399 {"SUSRAM_PGD0_PG_STS", BIT(1)}, 401 400 {"SMT1_PGD0_PG_STS", BIT(2)}, ··· 431 430 {} 432 431 }; 433 432 434 - const struct pmc_bit_map arl_pchs_power_gating_status_2_map[] = { 433 + static const struct pmc_bit_map arl_pchs_power_gating_status_2_map[] = { 435 434 {"U3FPW2_PGD0_PG_STS", BIT(0)}, 436 435 {"FIA_PGD0_PG_STS", BIT(1)}, 437 436 {"FIACPCB_X_PGD0_PG_STS", BIT(2)}, ··· 458 457 {} 459 458 }; 460 459 461 - const struct pmc_bit_map arl_pchs_d3_status_0_map[] = { 460 + static const struct pmc_bit_map arl_pchs_d3_status_0_map[] = { 462 461 {"SPF_D3_STS", BIT(0)}, 463 462 {"LPSS_D3_STS", BIT(3)}, 464 463 {"XDCI_D3_STS", BIT(4)}, ··· 475 474 {} 476 475 }; 477 476 478 - const struct pmc_bit_map arl_pchs_d3_status_1_map[] = { 477 + static const struct pmc_bit_map arl_pchs_d3_status_1_map[] = { 479 478 {"GBETSN1_D3_STS", BIT(14)}, 480 479 {"GBE_D3_STS", BIT(19)}, 481 480 {"ITSS_D3_STS", BIT(23)}, ··· 484 483 {} 485 484 }; 486 485 487 - const struct pmc_bit_map arl_pchs_d3_status_2_map[] = { 486 + static const struct pmc_bit_map arl_pchs_d3_status_2_map[] = { 488 487 {"CSMERTC_D3_STS", BIT(1)}, 489 488 {"SUSRAM_D3_STS", BIT(2)}, 490 489 {"CSE_D3_STS", BIT(4)}, ··· 505 504 {} 506 505 }; 507 506 508 - const struct pmc_bit_map arl_pchs_d3_status_3_map[] = { 507 + static const struct pmc_bit_map arl_pchs_d3_status_3_map[] = { 509 508 {"ESE_D3_STS", BIT(3)}, 510 509 {"GBETSN_D3_STS", BIT(13)}, 511 510 {"THC0_D3_STS", BIT(14)}, ··· 514 513 {} 515 514 }; 516 515 517 - const struct pmc_bit_map arl_pchs_vnn_req_status_0_map[] = { 516 + static const struct pmc_bit_map arl_pchs_vnn_req_status_0_map[] = { 518 517 {"FIA_VNN_REQ_STS", BIT(17)}, 519 518 {"ESPISPI_VNN_REQ_STS", BIT(18)}, 520 519 {} 521 520 }; 522 521 523 - const struct pmc_bit_map arl_pchs_vnn_req_status_1_map[] = { 522 + static const struct pmc_bit_map arl_pchs_vnn_req_status_1_map[] = { 524 523 {"NPK_VNN_REQ_STS", BIT(4)}, 525 524 {"DFXAGG_VNN_REQ_STS", BIT(8)}, 526 525 {"EXI_VNN_REQ_STS", BIT(9)}, ··· 531 530 {} 532 531 }; 533 532 534 - const struct pmc_bit_map arl_pchs_vnn_req_status_2_map[] = { 533 + static const struct pmc_bit_map arl_pchs_vnn_req_status_2_map[] = { 535 534 {"FIA2_VNN_REQ_STS", BIT(0)}, 536 535 {"CSMERTC_VNN_REQ_STS", BIT(1)}, 537 536 {"CSE_VNN_REQ_STS", BIT(4)}, ··· 549 548 {} 550 549 }; 551 550 552 - const struct pmc_bit_map arl_pchs_vnn_req_status_3_map[] = { 551 + static const struct pmc_bit_map arl_pchs_vnn_req_status_3_map[] = { 553 552 {"ESE_VNN_REQ_STS", BIT(3)}, 554 553 {"DTS0_VNN_REQ_STS", BIT(7)}, 555 554 {"GPIOCOM5_VNN_REQ_STS", BIT(11)}, ··· 557 556 {} 558 557 }; 559 558 560 - const struct pmc_bit_map arl_pchs_vnn_misc_status_map[] = { 559 + static const struct pmc_bit_map arl_pchs_vnn_misc_status_map[] = { 561 560 {"CPU_C10_REQ_STS", BIT(0)}, 562 561 {"TS_OFF_REQ_STS", BIT(1)}, 563 562 {"PNDE_MET_REQ_STS", BIT(2)}, ··· 587 586 {} 588 587 }; 589 588 590 - const struct pmc_bit_map arl_pchs_signal_status_map[] = { 589 + static const struct pmc_bit_map arl_pchs_signal_status_map[] = { 591 590 {"LSX_Wake0_STS", BIT(0)}, 592 591 {"LSX_Wake1_STS", BIT(1)}, 593 592 {"LSX_Wake2_STS", BIT(2)}, ··· 607 606 {} 608 607 }; 609 608 610 - const struct pmc_bit_map *arl_pchs_lpm_maps[] = { 609 + static const struct pmc_bit_map *arl_pchs_lpm_maps[] = { 611 610 arl_pchs_clocksource_status_map, 612 611 arl_pchs_power_gating_status_0_map, 613 612 arl_pchs_power_gating_status_1_map, ··· 625 624 NULL 626 625 }; 627 626 628 - const struct pmc_reg_map arl_pchs_reg_map = { 627 + static const struct pmc_reg_map arl_pchs_reg_map = { 629 628 .pfear_sts = ext_arl_socs_pfear_map, 630 629 .ppfear_buckets = ARL_SOCS_PPFEAR_NUM_ENTRIES, 631 630 .pm_read_disable_bit = CNP_PMC_READ_DISABLE_BIT, ··· 651 650 .etr3_offset = ETR3_OFFSET, 652 651 }; 653 652 653 + #define PMC_DEVID_SOCM 0x777f 654 654 #define PMC_DEVID_SOCS 0xae7f 655 655 #define PMC_DEVID_IOEP 0x7ecf 656 656 #define PMC_DEVID_PCHS 0x7f27 ··· 671 669 .devid = PMC_DEVID_PCHS, 672 670 .map = &arl_pchs_reg_map, 673 671 }, 672 + { 673 + .guid = SOCM_LPM_REQ_GUID, 674 + .devid = PMC_DEVID_SOCM, 675 + .map = &mtl_socm_reg_map, 676 + }, 674 677 {} 675 678 }; 676 679 677 680 #define ARL_NPU_PCI_DEV 0xad1d 678 681 #define ARL_GNA_PCI_DEV 0xae4c 682 + #define ARL_H_GNA_PCI_DEV 0x774c 679 683 /* 680 684 * Set power state of select devices that do not have drivers to D3 681 685 * so that they do not block Package C entry. ··· 692 684 pmc_core_set_device_d3(ARL_GNA_PCI_DEV); 693 685 } 694 686 687 + static void arl_h_d3_fixup(void) 688 + { 689 + pmc_core_set_device_d3(ARL_NPU_PCI_DEV); 690 + pmc_core_set_device_d3(ARL_H_GNA_PCI_DEV); 691 + } 692 + 695 693 static int arl_resume(struct pmc_dev *pmcdev) 696 694 { 697 695 arl_d3_fixup(); ··· 705 691 return cnl_resume(pmcdev); 706 692 } 707 693 708 - int arl_core_init(struct pmc_dev *pmcdev) 694 + static int arl_h_resume(struct pmc_dev *pmcdev) 709 695 { 710 - struct pmc *pmc = pmcdev->pmcs[PMC_IDX_SOC]; 711 - int ret; 712 - int func = 0; 713 - bool ssram_init = true; 696 + arl_h_d3_fixup(); 714 697 715 - arl_d3_fixup(); 716 - pmcdev->suspend = cnl_suspend; 717 - pmcdev->resume = arl_resume; 718 - pmcdev->regmap_list = arl_pmc_info_list; 719 - 720 - /* 721 - * If ssram init fails use legacy method to at least get the 722 - * primary PMC 723 - */ 724 - ret = pmc_core_ssram_init(pmcdev, func); 725 - if (ret) { 726 - ssram_init = false; 727 - pmc->map = &arl_socs_reg_map; 728 - 729 - ret = get_primary_reg_base(pmc); 730 - if (ret) 731 - return ret; 732 - } 733 - 734 - pmc_core_get_low_power_modes(pmcdev); 735 - pmc_core_punit_pmt_init(pmcdev, ARL_PMT_DMU_GUID); 736 - 737 - if (ssram_init) { 738 - ret = pmc_core_ssram_get_lpm_reqs(pmcdev); 739 - if (ret) 740 - return ret; 741 - } 742 - 743 - return 0; 698 + return cnl_resume(pmcdev); 744 699 } 700 + 701 + static int arl_core_init(struct pmc_dev *pmcdev, struct pmc_dev_info *pmc_dev_info) 702 + { 703 + arl_d3_fixup(); 704 + return generic_core_init(pmcdev, pmc_dev_info); 705 + } 706 + 707 + static int arl_h_core_init(struct pmc_dev *pmcdev, struct pmc_dev_info *pmc_dev_info) 708 + { 709 + arl_h_d3_fixup(); 710 + return generic_core_init(pmcdev, pmc_dev_info); 711 + } 712 + 713 + struct pmc_dev_info arl_pmc_dev = { 714 + .pci_func = 0, 715 + .dmu_guid = ARL_PMT_DMU_GUID, 716 + .regmap_list = arl_pmc_info_list, 717 + .map = &arl_socs_reg_map, 718 + .suspend = cnl_suspend, 719 + .resume = arl_resume, 720 + .init = arl_core_init, 721 + }; 722 + 723 + struct pmc_dev_info arl_h_pmc_dev = { 724 + .pci_func = 2, 725 + .dmu_guid = ARL_PMT_DMU_GUID, 726 + .regmap_list = arl_pmc_info_list, 727 + .map = &mtl_socm_reg_map, 728 + .suspend = cnl_suspend, 729 + .resume = arl_h_resume, 730 + .init = arl_h_core_init, 731 + };
+9 -20
drivers/platform/x86/intel/pmc/cnp.c
··· 88 88 {} 89 89 }; 90 90 91 - const struct pmc_bit_map *ext_cnp_pfear_map[] = { 91 + static const struct pmc_bit_map *ext_cnp_pfear_map[] = { 92 92 /* 93 93 * Check intel_pmc_core_ids[] users of cnp_reg_map for 94 94 * a list of core SoCs using this. ··· 97 97 NULL 98 98 }; 99 99 100 - const struct pmc_bit_map cnp_slps0_dbg0_map[] = { 100 + static const struct pmc_bit_map cnp_slps0_dbg0_map[] = { 101 101 {"AUDIO_D3", BIT(0)}, 102 102 {"OTG_D3", BIT(1)}, 103 103 {"XHCI_D3", BIT(2)}, ··· 110 110 {} 111 111 }; 112 112 113 - const struct pmc_bit_map cnp_slps0_dbg1_map[] = { 113 + static const struct pmc_bit_map cnp_slps0_dbg1_map[] = { 114 114 {"SDIO_PLL_OFF", BIT(0)}, 115 115 {"USB2_PLL_OFF", BIT(1)}, 116 116 {"AUDIO_PLL_OFF", BIT(2)}, ··· 127 127 {} 128 128 }; 129 129 130 - const struct pmc_bit_map cnp_slps0_dbg2_map[] = { 130 + static const struct pmc_bit_map cnp_slps0_dbg2_map[] = { 131 131 {"MPHY_CORE_GATED", BIT(0)}, 132 132 {"CSME_GATED", BIT(1)}, 133 133 {"USB2_SUS_GATED", BIT(2)}, ··· 274 274 return pmc_core_resume_common(pmcdev); 275 275 } 276 276 277 - int cnp_core_init(struct pmc_dev *pmcdev) 278 - { 279 - struct pmc *pmc = pmcdev->pmcs[PMC_IDX_MAIN]; 280 - int ret; 277 + struct pmc_dev_info cnp_pmc_dev = { 278 + .map = &cnp_reg_map, 279 + .suspend = cnl_suspend, 280 + .resume = cnl_resume, 281 + }; 281 282 282 - pmcdev->suspend = cnl_suspend; 283 - pmcdev->resume = cnl_resume; 284 - 285 - pmc->map = &cnp_reg_map; 286 - ret = get_primary_reg_base(pmc); 287 - if (ret) 288 - return ret; 289 - 290 - pmc_core_get_low_power_modes(pmcdev); 291 - 292 - return 0; 293 - }
+76 -39
drivers/platform/x86/intel/pmc/core.c
··· 1345 1345 } 1346 1346 } 1347 1347 1348 + /* 1349 + * When supported, ssram init is used to achieve all available PMCs. 1350 + * If ssram init fails, this function uses legacy method to at least get the 1351 + * primary PMC. 1352 + */ 1353 + int generic_core_init(struct pmc_dev *pmcdev, struct pmc_dev_info *pmc_dev_info) 1354 + { 1355 + struct pmc *pmc = pmcdev->pmcs[PMC_IDX_MAIN]; 1356 + bool ssram; 1357 + int ret; 1358 + 1359 + pmcdev->suspend = pmc_dev_info->suspend; 1360 + pmcdev->resume = pmc_dev_info->resume; 1361 + 1362 + ssram = pmc_dev_info->regmap_list != NULL; 1363 + if (ssram) { 1364 + pmcdev->regmap_list = pmc_dev_info->regmap_list; 1365 + ret = pmc_core_ssram_init(pmcdev, pmc_dev_info->pci_func); 1366 + if (ret) { 1367 + dev_warn(&pmcdev->pdev->dev, 1368 + "ssram init failed, %d, using legacy init\n", ret); 1369 + ssram = false; 1370 + } 1371 + } 1372 + 1373 + if (!ssram) { 1374 + pmc->map = pmc_dev_info->map; 1375 + ret = get_primary_reg_base(pmc); 1376 + if (ret) 1377 + return ret; 1378 + } 1379 + 1380 + pmc_core_get_low_power_modes(pmcdev); 1381 + if (pmc_dev_info->dmu_guid) 1382 + pmc_core_punit_pmt_init(pmcdev, pmc_dev_info->dmu_guid); 1383 + 1384 + if (ssram) 1385 + return pmc_core_ssram_get_lpm_reqs(pmcdev); 1386 + 1387 + return 0; 1388 + } 1389 + 1348 1390 static const struct x86_cpu_id intel_pmc_core_ids[] = { 1349 - X86_MATCH_VFM(INTEL_SKYLAKE_L, spt_core_init), 1350 - X86_MATCH_VFM(INTEL_SKYLAKE, spt_core_init), 1351 - X86_MATCH_VFM(INTEL_KABYLAKE_L, spt_core_init), 1352 - X86_MATCH_VFM(INTEL_KABYLAKE, spt_core_init), 1353 - X86_MATCH_VFM(INTEL_CANNONLAKE_L, cnp_core_init), 1354 - X86_MATCH_VFM(INTEL_ICELAKE_L, icl_core_init), 1355 - X86_MATCH_VFM(INTEL_ICELAKE_NNPI, icl_core_init), 1356 - X86_MATCH_VFM(INTEL_COMETLAKE, cnp_core_init), 1357 - X86_MATCH_VFM(INTEL_COMETLAKE_L, cnp_core_init), 1358 - X86_MATCH_VFM(INTEL_TIGERLAKE_L, tgl_l_core_init), 1359 - X86_MATCH_VFM(INTEL_TIGERLAKE, tgl_core_init), 1360 - X86_MATCH_VFM(INTEL_ATOM_TREMONT, tgl_l_core_init), 1361 - X86_MATCH_VFM(INTEL_ATOM_TREMONT_L, icl_core_init), 1362 - X86_MATCH_VFM(INTEL_ROCKETLAKE, tgl_core_init), 1363 - X86_MATCH_VFM(INTEL_ALDERLAKE_L, tgl_l_core_init), 1364 - X86_MATCH_VFM(INTEL_ATOM_GRACEMONT, tgl_l_core_init), 1365 - X86_MATCH_VFM(INTEL_ALDERLAKE, adl_core_init), 1366 - X86_MATCH_VFM(INTEL_RAPTORLAKE_P, tgl_l_core_init), 1367 - X86_MATCH_VFM(INTEL_RAPTORLAKE, adl_core_init), 1368 - X86_MATCH_VFM(INTEL_RAPTORLAKE_S, adl_core_init), 1369 - X86_MATCH_VFM(INTEL_METEORLAKE_L, mtl_core_init), 1370 - X86_MATCH_VFM(INTEL_ARROWLAKE, arl_core_init), 1371 - X86_MATCH_VFM(INTEL_LUNARLAKE_M, lnl_core_init), 1391 + X86_MATCH_VFM(INTEL_SKYLAKE_L, &spt_pmc_dev), 1392 + X86_MATCH_VFM(INTEL_SKYLAKE, &spt_pmc_dev), 1393 + X86_MATCH_VFM(INTEL_KABYLAKE_L, &spt_pmc_dev), 1394 + X86_MATCH_VFM(INTEL_KABYLAKE, &spt_pmc_dev), 1395 + X86_MATCH_VFM(INTEL_CANNONLAKE_L, &cnp_pmc_dev), 1396 + X86_MATCH_VFM(INTEL_ICELAKE_L, &icl_pmc_dev), 1397 + X86_MATCH_VFM(INTEL_ICELAKE_NNPI, &icl_pmc_dev), 1398 + X86_MATCH_VFM(INTEL_COMETLAKE, &cnp_pmc_dev), 1399 + X86_MATCH_VFM(INTEL_COMETLAKE_L, &cnp_pmc_dev), 1400 + X86_MATCH_VFM(INTEL_TIGERLAKE_L, &tgl_l_pmc_dev), 1401 + X86_MATCH_VFM(INTEL_TIGERLAKE, &tgl_pmc_dev), 1402 + X86_MATCH_VFM(INTEL_ATOM_TREMONT, &tgl_l_pmc_dev), 1403 + X86_MATCH_VFM(INTEL_ATOM_TREMONT_L, &icl_pmc_dev), 1404 + X86_MATCH_VFM(INTEL_ROCKETLAKE, &tgl_pmc_dev), 1405 + X86_MATCH_VFM(INTEL_ALDERLAKE_L, &tgl_l_pmc_dev), 1406 + X86_MATCH_VFM(INTEL_ATOM_GRACEMONT, &tgl_l_pmc_dev), 1407 + X86_MATCH_VFM(INTEL_ALDERLAKE, &adl_pmc_dev), 1408 + X86_MATCH_VFM(INTEL_RAPTORLAKE_P, &tgl_l_pmc_dev), 1409 + X86_MATCH_VFM(INTEL_RAPTORLAKE, &adl_pmc_dev), 1410 + X86_MATCH_VFM(INTEL_RAPTORLAKE_S, &adl_pmc_dev), 1411 + X86_MATCH_VFM(INTEL_METEORLAKE_L, &mtl_pmc_dev), 1412 + X86_MATCH_VFM(INTEL_ARROWLAKE, &arl_pmc_dev), 1413 + X86_MATCH_VFM(INTEL_ARROWLAKE_H, &arl_h_pmc_dev), 1414 + X86_MATCH_VFM(INTEL_ARROWLAKE_U, &arl_h_pmc_dev), 1415 + X86_MATCH_VFM(INTEL_LUNARLAKE_M, &lnl_pmc_dev), 1416 + X86_MATCH_VFM(INTEL_PANTHERLAKE_L, &ptl_pmc_dev), 1372 1417 {} 1373 1418 }; 1374 1419 1375 1420 MODULE_DEVICE_TABLE(x86cpu, intel_pmc_core_ids); 1376 - 1377 - static const struct pci_device_id pmc_pci_ids[] = { 1378 - { PCI_VDEVICE(INTEL, SPT_PMC_PCI_DEVICE_ID) }, 1379 - { } 1380 - }; 1381 1421 1382 1422 /* 1383 1423 * This quirk can be used on those platforms where ··· 1492 1452 static bool device_initialized; 1493 1453 struct pmc_dev *pmcdev; 1494 1454 const struct x86_cpu_id *cpu_id; 1495 - int (*core_init)(struct pmc_dev *pmcdev); 1455 + struct pmc_dev_info *pmc_dev_info; 1496 1456 struct pmc *primary_pmc; 1497 1457 int ret; 1498 1458 ··· 1512 1472 if (!cpu_id) 1513 1473 return -ENODEV; 1514 1474 1515 - core_init = (int (*)(struct pmc_dev *))cpu_id->driver_data; 1475 + pmc_dev_info = (struct pmc_dev_info *)cpu_id->driver_data; 1516 1476 1517 1477 /* Primary PMC */ 1518 1478 primary_pmc = devm_kzalloc(&pdev->dev, sizeof(*primary_pmc), GFP_KERNEL); ··· 1529 1489 if (!pmcdev->pkgc_res_cnt) 1530 1490 return -ENOMEM; 1531 1491 1532 - /* 1533 - * Coffee Lake has CPU ID of Kaby Lake and Cannon Lake PCH. So here 1534 - * Sunrisepoint PCH regmap can't be used. Use Cannon Lake PCH regmap 1535 - * in this case. 1536 - */ 1537 - if (core_init == spt_core_init && !pci_dev_present(pmc_pci_ids)) 1538 - core_init = cnp_core_init; 1539 - 1540 1492 mutex_init(&pmcdev->lock); 1541 - ret = core_init(pmcdev); 1493 + 1494 + if (pmc_dev_info->init) 1495 + ret = pmc_dev_info->init(pmcdev, pmc_dev_info); 1496 + else 1497 + ret = generic_core_init(pmcdev, pmc_dev_info); 1498 + 1542 1499 if (ret) { 1543 1500 pmc_core_clean_structure(pdev); 1544 1501 return ret;
+50 -143
drivers/platform/x86/intel/pmc/core.h
··· 285 285 #define LNL_PPFEAR_NUM_ENTRIES 12 286 286 #define LNL_S0IX_BLOCKER_OFFSET 0x2004 287 287 288 + /* Panther Lake Power Management Controller register offsets */ 289 + #define PTL_LPM_NUM_MAPS 14 290 + #define PTL_PMC_LTR_SATA2 0x1B90 291 + #define PTL_PMC_LTR_PMC 0x1BA8 292 + #define PTL_PMC_LTR_CUR_ASLT 0x1C28 293 + #define PTL_PMC_LTR_CUR_PLT 0x1C2C 294 + #define PTL_PCD_PMC_MMIO_REG_LEN 0x31A8 295 + 288 296 extern const char *pmc_lpm_modes[]; 289 297 290 298 struct pmc_bit_map { ··· 438 430 439 431 enum pmc_index { 440 432 PMC_IDX_MAIN, 441 - PMC_IDX_SOC = PMC_IDX_MAIN, 442 433 PMC_IDX_IOE, 443 434 PMC_IDX_PCH, 444 435 PMC_IDX_MAX 445 436 }; 446 437 438 + /** 439 + * struct pmc_dev_info - Structure to keep PMC device info 440 + * @pci_func: Function number of the primary PMC 441 + * @dmu_guid: Die Management Unit GUID 442 + * @regmap_list: Pointer to a list of pmc_info structure that could be 443 + * available for the platform. When set, this field implies 444 + * SSRAM support. 445 + * @map: Pointer to a pmc_reg_map struct that contains platform 446 + * specific attributes of the primary PMC 447 + * @suspend: Function to perform platform specific suspend 448 + * @resume: Function to perform platform specific resume 449 + * @init: Function to perform platform specific init action 450 + */ 451 + struct pmc_dev_info { 452 + u8 pci_func; 453 + u32 dmu_guid; 454 + struct pmc_info *regmap_list; 455 + const struct pmc_reg_map *map; 456 + void (*suspend)(struct pmc_dev *pmcdev); 457 + int (*resume)(struct pmc_dev *pmcdev); 458 + int (*init)(struct pmc_dev *pmcdev, struct pmc_dev_info *pmc_dev_info); 459 + }; 460 + 447 461 extern const struct pmc_bit_map msr_map[]; 448 - extern const struct pmc_bit_map spt_pll_map[]; 449 - extern const struct pmc_bit_map spt_mphy_map[]; 450 - extern const struct pmc_bit_map spt_pfear_map[]; 451 - extern const struct pmc_bit_map *ext_spt_pfear_map[]; 452 - extern const struct pmc_bit_map spt_ltr_show_map[]; 453 - extern const struct pmc_reg_map spt_reg_map; 454 462 extern const struct pmc_bit_map cnp_pfear_map[]; 455 - extern const struct pmc_bit_map *ext_cnp_pfear_map[]; 456 - extern const struct pmc_bit_map cnp_slps0_dbg0_map[]; 457 - extern const struct pmc_bit_map cnp_slps0_dbg1_map[]; 458 - extern const struct pmc_bit_map cnp_slps0_dbg2_map[]; 459 463 extern const struct pmc_bit_map *cnp_slps0_dbg_maps[]; 460 464 extern const struct pmc_bit_map cnp_ltr_show_map[]; 461 465 extern const struct pmc_reg_map cnp_reg_map; 462 - extern const struct pmc_bit_map icl_pfear_map[]; 463 - extern const struct pmc_bit_map *ext_icl_pfear_map[]; 464 - extern const struct pmc_reg_map icl_reg_map; 465 - extern const struct pmc_bit_map tgl_pfear_map[]; 466 - extern const struct pmc_bit_map *ext_tgl_pfear_map[]; 467 - extern const struct pmc_bit_map tgl_clocksource_status_map[]; 468 - extern const struct pmc_bit_map tgl_power_gating_status_map[]; 469 - extern const struct pmc_bit_map tgl_d3_status_map[]; 470 - extern const struct pmc_bit_map tgl_vnn_req_status_map[]; 471 - extern const struct pmc_bit_map tgl_vnn_misc_status_map[]; 472 466 extern const struct pmc_bit_map tgl_signal_status_map[]; 473 - extern const struct pmc_bit_map *tgl_lpm_maps[]; 474 - extern const struct pmc_reg_map tgl_reg_map; 475 - extern const struct pmc_reg_map tgl_h_reg_map; 476 - extern const struct pmc_bit_map adl_pfear_map[]; 477 - extern const struct pmc_bit_map *ext_adl_pfear_map[]; 478 - extern const struct pmc_bit_map adl_ltr_show_map[]; 479 - extern const struct pmc_bit_map adl_clocksource_status_map[]; 480 - extern const struct pmc_bit_map adl_power_gating_status_0_map[]; 481 - extern const struct pmc_bit_map adl_power_gating_status_1_map[]; 482 - extern const struct pmc_bit_map adl_power_gating_status_2_map[]; 483 - extern const struct pmc_bit_map adl_d3_status_0_map[]; 484 - extern const struct pmc_bit_map adl_d3_status_1_map[]; 485 - extern const struct pmc_bit_map adl_d3_status_2_map[]; 486 - extern const struct pmc_bit_map adl_d3_status_3_map[]; 487 - extern const struct pmc_bit_map adl_vnn_req_status_0_map[]; 488 - extern const struct pmc_bit_map adl_vnn_req_status_1_map[]; 489 - extern const struct pmc_bit_map adl_vnn_req_status_2_map[]; 490 - extern const struct pmc_bit_map adl_vnn_req_status_3_map[]; 491 - extern const struct pmc_bit_map adl_vnn_misc_status_map[]; 492 - extern const struct pmc_bit_map *adl_lpm_maps[]; 493 467 extern const struct pmc_reg_map adl_reg_map; 494 468 extern const struct pmc_bit_map mtl_socm_pfear_map[]; 495 - extern const struct pmc_bit_map *ext_mtl_socm_pfear_map[]; 496 - extern const struct pmc_bit_map mtl_socm_ltr_show_map[]; 497 - extern const struct pmc_bit_map mtl_socm_clocksource_status_map[]; 498 - extern const struct pmc_bit_map mtl_socm_power_gating_status_0_map[]; 499 - extern const struct pmc_bit_map mtl_socm_power_gating_status_1_map[]; 500 - extern const struct pmc_bit_map mtl_socm_power_gating_status_2_map[]; 501 469 extern const struct pmc_bit_map mtl_socm_d3_status_0_map[]; 502 470 extern const struct pmc_bit_map mtl_socm_d3_status_1_map[]; 503 - extern const struct pmc_bit_map mtl_socm_d3_status_2_map[]; 504 - extern const struct pmc_bit_map mtl_socm_d3_status_3_map[]; 505 471 extern const struct pmc_bit_map mtl_socm_vnn_req_status_0_map[]; 506 472 extern const struct pmc_bit_map mtl_socm_vnn_req_status_1_map[]; 507 473 extern const struct pmc_bit_map mtl_socm_vnn_req_status_2_map[]; 508 - extern const struct pmc_bit_map mtl_socm_vnn_req_status_3_map[]; 509 474 extern const struct pmc_bit_map mtl_socm_vnn_misc_status_map[]; 510 475 extern const struct pmc_bit_map mtl_socm_signal_status_map[]; 511 - extern const struct pmc_bit_map *mtl_socm_lpm_maps[]; 512 476 extern const struct pmc_reg_map mtl_socm_reg_map; 513 - extern const struct pmc_bit_map mtl_ioep_pfear_map[]; 514 - extern const struct pmc_bit_map *ext_mtl_ioep_pfear_map[]; 515 - extern const struct pmc_bit_map mtl_ioep_ltr_show_map[]; 516 - extern const struct pmc_bit_map mtl_ioep_clocksource_status_map[]; 517 - extern const struct pmc_bit_map mtl_ioep_power_gating_status_0_map[]; 518 - extern const struct pmc_bit_map mtl_ioep_power_gating_status_1_map[]; 519 - extern const struct pmc_bit_map mtl_ioep_power_gating_status_2_map[]; 520 - extern const struct pmc_bit_map mtl_ioep_d3_status_0_map[]; 521 - extern const struct pmc_bit_map mtl_ioep_d3_status_1_map[]; 522 - extern const struct pmc_bit_map mtl_ioep_d3_status_2_map[]; 523 - extern const struct pmc_bit_map mtl_ioep_d3_status_3_map[]; 524 - extern const struct pmc_bit_map mtl_ioep_vnn_req_status_0_map[]; 525 - extern const struct pmc_bit_map mtl_ioep_vnn_req_status_1_map[]; 526 - extern const struct pmc_bit_map mtl_ioep_vnn_req_status_2_map[]; 527 - extern const struct pmc_bit_map mtl_ioep_vnn_req_status_3_map[]; 528 - extern const struct pmc_bit_map mtl_ioep_vnn_misc_status_map[]; 529 - extern const struct pmc_bit_map *mtl_ioep_lpm_maps[]; 530 477 extern const struct pmc_reg_map mtl_ioep_reg_map; 531 - extern const struct pmc_bit_map mtl_ioem_pfear_map[]; 532 - extern const struct pmc_bit_map *ext_mtl_ioem_pfear_map[]; 533 - extern const struct pmc_bit_map mtl_ioem_power_gating_status_1_map[]; 534 - extern const struct pmc_bit_map mtl_ioem_vnn_req_status_1_map[]; 535 - extern const struct pmc_bit_map *mtl_ioem_lpm_maps[]; 536 - extern const struct pmc_reg_map mtl_ioem_reg_map; 537 - extern const struct pmc_reg_map lnl_socm_reg_map; 538 478 539 - /* LNL */ 540 - extern const struct pmc_bit_map lnl_ltr_show_map[]; 541 - extern const struct pmc_bit_map lnl_clocksource_status_map[]; 542 - extern const struct pmc_bit_map lnl_power_gating_status_0_map[]; 543 - extern const struct pmc_bit_map lnl_power_gating_status_1_map[]; 544 - extern const struct pmc_bit_map lnl_power_gating_status_2_map[]; 545 - extern const struct pmc_bit_map lnl_d3_status_0_map[]; 546 - extern const struct pmc_bit_map lnl_d3_status_1_map[]; 547 - extern const struct pmc_bit_map lnl_d3_status_2_map[]; 548 - extern const struct pmc_bit_map lnl_d3_status_3_map[]; 549 - extern const struct pmc_bit_map lnl_vnn_req_status_0_map[]; 550 - extern const struct pmc_bit_map lnl_vnn_req_status_1_map[]; 551 - extern const struct pmc_bit_map lnl_vnn_req_status_2_map[]; 552 - extern const struct pmc_bit_map lnl_vnn_req_status_3_map[]; 553 - extern const struct pmc_bit_map lnl_vnn_misc_status_map[]; 554 - extern const struct pmc_bit_map *lnl_lpm_maps[]; 555 - extern const struct pmc_bit_map *lnl_blk_maps[]; 556 - extern const struct pmc_bit_map lnl_pfear_map[]; 557 - extern const struct pmc_bit_map *ext_lnl_pfear_map[]; 558 - extern const struct pmc_bit_map lnl_signal_status_map[]; 559 - 560 - /* ARL */ 561 - extern const struct pmc_bit_map arl_socs_ltr_show_map[]; 562 - extern const struct pmc_bit_map arl_socs_clocksource_status_map[]; 563 - extern const struct pmc_bit_map arl_socs_power_gating_status_0_map[]; 564 - extern const struct pmc_bit_map arl_socs_power_gating_status_1_map[]; 565 - extern const struct pmc_bit_map arl_socs_power_gating_status_2_map[]; 566 - extern const struct pmc_bit_map arl_socs_d3_status_2_map[]; 567 - extern const struct pmc_bit_map arl_socs_d3_status_3_map[]; 568 - extern const struct pmc_bit_map arl_socs_vnn_req_status_3_map[]; 569 - extern const struct pmc_bit_map *arl_socs_lpm_maps[]; 570 - extern const struct pmc_bit_map arl_socs_pfear_map[]; 571 - extern const struct pmc_bit_map *ext_arl_socs_pfear_map[]; 572 - extern const struct pmc_reg_map arl_socs_reg_map; 573 - extern const struct pmc_bit_map arl_pchs_ltr_show_map[]; 574 - extern const struct pmc_bit_map arl_pchs_clocksource_status_map[]; 575 - extern const struct pmc_bit_map arl_pchs_power_gating_status_0_map[]; 576 - extern const struct pmc_bit_map arl_pchs_power_gating_status_1_map[]; 577 - extern const struct pmc_bit_map arl_pchs_power_gating_status_2_map[]; 578 - extern const struct pmc_bit_map arl_pchs_d3_status_0_map[]; 579 - extern const struct pmc_bit_map arl_pchs_d3_status_1_map[]; 580 - extern const struct pmc_bit_map arl_pchs_d3_status_2_map[]; 581 - extern const struct pmc_bit_map arl_pchs_d3_status_3_map[]; 582 - extern const struct pmc_bit_map arl_pchs_vnn_req_status_0_map[]; 583 - extern const struct pmc_bit_map arl_pchs_vnn_req_status_1_map[]; 584 - extern const struct pmc_bit_map arl_pchs_vnn_req_status_2_map[]; 585 - extern const struct pmc_bit_map arl_pchs_vnn_req_status_3_map[]; 586 - extern const struct pmc_bit_map arl_pchs_vnn_misc_status_map[]; 587 - extern const struct pmc_bit_map arl_pchs_signal_status_map[]; 588 - extern const struct pmc_bit_map *arl_pchs_lpm_maps[]; 589 - extern const struct pmc_reg_map arl_pchs_reg_map; 590 - 591 - extern void pmc_core_get_tgl_lpm_reqs(struct platform_device *pdev); 592 - extern int pmc_core_ssram_get_lpm_reqs(struct pmc_dev *pmcdev); 479 + void pmc_core_get_tgl_lpm_reqs(struct platform_device *pdev); 480 + int pmc_core_ssram_get_lpm_reqs(struct pmc_dev *pmcdev); 593 481 int pmc_core_send_ltr_ignore(struct pmc_dev *pmcdev, u32 value, int ignore); 594 482 595 483 int pmc_core_resume_common(struct pmc_dev *pmcdev); 596 484 int get_primary_reg_base(struct pmc *pmc); 597 - extern void pmc_core_get_low_power_modes(struct pmc_dev *pmcdev); 598 - extern void pmc_core_punit_pmt_init(struct pmc_dev *pmcdev, u32 guid); 599 - extern void pmc_core_set_device_d3(unsigned int device); 485 + void pmc_core_get_low_power_modes(struct pmc_dev *pmcdev); 486 + void pmc_core_punit_pmt_init(struct pmc_dev *pmcdev, u32 guid); 487 + void pmc_core_set_device_d3(unsigned int device); 600 488 601 - extern int pmc_core_ssram_init(struct pmc_dev *pmcdev, int func); 489 + int pmc_core_ssram_init(struct pmc_dev *pmcdev, int func); 602 490 603 - int spt_core_init(struct pmc_dev *pmcdev); 604 - int cnp_core_init(struct pmc_dev *pmcdev); 605 - int icl_core_init(struct pmc_dev *pmcdev); 606 - int tgl_core_init(struct pmc_dev *pmcdev); 607 - int tgl_l_core_init(struct pmc_dev *pmcdev); 608 - int tgl_core_generic_init(struct pmc_dev *pmcdev, int pch_tp); 609 - int adl_core_init(struct pmc_dev *pmcdev); 610 - int mtl_core_init(struct pmc_dev *pmcdev); 611 - int arl_core_init(struct pmc_dev *pmcdev); 612 - int lnl_core_init(struct pmc_dev *pmcdev); 491 + int generic_core_init(struct pmc_dev *pmcdev, struct pmc_dev_info *pmc_dev_info); 492 + 493 + extern struct pmc_dev_info spt_pmc_dev; 494 + extern struct pmc_dev_info cnp_pmc_dev; 495 + extern struct pmc_dev_info icl_pmc_dev; 496 + extern struct pmc_dev_info tgl_l_pmc_dev; 497 + extern struct pmc_dev_info tgl_pmc_dev; 498 + extern struct pmc_dev_info adl_pmc_dev; 499 + extern struct pmc_dev_info mtl_pmc_dev; 500 + extern struct pmc_dev_info arl_pmc_dev; 501 + extern struct pmc_dev_info arl_h_pmc_dev; 502 + extern struct pmc_dev_info lnl_pmc_dev; 503 + extern struct pmc_dev_info ptl_pmc_dev; 613 504 614 505 void cnl_suspend(struct pmc_dev *pmcdev); 615 506 int cnl_resume(struct pmc_dev *pmcdev);
+6 -18
drivers/platform/x86/intel/pmc/icl.c
··· 10 10 11 11 #include "core.h" 12 12 13 - const struct pmc_bit_map icl_pfear_map[] = { 13 + static const struct pmc_bit_map icl_pfear_map[] = { 14 14 {"RES_65", BIT(0)}, 15 15 {"RES_66", BIT(1)}, 16 16 {"RES_67", BIT(2)}, ··· 22 22 {} 23 23 }; 24 24 25 - const struct pmc_bit_map *ext_icl_pfear_map[] = { 25 + static const struct pmc_bit_map *ext_icl_pfear_map[] = { 26 26 /* 27 27 * Check intel_pmc_core_ids[] users of icl_reg_map for 28 28 * a list of core SoCs using this. ··· 32 32 NULL 33 33 }; 34 34 35 - const struct pmc_reg_map icl_reg_map = { 35 + static const struct pmc_reg_map icl_reg_map = { 36 36 .pfear_sts = ext_icl_pfear_map, 37 37 .slp_s0_offset = CNP_PMC_SLP_S0_RES_COUNTER_OFFSET, 38 38 .slp_s0_res_counter_step = ICL_PMC_SLP_S0_RES_COUNTER_STEP, ··· 50 50 .etr3_offset = ETR3_OFFSET, 51 51 }; 52 52 53 - int icl_core_init(struct pmc_dev *pmcdev) 54 - { 55 - struct pmc *pmc = pmcdev->pmcs[PMC_IDX_MAIN]; 56 - int ret; 57 - 58 - pmc->map = &icl_reg_map; 59 - 60 - ret = get_primary_reg_base(pmc); 61 - if (ret) 62 - return ret; 63 - 64 - pmc_core_get_low_power_modes(pmcdev); 65 - 66 - return ret; 67 - } 53 + struct pmc_dev_info icl_pmc_dev = { 54 + .map = &icl_reg_map, 55 + };
+30 -37
drivers/platform/x86/intel/pmc/lnl.c
··· 13 13 14 14 #include "core.h" 15 15 16 - const struct pmc_bit_map lnl_ltr_show_map[] = { 16 + static const struct pmc_bit_map lnl_ltr_show_map[] = { 17 17 {"SOUTHPORT_A", CNP_PMC_LTR_SPA}, 18 18 {"SOUTHPORT_B", CNP_PMC_LTR_SPB}, 19 19 {"SATA", CNP_PMC_LTR_SATA}, ··· 55 55 {} 56 56 }; 57 57 58 - const struct pmc_bit_map lnl_power_gating_status_0_map[] = { 58 + static const struct pmc_bit_map lnl_power_gating_status_0_map[] = { 59 59 {"PMC_PGD0_PG_STS", BIT(0), 0}, 60 60 {"FUSE_OSSE_PGD0_PG_STS", BIT(1), 0}, 61 61 {"ESPISPI_PGD0_PG_STS", BIT(2), 0}, ··· 91 91 {} 92 92 }; 93 93 94 - const struct pmc_bit_map lnl_power_gating_status_1_map[] = { 94 + static const struct pmc_bit_map lnl_power_gating_status_1_map[] = { 95 95 {"USBR0_PGD0_PG_STS", BIT(0), 1}, 96 96 {"SUSRAM_PGD0_PG_STS", BIT(1), 1}, 97 97 {"SMT1_PGD0_PG_STS", BIT(2), 1}, ··· 127 127 {} 128 128 }; 129 129 130 - const struct pmc_bit_map lnl_power_gating_status_2_map[] = { 130 + static const struct pmc_bit_map lnl_power_gating_status_2_map[] = { 131 131 {"PSF8_PGD0_PG_STS", BIT(0), 0}, 132 132 {"SBR16B2_PGD0_PG_STS", BIT(1), 0}, 133 133 {"D2D_IPU_PGD0_PG_STS", BIT(2), 1}, ··· 163 163 {} 164 164 }; 165 165 166 - const struct pmc_bit_map lnl_d3_status_0_map[] = { 166 + static const struct pmc_bit_map lnl_d3_status_0_map[] = { 167 167 {"LPSS_D3_STS", BIT(3), 1}, 168 168 {"XDCI_D3_STS", BIT(4), 1}, 169 169 {"XHCI_D3_STS", BIT(5), 1}, ··· 175 175 {} 176 176 }; 177 177 178 - const struct pmc_bit_map lnl_d3_status_1_map[] = { 178 + static const struct pmc_bit_map lnl_d3_status_1_map[] = { 179 179 {"OSSE_SMT1_D3_STS", BIT(7), 0}, 180 180 {"GBE_D3_STS", BIT(19), 0}, 181 181 {"ITSS_D3_STS", BIT(23), 0}, ··· 185 185 {} 186 186 }; 187 187 188 - const struct pmc_bit_map lnl_d3_status_2_map[] = { 188 + static const struct pmc_bit_map lnl_d3_status_2_map[] = { 189 189 {"ESE_D3_STS", BIT(0), 0}, 190 190 {"CSMERTC_D3_STS", BIT(1), 0}, 191 191 {"SUSRAM_D3_STS", BIT(2), 0}, ··· 205 205 {} 206 206 }; 207 207 208 - const struct pmc_bit_map lnl_d3_status_3_map[] = { 208 + static const struct pmc_bit_map lnl_d3_status_3_map[] = { 209 209 {"THC0_D3_STS", BIT(14), 1}, 210 210 {"THC1_D3_STS", BIT(15), 1}, 211 211 {"OSSE_SMT3_D3_STS", BIT(21), 0}, ··· 213 213 {} 214 214 }; 215 215 216 - const struct pmc_bit_map lnl_vnn_req_status_0_map[] = { 216 + static const struct pmc_bit_map lnl_vnn_req_status_0_map[] = { 217 217 {"LPSS_VNN_REQ_STS", BIT(3), 1}, 218 218 {"OSSE_VNN_REQ_STS", BIT(15), 1}, 219 219 {"ESPISPI_VNN_REQ_STS", BIT(18), 1}, 220 220 {} 221 221 }; 222 222 223 - const struct pmc_bit_map lnl_vnn_req_status_1_map[] = { 223 + static const struct pmc_bit_map lnl_vnn_req_status_1_map[] = { 224 224 {"NPK_VNN_REQ_STS", BIT(4), 1}, 225 225 {"OSSE_SMT1_VNN_REQ_STS", BIT(7), 1}, 226 226 {"DFXAGG_VNN_REQ_STS", BIT(8), 0}, ··· 232 232 {} 233 233 }; 234 234 235 - const struct pmc_bit_map lnl_vnn_req_status_2_map[] = { 235 + static const struct pmc_bit_map lnl_vnn_req_status_2_map[] = { 236 236 {"eSE_VNN_REQ_STS", BIT(0), 1}, 237 237 {"CSMERTC_VNN_REQ_STS", BIT(1), 1}, 238 238 {"CSE_VNN_REQ_STS", BIT(4), 1}, ··· 249 249 {} 250 250 }; 251 251 252 - const struct pmc_bit_map lnl_vnn_req_status_3_map[] = { 252 + static const struct pmc_bit_map lnl_vnn_req_status_3_map[] = { 253 253 {"DISP_SHIM_VNN_REQ_STS", BIT(2), 0}, 254 254 {"DTS0_VNN_REQ_STS", BIT(7), 0}, 255 255 {"GPIOCOM5_VNN_REQ_STS", BIT(11), 2}, 256 256 {} 257 257 }; 258 258 259 - const struct pmc_bit_map lnl_vnn_misc_status_map[] = { 259 + static const struct pmc_bit_map lnl_vnn_misc_status_map[] = { 260 260 {"CPU_C10_REQ_STS", BIT(0), 0}, 261 261 {"TS_OFF_REQ_STS", BIT(1), 0}, 262 262 {"PNDE_MET_REQ_STS", BIT(2), 1}, ··· 292 292 {} 293 293 }; 294 294 295 - const struct pmc_bit_map lnl_clocksource_status_map[] = { 295 + static const struct pmc_bit_map lnl_clocksource_status_map[] = { 296 296 {"AON2_OFF_STS", BIT(0), 0}, 297 297 {"AON3_OFF_STS", BIT(1), 1}, 298 298 {"AON4_OFF_STS", BIT(2), 1}, ··· 317 317 {} 318 318 }; 319 319 320 - const struct pmc_bit_map lnl_signal_status_map[] = { 320 + static const struct pmc_bit_map lnl_signal_status_map[] = { 321 321 {"LSX_Wake0_STS", BIT(0), 0}, 322 322 {"LSX_Wake1_STS", BIT(1), 0}, 323 323 {"LSX_Wake2_STS", BIT(2), 0}, ··· 337 337 {} 338 338 }; 339 339 340 - const struct pmc_bit_map lnl_rsc_status_map[] = { 340 + static const struct pmc_bit_map lnl_rsc_status_map[] = { 341 341 {"Memory", 0, 1}, 342 342 {"PSF0", 0, 1}, 343 343 {"PSF4", 0, 1}, ··· 349 349 {} 350 350 }; 351 351 352 - const struct pmc_bit_map *lnl_lpm_maps[] = { 352 + static const struct pmc_bit_map *lnl_lpm_maps[] = { 353 353 lnl_clocksource_status_map, 354 354 lnl_power_gating_status_0_map, 355 355 lnl_power_gating_status_1_map, ··· 367 367 NULL 368 368 }; 369 369 370 - const struct pmc_bit_map *lnl_blk_maps[] = { 370 + static const struct pmc_bit_map *lnl_blk_maps[] = { 371 371 lnl_power_gating_status_0_map, 372 372 lnl_power_gating_status_1_map, 373 373 lnl_power_gating_status_2_map, ··· 386 386 NULL 387 387 }; 388 388 389 - const struct pmc_bit_map lnl_pfear_map[] = { 389 + static const struct pmc_bit_map lnl_pfear_map[] = { 390 390 {"PMC_0", BIT(0)}, 391 391 {"FUSE_OSSE", BIT(1)}, 392 392 {"ESPISPI", BIT(2)}, ··· 498 498 {} 499 499 }; 500 500 501 - const struct pmc_bit_map *ext_lnl_pfear_map[] = { 501 + static const struct pmc_bit_map *ext_lnl_pfear_map[] = { 502 502 lnl_pfear_map, 503 503 NULL 504 504 }; 505 505 506 - const struct pmc_reg_map lnl_socm_reg_map = { 506 + static const struct pmc_reg_map lnl_socm_reg_map = { 507 507 .pfear_sts = ext_lnl_pfear_map, 508 508 .slp_s0_offset = CNP_PMC_SLP_S0_RES_COUNTER_OFFSET, 509 509 .slp_s0_res_counter_step = TGL_PMC_SLP_S0_RES_COUNTER_STEP, ··· 550 550 return cnl_resume(pmcdev); 551 551 } 552 552 553 - int lnl_core_init(struct pmc_dev *pmcdev) 553 + static int lnl_core_init(struct pmc_dev *pmcdev, struct pmc_dev_info *pmc_dev_info) 554 554 { 555 - int ret; 556 - struct pmc *pmc = pmcdev->pmcs[PMC_IDX_SOC]; 557 - 558 555 lnl_d3_fixup(); 559 - 560 - pmcdev->suspend = cnl_suspend; 561 - pmcdev->resume = lnl_resume; 562 - 563 - pmc->map = &lnl_socm_reg_map; 564 - ret = get_primary_reg_base(pmc); 565 - if (ret) 566 - return ret; 567 - 568 - pmc_core_get_low_power_modes(pmcdev); 569 - 570 - return 0; 556 + return generic_core_init(pmcdev, pmc_dev_info); 571 557 } 558 + 559 + struct pmc_dev_info lnl_pmc_dev = { 560 + .map = &lnl_socm_reg_map, 561 + .suspend = cnl_suspend, 562 + .resume = lnl_resume, 563 + .init = lnl_core_init, 564 + };
+44 -65
drivers/platform/x86/intel/pmc/mtl.c
··· 102 102 {} 103 103 }; 104 104 105 - const struct pmc_bit_map *ext_mtl_socm_pfear_map[] = { 105 + static const struct pmc_bit_map *ext_mtl_socm_pfear_map[] = { 106 106 mtl_socm_pfear_map, 107 107 NULL 108 108 }; 109 109 110 - const struct pmc_bit_map mtl_socm_ltr_show_map[] = { 110 + static const struct pmc_bit_map mtl_socm_ltr_show_map[] = { 111 111 {"SOUTHPORT_A", CNP_PMC_LTR_SPA}, 112 112 {"SOUTHPORT_B", CNP_PMC_LTR_SPB}, 113 113 {"SATA", CNP_PMC_LTR_SATA}, ··· 141 141 {} 142 142 }; 143 143 144 - const struct pmc_bit_map mtl_socm_clocksource_status_map[] = { 144 + static const struct pmc_bit_map mtl_socm_clocksource_status_map[] = { 145 145 {"AON2_OFF_STS", BIT(0)}, 146 146 {"AON3_OFF_STS", BIT(1)}, 147 147 {"AON4_OFF_STS", BIT(2)}, ··· 167 167 {} 168 168 }; 169 169 170 - const struct pmc_bit_map mtl_socm_power_gating_status_0_map[] = { 170 + static const struct pmc_bit_map mtl_socm_power_gating_status_0_map[] = { 171 171 {"PMC_PGD0_PG_STS", BIT(0)}, 172 172 {"DMI_PGD0_PG_STS", BIT(1)}, 173 173 {"ESPISPI_PGD0_PG_STS", BIT(2)}, ··· 203 203 {} 204 204 }; 205 205 206 - const struct pmc_bit_map mtl_socm_power_gating_status_1_map[] = { 206 + static const struct pmc_bit_map mtl_socm_power_gating_status_1_map[] = { 207 207 {"USBR0_PGD0_PG_STS", BIT(0)}, 208 208 {"SUSRAM_PGD0_PG_STS", BIT(1)}, 209 209 {"SMT1_PGD0_PG_STS", BIT(2)}, ··· 239 239 {} 240 240 }; 241 241 242 - const struct pmc_bit_map mtl_socm_power_gating_status_2_map[] = { 242 + static const struct pmc_bit_map mtl_socm_power_gating_status_2_map[] = { 243 243 {"PSF8_PGD0_PG_STS", BIT(0)}, 244 244 {"FIA_PGD0_PG_STS", BIT(1)}, 245 245 {"SOC_D2D_PGD1_PG_STS", BIT(2)}, ··· 291 291 {} 292 292 }; 293 293 294 - const struct pmc_bit_map mtl_socm_d3_status_2_map[] = { 294 + static const struct pmc_bit_map mtl_socm_d3_status_2_map[] = { 295 295 {"GNA_D3_STS", BIT(0)}, 296 296 {"CSMERTC_D3_STS", BIT(1)}, 297 297 {"SUSRAM_D3_STS", BIT(2)}, ··· 310 310 {} 311 311 }; 312 312 313 - const struct pmc_bit_map mtl_socm_d3_status_3_map[] = { 313 + static const struct pmc_bit_map mtl_socm_d3_status_3_map[] = { 314 314 {"ESE_D3_STS", BIT(2)}, 315 315 {"GBETSN_D3_STS", BIT(13)}, 316 316 {"THC0_D3_STS", BIT(14)}, ··· 353 353 {} 354 354 }; 355 355 356 - const struct pmc_bit_map mtl_socm_vnn_req_status_3_map[] = { 356 + static const struct pmc_bit_map mtl_socm_vnn_req_status_3_map[] = { 357 357 {"ESE_VNN_REQ_STS", BIT(2)}, 358 358 {"DTS0_VNN_REQ_STS", BIT(7)}, 359 359 {"GPIOCOM5_VNN_REQ_STS", BIT(11)}, ··· 432 432 {} 433 433 }; 434 434 435 - const struct pmc_bit_map *mtl_socm_lpm_maps[] = { 435 + static const struct pmc_bit_map *mtl_socm_lpm_maps[] = { 436 436 mtl_socm_clocksource_status_map, 437 437 mtl_socm_power_gating_status_0_map, 438 438 mtl_socm_power_gating_status_1_map, ··· 476 476 .lpm_reg_index = MTL_LPM_REG_INDEX, 477 477 }; 478 478 479 - const struct pmc_bit_map mtl_ioep_pfear_map[] = { 479 + static const struct pmc_bit_map mtl_ioep_pfear_map[] = { 480 480 {"PMC_0", BIT(0)}, 481 481 {"OPI", BIT(1)}, 482 482 {"TCSS", BIT(2)}, ··· 563 563 {} 564 564 }; 565 565 566 - const struct pmc_bit_map *ext_mtl_ioep_pfear_map[] = { 566 + static const struct pmc_bit_map *ext_mtl_ioep_pfear_map[] = { 567 567 mtl_ioep_pfear_map, 568 568 NULL 569 569 }; 570 570 571 - const struct pmc_bit_map mtl_ioep_ltr_show_map[] = { 571 + static const struct pmc_bit_map mtl_ioep_ltr_show_map[] = { 572 572 {"SOUTHPORT_A", CNP_PMC_LTR_SPA}, 573 573 {"SOUTHPORT_B", CNP_PMC_LTR_SPB}, 574 574 {"SATA", CNP_PMC_LTR_SATA}, ··· 600 600 {} 601 601 }; 602 602 603 - const struct pmc_bit_map mtl_ioep_clocksource_status_map[] = { 603 + static const struct pmc_bit_map mtl_ioep_clocksource_status_map[] = { 604 604 {"AON2_OFF_STS", BIT(0)}, 605 605 {"AON3_OFF_STS", BIT(1)}, 606 606 {"AON4_OFF_STS", BIT(2)}, ··· 623 623 {} 624 624 }; 625 625 626 - const struct pmc_bit_map mtl_ioep_power_gating_status_0_map[] = { 626 + static const struct pmc_bit_map mtl_ioep_power_gating_status_0_map[] = { 627 627 {"PMC_PGD0_PG_STS", BIT(0)}, 628 628 {"DMI_PGD0_PG_STS", BIT(1)}, 629 629 {"TCSS_PGD0_PG_STS", BIT(2)}, ··· 650 650 {} 651 651 }; 652 652 653 - const struct pmc_bit_map mtl_ioep_power_gating_status_1_map[] = { 653 + static const struct pmc_bit_map mtl_ioep_power_gating_status_1_map[] = { 654 654 {"PSF9_PGD0_PG_STS", BIT(0)}, 655 655 {"MPFPW4_PGD0_PG_STS", BIT(1)}, 656 656 {"SBR0_PGD0_PG_STS", BIT(8)}, ··· 668 668 {} 669 669 }; 670 670 671 - const struct pmc_bit_map mtl_ioep_power_gating_status_2_map[] = { 671 + static const struct pmc_bit_map mtl_ioep_power_gating_status_2_map[] = { 672 672 {"FIA_PGD0_PG_STS", BIT(1)}, 673 673 {"FIA_P_PGD0_PG_STS", BIT(3)}, 674 674 {"TAM_PGD0_PG_STS", BIT(4)}, ··· 680 680 {} 681 681 }; 682 682 683 - const struct pmc_bit_map mtl_ioep_d3_status_0_map[] = { 683 + static const struct pmc_bit_map mtl_ioep_d3_status_0_map[] = { 684 684 {"SPF_D3_STS", BIT(0)}, 685 685 {"SPA_D3_STS", BIT(12)}, 686 686 {"SPB_D3_STS", BIT(13)}, ··· 691 691 {} 692 692 }; 693 693 694 - const struct pmc_bit_map mtl_ioep_d3_status_1_map[] = { 694 + static const struct pmc_bit_map mtl_ioep_d3_status_1_map[] = { 695 695 {"GBETSN1_D3_STS", BIT(14)}, 696 696 {"P2S_D3_STS", BIT(24)}, 697 697 {} 698 698 }; 699 699 700 - const struct pmc_bit_map mtl_ioep_d3_status_2_map[] = { 700 + static const struct pmc_bit_map mtl_ioep_d3_status_2_map[] = { 701 701 {} 702 702 }; 703 703 704 - const struct pmc_bit_map mtl_ioep_d3_status_3_map[] = { 704 + static const struct pmc_bit_map mtl_ioep_d3_status_3_map[] = { 705 705 {"GBETSN_D3_STS", BIT(13)}, 706 706 {"ACE_D3_STS", BIT(23)}, 707 707 {} 708 708 }; 709 709 710 - const struct pmc_bit_map mtl_ioep_vnn_req_status_0_map[] = { 710 + static const struct pmc_bit_map mtl_ioep_vnn_req_status_0_map[] = { 711 711 {"FIA_VNN_REQ_STS", BIT(17)}, 712 712 {} 713 713 }; 714 714 715 - const struct pmc_bit_map mtl_ioep_vnn_req_status_1_map[] = { 715 + static const struct pmc_bit_map mtl_ioep_vnn_req_status_1_map[] = { 716 716 {"DFXAGG_VNN_REQ_STS", BIT(8)}, 717 717 {} 718 718 }; 719 719 720 - const struct pmc_bit_map mtl_ioep_vnn_req_status_2_map[] = { 720 + static const struct pmc_bit_map mtl_ioep_vnn_req_status_2_map[] = { 721 721 {} 722 722 }; 723 723 724 - const struct pmc_bit_map mtl_ioep_vnn_req_status_3_map[] = { 724 + static const struct pmc_bit_map mtl_ioep_vnn_req_status_3_map[] = { 725 725 {"DTS0_VNN_REQ_STS", BIT(7)}, 726 726 {"DISP_VNN_REQ_STS", BIT(19)}, 727 727 {} 728 728 }; 729 729 730 - const struct pmc_bit_map mtl_ioep_vnn_misc_status_map[] = { 730 + static const struct pmc_bit_map mtl_ioep_vnn_misc_status_map[] = { 731 731 {"CPU_C10_REQ_STS", BIT(0)}, 732 732 {"TS_OFF_REQ_STS", BIT(1)}, 733 733 {"PNDE_MET_REQ_STS", BIT(2)}, ··· 762 762 {} 763 763 }; 764 764 765 - const struct pmc_bit_map *mtl_ioep_lpm_maps[] = { 765 + static const struct pmc_bit_map *mtl_ioep_lpm_maps[] = { 766 766 mtl_ioep_clocksource_status_map, 767 767 mtl_ioep_power_gating_status_0_map, 768 768 mtl_ioep_power_gating_status_1_map, ··· 800 800 .lpm_reg_index = MTL_LPM_REG_INDEX, 801 801 }; 802 802 803 - const struct pmc_bit_map mtl_ioem_pfear_map[] = { 803 + static const struct pmc_bit_map mtl_ioem_pfear_map[] = { 804 804 {"PMC_0", BIT(0)}, 805 805 {"OPI", BIT(1)}, 806 806 {"TCSS", BIT(2)}, ··· 887 887 {} 888 888 }; 889 889 890 - const struct pmc_bit_map *ext_mtl_ioem_pfear_map[] = { 890 + static const struct pmc_bit_map *ext_mtl_ioem_pfear_map[] = { 891 891 mtl_ioem_pfear_map, 892 892 NULL 893 893 }; 894 894 895 - const struct pmc_bit_map mtl_ioem_power_gating_status_1_map[] = { 895 + static const struct pmc_bit_map mtl_ioem_power_gating_status_1_map[] = { 896 896 {"PSF9_PGD0_PG_STS", BIT(0)}, 897 897 {"MPFPW4_PGD0_PG_STS", BIT(1)}, 898 898 {"SBR0_PGD0_PG_STS", BIT(8)}, ··· 909 909 {} 910 910 }; 911 911 912 - const struct pmc_bit_map *mtl_ioem_lpm_maps[] = { 912 + static const struct pmc_bit_map *mtl_ioem_lpm_maps[] = { 913 913 mtl_ioep_clocksource_status_map, 914 914 mtl_ioep_power_gating_status_0_map, 915 915 mtl_ioem_power_gating_status_1_map, ··· 927 927 NULL 928 928 }; 929 929 930 - const struct pmc_reg_map mtl_ioem_reg_map = { 930 + static const struct pmc_reg_map mtl_ioem_reg_map = { 931 931 .regmap_length = MTL_IOE_PMC_MMIO_REG_LEN, 932 932 .pfear_sts = ext_mtl_ioem_pfear_map, 933 933 .ppfear0_offset = CNP_PMC_HOST_PPFEAR0A, ··· 990 990 return cnl_resume(pmcdev); 991 991 } 992 992 993 - int mtl_core_init(struct pmc_dev *pmcdev) 993 + static int mtl_core_init(struct pmc_dev *pmcdev, struct pmc_dev_info *pmc_dev_info) 994 994 { 995 - struct pmc *pmc = pmcdev->pmcs[PMC_IDX_SOC]; 996 - int ret; 997 - int func = 2; 998 - bool ssram_init = true; 999 - 1000 995 mtl_d3_fixup(); 1001 - 1002 - pmcdev->suspend = cnl_suspend; 1003 - pmcdev->resume = mtl_resume; 1004 - pmcdev->regmap_list = mtl_pmc_info_list; 1005 - 1006 - /* 1007 - * If ssram init fails use legacy method to at least get the 1008 - * primary PMC 1009 - */ 1010 - ret = pmc_core_ssram_init(pmcdev, func); 1011 - if (ret) { 1012 - ssram_init = false; 1013 - dev_warn(&pmcdev->pdev->dev, 1014 - "ssram init failed, %d, using legacy init\n", ret); 1015 - pmc->map = &mtl_socm_reg_map; 1016 - ret = get_primary_reg_base(pmc); 1017 - if (ret) 1018 - return ret; 1019 - } 1020 - 1021 - pmc_core_get_low_power_modes(pmcdev); 1022 - pmc_core_punit_pmt_init(pmcdev, MTL_PMT_DMU_GUID); 1023 - 1024 - if (ssram_init) 1025 - return pmc_core_ssram_get_lpm_reqs(pmcdev); 1026 - 1027 - return 0; 996 + return generic_core_init(pmcdev, pmc_dev_info); 1028 997 } 998 + 999 + struct pmc_dev_info mtl_pmc_dev = { 1000 + .pci_func = 2, 1001 + .dmu_guid = MTL_PMT_DMU_GUID, 1002 + .regmap_list = mtl_pmc_info_list, 1003 + .map = &mtl_socm_reg_map, 1004 + .suspend = cnl_suspend, 1005 + .resume = mtl_resume, 1006 + .init = mtl_core_init, 1007 + };
+550
drivers/platform/x86/intel/pmc/ptl.c
··· 1 + // SPDX-License-Identifier: GPL-2.0 2 + /* 3 + * This file contains platform specific structure definitions 4 + * and init function used by Panther Lake PCH. 5 + * 6 + * Copyright (c) 2025, Intel Corporation. 7 + */ 8 + 9 + #include <linux/pci.h> 10 + 11 + #include "core.h" 12 + 13 + static const struct pmc_bit_map ptl_pcdp_pfear_map[] = { 14 + {"PMC_0", BIT(0)}, 15 + {"FUSE_OSSE", BIT(1)}, 16 + {"ESPISPI", BIT(2)}, 17 + {"XHCI", BIT(3)}, 18 + {"SPA", BIT(4)}, 19 + {"SPB", BIT(5)}, 20 + {"MPFPW2", BIT(6)}, 21 + {"GBE", BIT(7)}, 22 + 23 + {"SBR16B20", BIT(0)}, 24 + {"SBR8B20", BIT(1)}, 25 + {"SBR16B21", BIT(2)}, 26 + {"DBG_SBR16B", BIT(3)}, 27 + {"OSSE_HOTHAM", BIT(4)}, 28 + {"D2D_DISP_1", BIT(5)}, 29 + {"LPSS", BIT(6)}, 30 + {"LPC", BIT(7)}, 31 + 32 + {"SMB", BIT(0)}, 33 + {"ISH", BIT(1)}, 34 + {"SBR16B2", BIT(2)}, 35 + {"NPK_0", BIT(3)}, 36 + {"D2D_NOC_1", BIT(4)}, 37 + {"SBR8B2", BIT(5)}, 38 + {"FUSE", BIT(6)}, 39 + {"SBR16B0", BIT(7)}, 40 + 41 + {"PSF0", BIT(0)}, 42 + {"XDCI", BIT(1)}, 43 + {"EXI", BIT(2)}, 44 + {"CSE", BIT(3)}, 45 + {"KVMCC", BIT(4)}, 46 + {"PMT", BIT(5)}, 47 + {"CLINK", BIT(6)}, 48 + {"PTIO", BIT(7)}, 49 + 50 + {"USBR0", BIT(0)}, 51 + {"SUSRAM", BIT(1)}, 52 + {"SMT1", BIT(2)}, 53 + {"MPFPW1", BIT(3)}, 54 + {"SMS2", BIT(4)}, 55 + {"SMS1", BIT(5)}, 56 + {"CSMERTC", BIT(6)}, 57 + {"CSMEPSF", BIT(7)}, 58 + 59 + {"D2D_NOC_0", BIT(0)}, 60 + {"ESE", BIT(1)}, 61 + {"P2SB8B", BIT(2)}, 62 + {"SBR16B7", BIT(3)}, 63 + {"SBR16B3", BIT(4)}, 64 + {"OSSE_SMT1", BIT(5)}, 65 + {"D2D_DISP", BIT(6)}, 66 + {"DBG_SBR", BIT(7)}, 67 + 68 + {"U3FPW1", BIT(0)}, 69 + {"FIA_X", BIT(1)}, 70 + {"PSF4", BIT(2)}, 71 + {"CNVI", BIT(3)}, 72 + {"UFSX2", BIT(4)}, 73 + {"ENDBG", BIT(5)}, 74 + {"DBC", BIT(6)}, 75 + {"FIA_PG", BIT(7)}, 76 + 77 + {"D2D_IPU", BIT(0)}, 78 + {"NPK1", BIT(1)}, 79 + {"FIACPCB_X", BIT(2)}, 80 + {"SBR8B4", BIT(3)}, 81 + {"DBG_PSF", BIT(4)}, 82 + {"PSF6", BIT(5)}, 83 + {"UFSPW1", BIT(6)}, 84 + {"FIA_U", BIT(7)}, 85 + 86 + {"PSF8", BIT(0)}, 87 + {"SBR16B4", BIT(1)}, 88 + {"SBR16B5", BIT(2)}, 89 + {"FIACPCB_U", BIT(3)}, 90 + {"TAM", BIT(4)}, 91 + {"D2D_NOC_2", BIT(5)}, 92 + {"TBTLSX", BIT(6)}, 93 + {"THC0", BIT(7)}, 94 + 95 + {"THC1", BIT(0)}, 96 + {"PMC_1", BIT(1)}, 97 + {"SBR8B1", BIT(2)}, 98 + {"TCSS", BIT(3)}, 99 + {"DISP_PGA", BIT(4)}, 100 + {"SBR16B1", BIT(5)}, 101 + {"SBRG", BIT(6)}, 102 + {"PSF5", BIT(7)}, 103 + 104 + {"P2SB16B", BIT(0)}, 105 + {"ACE_0", BIT(1)}, 106 + {"ACE_1", BIT(2)}, 107 + {"ACE_2", BIT(3)}, 108 + {"ACE_3", BIT(4)}, 109 + {"ACE_4", BIT(5)}, 110 + {"ACE_5", BIT(6)}, 111 + {"ACE_6", BIT(7)}, 112 + 113 + {"ACE_7", BIT(0)}, 114 + {"ACE_8", BIT(1)}, 115 + {"ACE_9", BIT(2)}, 116 + {"ACE_10", BIT(3)}, 117 + {"FIACPCB_PG", BIT(4)}, 118 + {"SBR16B6", BIT(5)}, 119 + {"OSSE", BIT(6)}, 120 + {"SBR8B0", BIT(7)}, 121 + {} 122 + }; 123 + 124 + static const struct pmc_bit_map *ext_ptl_pcdp_pfear_map[] = { 125 + ptl_pcdp_pfear_map, 126 + NULL 127 + }; 128 + 129 + static const struct pmc_bit_map ptl_pcdp_ltr_show_map[] = { 130 + {"SOUTHPORT_A", CNP_PMC_LTR_SPA}, 131 + {"SOUTHPORT_B", CNP_PMC_LTR_SPB}, 132 + {"SATA", CNP_PMC_LTR_SATA}, 133 + {"GIGABIT_ETHERNET", CNP_PMC_LTR_GBE}, 134 + {"XHCI", CNP_PMC_LTR_XHCI}, 135 + {"SOUTHPORT_F", ADL_PMC_LTR_SPF}, 136 + {"ME", CNP_PMC_LTR_ME}, 137 + {"SATA1", CNP_PMC_LTR_EVA}, 138 + {"SOUTHPORT_C", CNP_PMC_LTR_SPC}, 139 + {"HD_AUDIO", CNP_PMC_LTR_AZ}, 140 + {"CNV", CNP_PMC_LTR_CNV}, 141 + {"LPSS", CNP_PMC_LTR_LPSS}, 142 + {"SOUTHPORT_D", CNP_PMC_LTR_SPD}, 143 + {"SOUTHPORT_E", CNP_PMC_LTR_SPE}, 144 + {"SATA2", PTL_PMC_LTR_SATA2}, 145 + {"ESPI", CNP_PMC_LTR_ESPI}, 146 + {"SCC", CNP_PMC_LTR_SCC}, 147 + {"ISH", CNP_PMC_LTR_ISH}, 148 + {"UFSX2", CNP_PMC_LTR_UFSX2}, 149 + {"EMMC", CNP_PMC_LTR_EMMC}, 150 + {"WIGIG", ICL_PMC_LTR_WIGIG}, 151 + {"THC0", TGL_PMC_LTR_THC0}, 152 + {"THC1", TGL_PMC_LTR_THC1}, 153 + {"SOUTHPORT_G", MTL_PMC_LTR_SPG}, 154 + {"ESE", MTL_PMC_LTR_ESE}, 155 + {"IOE_PMC", MTL_PMC_LTR_IOE_PMC}, 156 + {"DMI3", ARL_PMC_LTR_DMI3}, 157 + {"OSSE", LNL_PMC_LTR_OSSE}, 158 + 159 + /* Below two cannot be used for LTR_IGNORE */ 160 + {"CURRENT_PLATFORM", PTL_PMC_LTR_CUR_PLT}, 161 + {"AGGREGATED_SYSTEM", PTL_PMC_LTR_CUR_ASLT}, 162 + {} 163 + }; 164 + 165 + static const struct pmc_bit_map ptl_pcdp_clocksource_status_map[] = { 166 + {"AON2_OFF_STS", BIT(0), 1}, 167 + {"AON3_OFF_STS", BIT(1), 0}, 168 + {"AON4_OFF_STS", BIT(2), 1}, 169 + {"AON5_OFF_STS", BIT(3), 1}, 170 + {"AON1_OFF_STS", BIT(4), 0}, 171 + {"XTAL_LVM_OFF_STS", BIT(5), 0}, 172 + {"MPFPW1_0_PLL_OFF_STS", BIT(6), 1}, 173 + {"USB3_PLL_OFF_STS", BIT(8), 1}, 174 + {"AON3_SPL_OFF_STS", BIT(9), 1}, 175 + {"MPFPW2_0_PLL_OFF_STS", BIT(12), 1}, 176 + {"XTAL_AGGR_OFF_STS", BIT(17), 1}, 177 + {"USB2_PLL_OFF_STS", BIT(18), 0}, 178 + {"SAF_PLL_OFF_STS", BIT(19), 1}, 179 + {"SE_TCSS_PLL_OFF_STS", BIT(20), 1}, 180 + {"DDI_PLL_OFF_STS", BIT(21), 1}, 181 + {"FILTER_PLL_OFF_STS", BIT(22), 1}, 182 + {"ACE_PLL_OFF_STS", BIT(24), 0}, 183 + {"FABRIC_PLL_OFF_STS", BIT(25), 1}, 184 + {"SOC_PLL_OFF_STS", BIT(26), 1}, 185 + {"REF_PLL_OFF_STS", BIT(28), 1}, 186 + {"IMG_PLL_OFF_STS", BIT(29), 1}, 187 + {"RTC_PLL_OFF_STS", BIT(31), 0}, 188 + {} 189 + }; 190 + 191 + static const struct pmc_bit_map ptl_pcdp_power_gating_status_0_map[] = { 192 + {"PMC_PGD0_PG_STS", BIT(0), 0}, 193 + {"FUSE_OSSE_PGD0_PG_STS", BIT(1), 0}, 194 + {"ESPISPI_PGD0_PG_STS", BIT(2), 0}, 195 + {"XHCI_PGD0_PG_STS", BIT(3), 1}, 196 + {"SPA_PGD0_PG_STS", BIT(4), 1}, 197 + {"SPB_PGD0_PG_STS", BIT(5), 1}, 198 + {"MPFPW2_PGD0_PG_STS", BIT(6), 0}, 199 + {"GBE_PGD0_PG_STS", BIT(7), 1}, 200 + {"SBR16B20_PGD0_PG_STS", BIT(8), 0}, 201 + {"SBR8B20_PGD0_PG_STS", BIT(9), 0}, 202 + {"SBR16B21_PGD0_PG_STS", BIT(10), 0}, 203 + {"DBG_PGD0_PG_STS", BIT(11), 0}, 204 + {"OSSE_HOTHAM_PGD0_PG_STS", BIT(12), 1}, 205 + {"D2D_DISP_PGD1_PG_STS", BIT(13), 1}, 206 + {"LPSS_PGD0_PG_STS", BIT(14), 1}, 207 + {"LPC_PGD0_PG_STS", BIT(15), 0}, 208 + {"SMB_PGD0_PG_STS", BIT(16), 0}, 209 + {"ISH_PGD0_PG_STS", BIT(17), 0}, 210 + {"SBR16B2_PGD0_PG_STS", BIT(18), 0}, 211 + {"NPK_PGD0_PG_STS", BIT(19), 0}, 212 + {"D2D_NOC_PGD1_PG_STS", BIT(20), 1}, 213 + {"SBR8B2_PGD0_PG_STS", BIT(21), 0}, 214 + {"FUSE_PGD0_PG_STS", BIT(22), 0}, 215 + {"SBR16B0_PGD0_PG_STS", BIT(23), 0}, 216 + {"PSF0_PGD0_PG_STS", BIT(24), 0}, 217 + {"XDCI_PGD0_PG_STS", BIT(25), 1}, 218 + {"EXI_PGD0_PG_STS", BIT(26), 0}, 219 + {"CSE_PGD0_PG_STS", BIT(27), 1}, 220 + {"KVMCC_PGD0_PG_STS", BIT(28), 1}, 221 + {"PMT_PGD0_PG_STS", BIT(29), 1}, 222 + {"CLINK_PGD0_PG_STS", BIT(30), 1}, 223 + {"PTIO_PGD0_PG_STS", BIT(31), 1}, 224 + {} 225 + }; 226 + 227 + static const struct pmc_bit_map ptl_pcdp_power_gating_status_1_map[] = { 228 + {"USBR0_PGD0_PG_STS", BIT(0), 1}, 229 + {"SUSRAM_PGD0_PG_STS", BIT(1), 1}, 230 + {"SMT1_PGD0_PG_STS", BIT(2), 1}, 231 + {"MPFPW1_PGD0_PG_STS", BIT(3), 0}, 232 + {"SMS2_PGD0_PG_STS", BIT(4), 1}, 233 + {"SMS1_PGD0_PG_STS", BIT(5), 1}, 234 + {"CSMERTC_PGD0_PG_STS", BIT(6), 0}, 235 + {"CSMEPSF_PGD0_PG_STS", BIT(7), 0}, 236 + {"D2D_NOC_PGD0_PG_STS", BIT(8), 0}, 237 + {"ESE_PGD0_PG_STS", BIT(9), 1}, 238 + {"P2SB8B_PGD0_PG_STS", BIT(10), 1}, 239 + {"SBR16B7_PGD0_PG_STS", BIT(11), 0}, 240 + {"SBR16B3_PGD0_PG_STS", BIT(12), 0}, 241 + {"OSSE_SMT1_PGD0_PG_STS", BIT(13), 1}, 242 + {"D2D_DISP_PGD0_PG_STS", BIT(14), 1}, 243 + {"DBG_SBR_PGD0_PG_STS", BIT(15), 0}, 244 + {"U3FPW1_PGD0_PG_STS", BIT(16), 0}, 245 + {"FIA_X_PGD0_PG_STS", BIT(17), 0}, 246 + {"PSF4_PGD0_PG_STS", BIT(18), 0}, 247 + {"CNVI_PGD0_PG_STS", BIT(19), 0}, 248 + {"UFSX2_PGD0_PG_STS", BIT(20), 1}, 249 + {"ENDBG_PGD0_PG_STS", BIT(21), 0}, 250 + {"DBC_PGD0_PG_STS", BIT(22), 0}, 251 + {"FIA_PG_PGD0_PG_STS", BIT(23), 0}, 252 + {"D2D_IPU_PGD0_PG_STS", BIT(24), 1}, 253 + {"NPK_PGD1_PG_STS", BIT(25), 0}, 254 + {"FIACPCB_X_PGD0_PG_STS", BIT(26), 0}, 255 + {"SBR8B4_PGD0_PG_STS", BIT(27), 0}, 256 + {"DBG_PSF_PGD0_PG_STS", BIT(28), 0}, 257 + {"PSF6_PGD0_PG_STS", BIT(29), 0}, 258 + {"UFSPW1_PGD0_PG_STS", BIT(30), 0}, 259 + {"FIA_U_PGD0_PG_STS", BIT(31), 0}, 260 + {} 261 + }; 262 + 263 + static const struct pmc_bit_map ptl_pcdp_power_gating_status_2_map[] = { 264 + {"PSF8_PGD0_PG_STS", BIT(0), 0}, 265 + {"SBR16B4_PGD0_PG_STS", BIT(1), 0}, 266 + {"SBR16B5_PGD0_PG_STS", BIT(2), 0}, 267 + {"FIACPCB_U_PGD0_PG_STS", BIT(3), 0}, 268 + {"TAM_PGD0_PG_STS", BIT(4), 1}, 269 + {"D2D_NOC_PGD0_PG_STS", BIT(5), 1}, 270 + {"TBTLSX_PGD0_PG_STS", BIT(6), 1}, 271 + {"THC0_PGD0_PG_STS", BIT(7), 1}, 272 + {"THC1_PGD0_PG_STS", BIT(8), 1}, 273 + {"PMC_PGD1_PG_STS", BIT(9), 0}, 274 + {"SBR8B1_PGD0_PG_STS", BIT(10), 0}, 275 + {"TCSS_PGD0_PG_STS", BIT(11), 0}, 276 + {"DISP_PGA_PGD0_PG_STS", BIT(12), 0}, 277 + {"SBR16B1_PGD0_PG_STS", BIT(13), 0}, 278 + {"SBRG_PGD0_PG_STS", BIT(14), 0}, 279 + {"PSF5_PGD0_PG_STS", BIT(15), 0}, 280 + {"P2SB16B_PGD0_PG_STS", BIT(16), 1}, 281 + {"ACE_PGD0_PG_STS", BIT(17), 0}, 282 + {"ACE_PGD1_PG_STS", BIT(18), 0}, 283 + {"ACE_PGD2_PG_STS", BIT(19), 0}, 284 + {"ACE_PGD3_PG_STS", BIT(20), 0}, 285 + {"ACE_PGD4_PG_STS", BIT(21), 0}, 286 + {"ACE_PGD5_PG_STS", BIT(22), 0}, 287 + {"ACE_PGD6_PG_STS", BIT(23), 0}, 288 + {"ACE_PGD7_PG_STS", BIT(24), 0}, 289 + {"ACE_PGD8_PG_STS", BIT(25), 0}, 290 + {"ACE_PGD9_PG_STS", BIT(26), 0}, 291 + {"ACE_PGD10_PG_STS", BIT(27), 0}, 292 + {"FIACPCB_PG_PGD0_PG_STS", BIT(28), 0}, 293 + {"SBR16B6_PGD0_PG_STS", BIT(29), 0}, 294 + {"OSSE_PGD0_PG_STS", BIT(30), 1}, 295 + {"SBR8B0_PGD0_PG_STS", BIT(31), 0}, 296 + {} 297 + }; 298 + 299 + static const struct pmc_bit_map ptl_pcdp_d3_status_0_map[] = { 300 + {"LPSS_D3_STS", BIT(3), 1}, 301 + {"XDCI_D3_STS", BIT(4), 1}, 302 + {"XHCI_D3_STS", BIT(5), 1}, 303 + {"OSSE_D3_STS", BIT(6), 0}, 304 + {"SPA_D3_STS", BIT(12), 0}, 305 + {"SPB_D3_STS", BIT(13), 0}, 306 + {"ESPISPI_D3_STS", BIT(18), 0}, 307 + {"PSTH_D3_STS", BIT(21), 0}, 308 + {"OSSE_SMT1_D3_STS", BIT(30), 0}, 309 + {} 310 + }; 311 + 312 + static const struct pmc_bit_map ptl_pcdp_d3_status_1_map[] = { 313 + {"GBE_D3_STS", BIT(19), 0}, 314 + {"ITSS_D3_STS", BIT(23), 0}, 315 + {"CNVI_D3_STS", BIT(27), 0}, 316 + {"UFSX2_D3_STS", BIT(28), 1}, 317 + {"OSSE_HOTHAM_D3_STS", BIT(29), 0}, 318 + {"ESE_D3_STS", BIT(30), 0}, 319 + {} 320 + }; 321 + 322 + static const struct pmc_bit_map ptl_pcdp_d3_status_2_map[] = { 323 + {"CSMERTC_D3_STS", BIT(1), 0}, 324 + {"SUSRAM_D3_STS", BIT(2), 0}, 325 + {"CSE_D3_STS", BIT(4), 0}, 326 + {"KVMCC_D3_STS", BIT(5), 0}, 327 + {"USBR0_D3_STS", BIT(6), 0}, 328 + {"ISH_D3_STS", BIT(7), 0}, 329 + {"SMT1_D3_STS", BIT(8), 0}, 330 + {"SMT2_D3_STS", BIT(9), 0}, 331 + {"SMT3_D3_STS", BIT(10), 0}, 332 + {"OSSE_SMT2_D3_STS", BIT(12), 0}, 333 + {"CLINK_D3_STS", BIT(14), 0}, 334 + {"PTIO_D3_STS", BIT(16), 0}, 335 + {"PMT_D3_STS", BIT(17), 0}, 336 + {"SMS1_D3_STS", BIT(18), 0}, 337 + {"SMS2_D3_STS", BIT(19), 0}, 338 + {} 339 + }; 340 + 341 + static const struct pmc_bit_map ptl_pcdp_d3_status_3_map[] = { 342 + {"THC0_D3_STS", BIT(14), 1}, 343 + {"THC1_D3_STS", BIT(15), 1}, 344 + {"OSSE_SMT3_D3_STS", BIT(18), 0}, 345 + {"ACE_D3_STS", BIT(23), 0}, 346 + {} 347 + }; 348 + 349 + static const struct pmc_bit_map ptl_pcdp_vnn_req_status_0_map[] = { 350 + {"LPSS_VNN_REQ_STS", BIT(3), 1}, 351 + {"OSSE_VNN_REQ_STS", BIT(6), 1}, 352 + {"ESPISPI_VNN_REQ_STS", BIT(18), 1}, 353 + {"OSSE_SMT1_VNN_REQ_STS", BIT(30), 1}, 354 + {} 355 + }; 356 + 357 + static const struct pmc_bit_map ptl_pcdp_vnn_req_status_1_map[] = { 358 + {"NPK_VNN_REQ_STS", BIT(4), 1}, 359 + {"DFXAGG_VNN_REQ_STS", BIT(8), 0}, 360 + {"EXI_VNN_REQ_STS", BIT(9), 1}, 361 + {"P2D_VNN_REQ_STS", BIT(18), 1}, 362 + {"GBE_VNN_REQ_STS", BIT(19), 1}, 363 + {"SMB_VNN_REQ_STS", BIT(25), 1}, 364 + {"LPC_VNN_REQ_STS", BIT(26), 0}, 365 + {"ESE_VNN_REQ_STS", BIT(30), 1}, 366 + {} 367 + }; 368 + 369 + static const struct pmc_bit_map ptl_pcdp_vnn_req_status_2_map[] = { 370 + {"CSMERTC_VNN_REQ_STS", BIT(1), 1}, 371 + {"CSE_VNN_REQ_STS", BIT(4), 1}, 372 + {"ISH_VNN_REQ_STS", BIT(7), 1}, 373 + {"SMT1_VNN_REQ_STS", BIT(8), 1}, 374 + {"CLINK_VNN_REQ_STS", BIT(14), 1}, 375 + {"SMS1_VNN_REQ_STS", BIT(18), 1}, 376 + {"SMS2_VNN_REQ_STS", BIT(19), 1}, 377 + {"GPIOCOM4_VNN_REQ_STS", BIT(20), 1}, 378 + {"GPIOCOM3_VNN_REQ_STS", BIT(21), 1}, 379 + {"GPIOCOM1_VNN_REQ_STS", BIT(23), 1}, 380 + {"GPIOCOM0_VNN_REQ_STS", BIT(24), 1}, 381 + {"DISP_SHIM_VNN_REQ_STS", BIT(26), 1}, 382 + {} 383 + }; 384 + 385 + static const struct pmc_bit_map ptl_pcdp_vnn_req_status_3_map[] = { 386 + {"DTS0_VNN_REQ_STS", BIT(7), 0}, 387 + {"GPIOCOM5_VNN_REQ_STS", BIT(11), 1}, 388 + {} 389 + }; 390 + 391 + static const struct pmc_bit_map ptl_pcdp_vnn_misc_status_map[] = { 392 + {"CPU_C10_REQ_STS", BIT(0), 0}, 393 + {"TS_OFF_REQ_STS", BIT(1), 0}, 394 + {"PNDE_MET_REQ_STS", BIT(2), 1}, 395 + {"PG5_PMA0_REQ_STS", BIT(3), 0}, 396 + {"FW_THROTTLE_ALLOWED_REQ_STS", BIT(4), 0}, 397 + {"VNN_SOC_REQ_STS", BIT(6), 1}, 398 + {"ISH_VNNAON_REQ_STS", BIT(7), 0}, 399 + {"D2D_NOC_CFI_QACTIVE_REQ_STS", BIT(8), 1}, 400 + {"D2D_NOC_GPSB_QACTIVE_REQ_STS", BIT(9), 1}, 401 + {"D2D_IPU_QACTIVE_REQ_STS", BIT(10), 1}, 402 + {"PLT_GREATER_REQ_STS", BIT(11), 1}, 403 + {"ALL_SBR_IDLE_REQ_STS", BIT(12), 0}, 404 + {"PMC_IDLE_FB_OCP_REQ_STS", BIT(13), 0}, 405 + {"PM_SYNC_STATES_REQ_STS", BIT(14), 0}, 406 + {"EA_REQ_STS", BIT(15), 0}, 407 + {"MPHY_CORE_OFF_REQ_STS", BIT(16), 0}, 408 + {"BRK_EV_EN_REQ_STS", BIT(17), 0}, 409 + {"AUTO_DEMO_EN_REQ_STS", BIT(18), 0}, 410 + {"ITSS_CLK_SRC_REQ_STS", BIT(19), 1}, 411 + {"ARC_IDLE_REQ_STS", BIT(21), 0}, 412 + {"PG5_PMA1_REQ_STS", BIT(22), 0}, 413 + {"FIA_DEEP_PM_REQ_STS", BIT(23), 0}, 414 + {"XDCI_ATTACHED_REQ_STS", BIT(24), 1}, 415 + {"ARC_INTERRUPT_WAKE_REQ_STS", BIT(25), 0}, 416 + {"D2D_DISP_DDI_QACTIVE_REQ_STS", BIT(26), 1}, 417 + {"PRE_WAKE0_REQ_STS", BIT(27), 1}, 418 + {"PRE_WAKE1_REQ_STS", BIT(28), 1}, 419 + {"PRE_WAKE2_REQ_STS", BIT(29), 1}, 420 + {"D2D_DISP_EDP_QACTIVE_REQ_STS", BIT(31), 1}, 421 + {} 422 + }; 423 + 424 + static const struct pmc_bit_map ptl_pcdp_signal_status_map[] = { 425 + {"LSX_Wake0_STS", BIT(0), 0}, 426 + {"LSX_Wake1_STS", BIT(1), 0}, 427 + {"LSX_Wake2_STS", BIT(2), 0}, 428 + {"LSX_Wake3_STS", BIT(3), 0}, 429 + {"LSX_Wake4_STS", BIT(4), 0}, 430 + {"LSX_Wake5_STS", BIT(5), 0}, 431 + {"LSX_Wake6_STS", BIT(6), 0}, 432 + {"LSX_Wake7_STS", BIT(7), 0}, 433 + {"LPSS_Wake0_STS", BIT(8), 1}, 434 + {"LPSS_Wake1_STS", BIT(9), 1}, 435 + {"Int_Timer_SS_Wake0_STS", BIT(10), 1}, 436 + {"Int_Timer_SS_Wake1_STS", BIT(11), 1}, 437 + {"Int_Timer_SS_Wake2_STS", BIT(12), 1}, 438 + {"Int_Timer_SS_Wake3_STS", BIT(13), 1}, 439 + {"Int_Timer_SS_Wake4_STS", BIT(14), 1}, 440 + {"Int_Timer_SS_Wake5_STS", BIT(15), 1}, 441 + {} 442 + }; 443 + 444 + static const struct pmc_bit_map ptl_pcdp_rsc_status_map[] = { 445 + {"Memory", 0, 1}, 446 + {"PSF0", 0, 1}, 447 + {"PSF4", 0, 1}, 448 + {"PSF5", 0, 1}, 449 + {"PSF6", 0, 1}, 450 + {"PSF8", 0, 1}, 451 + {"SAF_CFI_LINK", 0, 1}, 452 + {"SB", 0, 1}, 453 + {} 454 + }; 455 + 456 + static const struct pmc_bit_map *ptl_pcdp_lpm_maps[] = { 457 + ptl_pcdp_clocksource_status_map, 458 + ptl_pcdp_power_gating_status_0_map, 459 + ptl_pcdp_power_gating_status_1_map, 460 + ptl_pcdp_power_gating_status_2_map, 461 + ptl_pcdp_d3_status_0_map, 462 + ptl_pcdp_d3_status_1_map, 463 + ptl_pcdp_d3_status_2_map, 464 + ptl_pcdp_d3_status_3_map, 465 + ptl_pcdp_vnn_req_status_0_map, 466 + ptl_pcdp_vnn_req_status_1_map, 467 + ptl_pcdp_vnn_req_status_2_map, 468 + ptl_pcdp_vnn_req_status_3_map, 469 + ptl_pcdp_vnn_misc_status_map, 470 + ptl_pcdp_signal_status_map, 471 + NULL 472 + }; 473 + 474 + static const struct pmc_bit_map *ptl_pcdp_blk_maps[] = { 475 + ptl_pcdp_power_gating_status_0_map, 476 + ptl_pcdp_power_gating_status_1_map, 477 + ptl_pcdp_power_gating_status_2_map, 478 + ptl_pcdp_rsc_status_map, 479 + ptl_pcdp_vnn_req_status_0_map, 480 + ptl_pcdp_vnn_req_status_1_map, 481 + ptl_pcdp_vnn_req_status_2_map, 482 + ptl_pcdp_vnn_req_status_3_map, 483 + ptl_pcdp_d3_status_0_map, 484 + ptl_pcdp_d3_status_1_map, 485 + ptl_pcdp_d3_status_2_map, 486 + ptl_pcdp_d3_status_3_map, 487 + ptl_pcdp_clocksource_status_map, 488 + ptl_pcdp_vnn_misc_status_map, 489 + ptl_pcdp_signal_status_map, 490 + NULL 491 + }; 492 + 493 + static const struct pmc_reg_map ptl_pcdp_reg_map = { 494 + .pfear_sts = ext_ptl_pcdp_pfear_map, 495 + .slp_s0_offset = CNP_PMC_SLP_S0_RES_COUNTER_OFFSET, 496 + .slp_s0_res_counter_step = TGL_PMC_SLP_S0_RES_COUNTER_STEP, 497 + .ltr_show_sts = ptl_pcdp_ltr_show_map, 498 + .msr_sts = msr_map, 499 + .ltr_ignore_offset = CNP_PMC_LTR_IGNORE_OFFSET, 500 + .regmap_length = PTL_PCD_PMC_MMIO_REG_LEN, 501 + .ppfear0_offset = CNP_PMC_HOST_PPFEAR0A, 502 + .ppfear_buckets = LNL_PPFEAR_NUM_ENTRIES, 503 + .pm_cfg_offset = CNP_PMC_PM_CFG_OFFSET, 504 + .pm_read_disable_bit = CNP_PMC_READ_DISABLE_BIT, 505 + .lpm_num_maps = PTL_LPM_NUM_MAPS, 506 + .ltr_ignore_max = LNL_NUM_IP_IGN_ALLOWED, 507 + .lpm_res_counter_step_x2 = TGL_PMC_LPM_RES_COUNTER_STEP_X2, 508 + .etr3_offset = ETR3_OFFSET, 509 + .lpm_sts_latch_en_offset = MTL_LPM_STATUS_LATCH_EN_OFFSET, 510 + .lpm_priority_offset = MTL_LPM_PRI_OFFSET, 511 + .lpm_en_offset = MTL_LPM_EN_OFFSET, 512 + .lpm_residency_offset = MTL_LPM_RESIDENCY_OFFSET, 513 + .lpm_sts = ptl_pcdp_lpm_maps, 514 + .lpm_status_offset = MTL_LPM_STATUS_OFFSET, 515 + .lpm_live_status_offset = MTL_LPM_LIVE_STATUS_OFFSET, 516 + .s0ix_blocker_maps = ptl_pcdp_blk_maps, 517 + .s0ix_blocker_offset = LNL_S0IX_BLOCKER_OFFSET, 518 + }; 519 + 520 + #define PTL_NPU_PCI_DEV 0xb03e 521 + #define PTL_IPU_PCI_DEV 0xb05d 522 + 523 + /* 524 + * Set power state of select devices that do not have drivers to D3 525 + * so that they do not block Package C entry. 526 + */ 527 + static void ptl_d3_fixup(void) 528 + { 529 + pmc_core_set_device_d3(PTL_IPU_PCI_DEV); 530 + pmc_core_set_device_d3(PTL_NPU_PCI_DEV); 531 + } 532 + 533 + static int ptl_resume(struct pmc_dev *pmcdev) 534 + { 535 + ptl_d3_fixup(); 536 + return cnl_resume(pmcdev); 537 + } 538 + 539 + static int ptl_core_init(struct pmc_dev *pmcdev, struct pmc_dev_info *pmc_dev_info) 540 + { 541 + ptl_d3_fixup(); 542 + return generic_core_init(pmcdev, pmc_dev_info); 543 + } 544 + 545 + struct pmc_dev_info ptl_pmc_dev = { 546 + .map = &ptl_pcdp_reg_map, 547 + .suspend = cnl_suspend, 548 + .resume = ptl_resume, 549 + .init = ptl_core_init, 550 + };
+27 -18
drivers/platform/x86/intel/pmc/spt.c
··· 8 8 * 9 9 */ 10 10 11 + #include <linux/pci.h> 12 + 11 13 #include "core.h" 12 14 13 - const struct pmc_bit_map spt_pll_map[] = { 15 + static const struct pmc_bit_map spt_pll_map[] = { 14 16 {"MIPI PLL", SPT_PMC_BIT_MPHY_CMN_LANE0}, 15 17 {"GEN2 USB2PCIE2 PLL", SPT_PMC_BIT_MPHY_CMN_LANE1}, 16 18 {"DMIPCIE3 PLL", SPT_PMC_BIT_MPHY_CMN_LANE2}, ··· 20 18 {} 21 19 }; 22 20 23 - const struct pmc_bit_map spt_mphy_map[] = { 21 + static const struct pmc_bit_map spt_mphy_map[] = { 24 22 {"MPHY CORE LANE 0", SPT_PMC_BIT_MPHY_LANE0}, 25 23 {"MPHY CORE LANE 1", SPT_PMC_BIT_MPHY_LANE1}, 26 24 {"MPHY CORE LANE 2", SPT_PMC_BIT_MPHY_LANE2}, ··· 40 38 {} 41 39 }; 42 40 43 - const struct pmc_bit_map spt_pfear_map[] = { 41 + static const struct pmc_bit_map spt_pfear_map[] = { 44 42 {"PMC", SPT_PMC_BIT_PMC}, 45 43 {"OPI-DMI", SPT_PMC_BIT_OPI}, 46 44 {"SPI / eSPI", SPT_PMC_BIT_SPI}, ··· 84 82 {} 85 83 }; 86 84 87 - const struct pmc_bit_map *ext_spt_pfear_map[] = { 85 + static const struct pmc_bit_map *ext_spt_pfear_map[] = { 88 86 /* 89 87 * Check intel_pmc_core_ids[] users of spt_reg_map for 90 88 * a list of core SoCs using this. ··· 93 91 NULL 94 92 }; 95 93 96 - const struct pmc_bit_map spt_ltr_show_map[] = { 94 + static const struct pmc_bit_map spt_ltr_show_map[] = { 97 95 {"SOUTHPORT_A", SPT_PMC_LTR_SPA}, 98 96 {"SOUTHPORT_B", SPT_PMC_LTR_SPB}, 99 97 {"SATA", SPT_PMC_LTR_SATA}, ··· 118 116 {} 119 117 }; 120 118 121 - const struct pmc_reg_map spt_reg_map = { 119 + static const struct pmc_reg_map spt_reg_map = { 122 120 .pfear_sts = ext_spt_pfear_map, 123 121 .mphy_sts = spt_mphy_map, 124 122 .pll_sts = spt_pll_map, ··· 136 134 .pm_vric1_offset = SPT_PMC_VRIC1_OFFSET, 137 135 }; 138 136 139 - int spt_core_init(struct pmc_dev *pmcdev) 137 + static const struct pci_device_id spt_pmc_pci_id[] = { 138 + { PCI_VDEVICE(INTEL, SPT_PMC_PCI_DEVICE_ID) }, 139 + { } 140 + }; 141 + 142 + static int spt_core_init(struct pmc_dev *pmcdev, struct pmc_dev_info *pmc_dev_info) 140 143 { 141 - struct pmc *pmc = pmcdev->pmcs[PMC_IDX_MAIN]; 142 - int ret; 144 + /* 145 + * Coffee Lake has CPU ID of Kaby Lake and Cannon Lake PCH. So here 146 + * Sunrisepoint PCH regmap can't be used. Use Cannon Lake PCH regmap 147 + * in this case. 148 + */ 149 + if (!pci_dev_present(spt_pmc_pci_id)) 150 + return generic_core_init(pmcdev, &cnp_pmc_dev); 143 151 144 - pmc->map = &spt_reg_map; 145 - 146 - ret = get_primary_reg_base(pmc); 147 - if (ret) 148 - return ret; 149 - 150 - pmc_core_get_low_power_modes(pmcdev); 151 - 152 - return ret; 152 + return generic_core_init(pmcdev, pmc_dev_info); 153 153 } 154 + 155 + struct pmc_dev_info spt_pmc_dev = { 156 + .map = &spt_reg_map, 157 + .init = spt_core_init, 158 + };
+26 -33
drivers/platform/x86/intel/pmc/tgl.c
··· 18 18 PCH_LP 19 19 }; 20 20 21 - const struct pmc_bit_map tgl_pfear_map[] = { 21 + static const struct pmc_bit_map tgl_pfear_map[] = { 22 22 {"PSF9", BIT(0)}, 23 23 {"RES_66", BIT(1)}, 24 24 {"RES_67", BIT(2)}, ··· 29 29 {} 30 30 }; 31 31 32 - const struct pmc_bit_map *ext_tgl_pfear_map[] = { 32 + static const struct pmc_bit_map *ext_tgl_pfear_map[] = { 33 33 /* 34 34 * Check intel_pmc_core_ids[] users of tgl_reg_map for 35 35 * a list of core SoCs using this. ··· 39 39 NULL 40 40 }; 41 41 42 - const struct pmc_bit_map tgl_clocksource_status_map[] = { 42 + static const struct pmc_bit_map tgl_clocksource_status_map[] = { 43 43 {"USB2PLL_OFF_STS", BIT(18)}, 44 44 {"PCIe/USB3.1_Gen2PLL_OFF_STS", BIT(19)}, 45 45 {"PCIe_Gen3PLL_OFF_STS", BIT(20)}, ··· 55 55 {} 56 56 }; 57 57 58 - const struct pmc_bit_map tgl_power_gating_status_map[] = { 58 + static const struct pmc_bit_map tgl_power_gating_status_map[] = { 59 59 {"CSME_PG_STS", BIT(0)}, 60 60 {"SATA_PG_STS", BIT(1)}, 61 61 {"xHCI_PG_STS", BIT(2)}, ··· 83 83 {} 84 84 }; 85 85 86 - const struct pmc_bit_map tgl_d3_status_map[] = { 86 + static const struct pmc_bit_map tgl_d3_status_map[] = { 87 87 {"ADSP_D3_STS", BIT(0)}, 88 88 {"SATA_D3_STS", BIT(1)}, 89 89 {"xHCI0_D3_STS", BIT(2)}, ··· 98 98 {} 99 99 }; 100 100 101 - const struct pmc_bit_map tgl_vnn_req_status_map[] = { 101 + static const struct pmc_bit_map tgl_vnn_req_status_map[] = { 102 102 {"GPIO_COM0_VNN_REQ_STS", BIT(1)}, 103 103 {"GPIO_COM1_VNN_REQ_STS", BIT(2)}, 104 104 {"GPIO_COM2_VNN_REQ_STS", BIT(3)}, ··· 123 123 {} 124 124 }; 125 125 126 - const struct pmc_bit_map tgl_vnn_misc_status_map[] = { 126 + static const struct pmc_bit_map tgl_vnn_misc_status_map[] = { 127 127 {"CPU_C10_REQ_STS_0", BIT(0)}, 128 128 {"PCIe_LPM_En_REQ_STS_3", BIT(3)}, 129 129 {"ITH_REQ_STS_5", BIT(5)}, ··· 175 175 {} 176 176 }; 177 177 178 - const struct pmc_bit_map *tgl_lpm_maps[] = { 178 + static const struct pmc_bit_map *tgl_lpm_maps[] = { 179 179 tgl_clocksource_status_map, 180 180 tgl_power_gating_status_map, 181 181 tgl_d3_status_map, ··· 185 185 NULL 186 186 }; 187 187 188 - const struct pmc_reg_map tgl_reg_map = { 188 + static const struct pmc_reg_map tgl_reg_map = { 189 189 .pfear_sts = ext_tgl_pfear_map, 190 190 .slp_s0_offset = CNP_PMC_SLP_S0_RES_COUNTER_OFFSET, 191 191 .slp_s0_res_counter_step = TGL_PMC_SLP_S0_RES_COUNTER_STEP, ··· 210 210 .etr3_offset = ETR3_OFFSET, 211 211 }; 212 212 213 - const struct pmc_reg_map tgl_h_reg_map = { 213 + static const struct pmc_reg_map tgl_h_reg_map = { 214 214 .pfear_sts = ext_tgl_pfear_map, 215 215 .slp_s0_offset = CNP_PMC_SLP_S0_RES_COUNTER_OFFSET, 216 216 .slp_s0_res_counter_step = TGL_PMC_SLP_S0_RES_COUNTER_STEP, ··· 285 285 ACPI_FREE(out_obj); 286 286 } 287 287 288 - int tgl_l_core_init(struct pmc_dev *pmcdev) 288 + static int tgl_core_init(struct pmc_dev *pmcdev, struct pmc_dev_info *pmc_dev_info) 289 289 { 290 - return tgl_core_generic_init(pmcdev, PCH_LP); 291 - } 292 - 293 - int tgl_core_init(struct pmc_dev *pmcdev) 294 - { 295 - return tgl_core_generic_init(pmcdev, PCH_H); 296 - } 297 - 298 - int tgl_core_generic_init(struct pmc_dev *pmcdev, int pch_tp) 299 - { 300 - struct pmc *pmc = pmcdev->pmcs[PMC_IDX_MAIN]; 301 290 int ret; 302 291 303 - if (pch_tp == PCH_H) 304 - pmc->map = &tgl_h_reg_map; 305 - else 306 - pmc->map = &tgl_reg_map; 307 - 308 - pmcdev->suspend = cnl_suspend; 309 - pmcdev->resume = cnl_resume; 310 - 311 - ret = get_primary_reg_base(pmc); 292 + ret = generic_core_init(pmcdev, pmc_dev_info); 312 293 if (ret) 313 294 return ret; 314 295 315 - pmc_core_get_low_power_modes(pmcdev); 316 296 pmc_core_get_tgl_lpm_reqs(pmcdev->pdev); 317 - 318 297 return 0; 319 298 } 299 + 300 + struct pmc_dev_info tgl_l_pmc_dev = { 301 + .map = &tgl_reg_map, 302 + .suspend = cnl_suspend, 303 + .resume = cnl_resume, 304 + .init = tgl_core_init, 305 + }; 306 + 307 + struct pmc_dev_info tgl_pmc_dev = { 308 + .map = &tgl_h_reg_map, 309 + .suspend = cnl_suspend, 310 + .resume = cnl_resume, 311 + .init = tgl_core_init, 312 + };
+212
drivers/platform/x86/lenovo-wmi-hotkey-utilities.c
··· 1 + // SPDX-License-Identifier: GPL-2.0 2 + /* 3 + * Lenovo Super Hotkey Utility WMI extras driver for Ideapad laptop 4 + * 5 + * Copyright (C) 2025 Lenovo 6 + */ 7 + 8 + #include <linux/cleanup.h> 9 + #include <linux/dev_printk.h> 10 + #include <linux/device.h> 11 + #include <linux/leds.h> 12 + #include <linux/module.h> 13 + #include <linux/wmi.h> 14 + 15 + /* Lenovo Super Hotkey WMI GUIDs */ 16 + #define LUD_WMI_METHOD_GUID "CE6C0974-0407-4F50-88BA-4FC3B6559AD8" 17 + 18 + /* Lenovo Utility Data WMI method_id */ 19 + #define WMI_LUD_GET_SUPPORT 1 20 + #define WMI_LUD_SET_FEATURE 2 21 + 22 + #define WMI_LUD_GET_MICMUTE_LED_VER 20 23 + #define WMI_LUD_GET_AUDIOMUTE_LED_VER 26 24 + 25 + #define WMI_LUD_SUPPORT_MICMUTE_LED_VER 25 26 + #define WMI_LUD_SUPPORT_AUDIOMUTE_LED_VER 27 27 + 28 + /* Input parameters to mute/unmute audio LED and Mic LED */ 29 + struct wmi_led_args { 30 + u8 id; 31 + u8 subid; 32 + u16 value; 33 + }; 34 + 35 + /* Values of input parameters to SetFeature of audio LED and Mic LED */ 36 + enum hotkey_set_feature { 37 + MIC_MUTE_LED_ON = 1, 38 + MIC_MUTE_LED_OFF = 2, 39 + AUDIO_MUTE_LED_ON = 4, 40 + AUDIO_MUTE_LED_OFF = 5, 41 + }; 42 + 43 + #define LSH_ACPI_LED_MAX 2 44 + 45 + struct lenovo_super_hotkey_wmi_private { 46 + struct led_classdev cdev[LSH_ACPI_LED_MAX]; 47 + struct wmi_device *led_wdev; 48 + }; 49 + 50 + enum mute_led_type { 51 + MIC_MUTE, 52 + AUDIO_MUTE, 53 + }; 54 + 55 + static int lsh_wmi_mute_led_set(enum mute_led_type led_type, struct led_classdev *led_cdev, 56 + enum led_brightness brightness) 57 + 58 + { 59 + struct lenovo_super_hotkey_wmi_private *wpriv = container_of(led_cdev, 60 + struct lenovo_super_hotkey_wmi_private, cdev[led_type]); 61 + struct wmi_led_args led_arg = {0, 0, 0}; 62 + struct acpi_buffer input; 63 + acpi_status status; 64 + 65 + switch (led_type) { 66 + case MIC_MUTE: 67 + led_arg.id = brightness == LED_ON ? MIC_MUTE_LED_ON : MIC_MUTE_LED_OFF; 68 + break; 69 + case AUDIO_MUTE: 70 + led_arg.id = brightness == LED_ON ? AUDIO_MUTE_LED_ON : AUDIO_MUTE_LED_OFF; 71 + break; 72 + default: 73 + return -EINVAL; 74 + } 75 + 76 + input.length = sizeof(led_arg); 77 + input.pointer = &led_arg; 78 + status = wmidev_evaluate_method(wpriv->led_wdev, 0, WMI_LUD_SET_FEATURE, &input, NULL); 79 + if (ACPI_FAILURE(status)) 80 + return -EIO; 81 + 82 + return 0; 83 + } 84 + 85 + static int lsh_wmi_audiomute_led_set(struct led_classdev *led_cdev, 86 + enum led_brightness brightness) 87 + 88 + { 89 + return lsh_wmi_mute_led_set(AUDIO_MUTE, led_cdev, brightness); 90 + } 91 + 92 + static int lsh_wmi_micmute_led_set(struct led_classdev *led_cdev, 93 + enum led_brightness brightness) 94 + { 95 + return lsh_wmi_mute_led_set(MIC_MUTE, led_cdev, brightness); 96 + } 97 + 98 + static int lenovo_super_hotkey_wmi_led_init(enum mute_led_type led_type, struct device *dev) 99 + { 100 + struct lenovo_super_hotkey_wmi_private *wpriv = dev_get_drvdata(dev); 101 + struct acpi_buffer output = { ACPI_ALLOCATE_BUFFER, NULL }; 102 + struct acpi_buffer input; 103 + int led_version, err = 0; 104 + unsigned int wmiarg; 105 + acpi_status status; 106 + 107 + switch (led_type) { 108 + case MIC_MUTE: 109 + wmiarg = WMI_LUD_GET_MICMUTE_LED_VER; 110 + break; 111 + case AUDIO_MUTE: 112 + wmiarg = WMI_LUD_GET_AUDIOMUTE_LED_VER; 113 + break; 114 + default: 115 + return -EINVAL; 116 + } 117 + 118 + input.length = sizeof(wmiarg); 119 + input.pointer = &wmiarg; 120 + status = wmidev_evaluate_method(wpriv->led_wdev, 0, WMI_LUD_GET_SUPPORT, &input, &output); 121 + if (ACPI_FAILURE(status)) 122 + return -EIO; 123 + 124 + union acpi_object *obj __free(kfree) = output.pointer; 125 + if (obj && obj->type == ACPI_TYPE_INTEGER) 126 + led_version = obj->integer.value; 127 + else 128 + return -EIO; 129 + 130 + wpriv->cdev[led_type].max_brightness = LED_ON; 131 + wpriv->cdev[led_type].flags = LED_CORE_SUSPENDRESUME; 132 + 133 + switch (led_type) { 134 + case MIC_MUTE: 135 + if (led_version != WMI_LUD_SUPPORT_MICMUTE_LED_VER) 136 + return -EIO; 137 + 138 + wpriv->cdev[led_type].name = "platform::micmute"; 139 + wpriv->cdev[led_type].brightness_set_blocking = &lsh_wmi_micmute_led_set; 140 + wpriv->cdev[led_type].default_trigger = "audio-micmute"; 141 + break; 142 + case AUDIO_MUTE: 143 + if (led_version != WMI_LUD_SUPPORT_AUDIOMUTE_LED_VER) 144 + return -EIO; 145 + 146 + wpriv->cdev[led_type].name = "platform::mute"; 147 + wpriv->cdev[led_type].brightness_set_blocking = &lsh_wmi_audiomute_led_set; 148 + wpriv->cdev[led_type].default_trigger = "audio-mute"; 149 + break; 150 + default: 151 + dev_err(dev, "Unknown LED type %d\n", led_type); 152 + return -EINVAL; 153 + } 154 + 155 + err = devm_led_classdev_register(dev, &wpriv->cdev[led_type]); 156 + if (err < 0) { 157 + dev_err(dev, "Could not register mute LED %d : %d\n", led_type, err); 158 + return err; 159 + } 160 + return 0; 161 + } 162 + 163 + static int lenovo_super_hotkey_wmi_leds_setup(struct device *dev) 164 + { 165 + int err; 166 + 167 + err = lenovo_super_hotkey_wmi_led_init(MIC_MUTE, dev); 168 + if (err) 169 + return err; 170 + 171 + err = lenovo_super_hotkey_wmi_led_init(AUDIO_MUTE, dev); 172 + if (err) 173 + return err; 174 + 175 + return 0; 176 + } 177 + 178 + static int lenovo_super_hotkey_wmi_probe(struct wmi_device *wdev, const void *context) 179 + { 180 + struct lenovo_super_hotkey_wmi_private *wpriv; 181 + 182 + wpriv = devm_kzalloc(&wdev->dev, sizeof(*wpriv), GFP_KERNEL); 183 + if (!wpriv) 184 + return -ENOMEM; 185 + 186 + dev_set_drvdata(&wdev->dev, wpriv); 187 + wpriv->led_wdev = wdev; 188 + return lenovo_super_hotkey_wmi_leds_setup(&wdev->dev); 189 + } 190 + 191 + static const struct wmi_device_id lenovo_super_hotkey_wmi_id_table[] = { 192 + { LUD_WMI_METHOD_GUID, NULL }, /* Utility data */ 193 + { } 194 + }; 195 + 196 + MODULE_DEVICE_TABLE(wmi, lenovo_super_hotkey_wmi_id_table); 197 + 198 + static struct wmi_driver lenovo_wmi_hotkey_utilities_driver = { 199 + .driver = { 200 + .name = "lenovo_wmi_hotkey_utilities", 201 + .probe_type = PROBE_PREFER_ASYNCHRONOUS 202 + }, 203 + .id_table = lenovo_super_hotkey_wmi_id_table, 204 + .probe = lenovo_super_hotkey_wmi_probe, 205 + .no_singleton = true, 206 + }; 207 + 208 + module_wmi_driver(lenovo_wmi_hotkey_utilities_driver); 209 + 210 + MODULE_AUTHOR("Jackie Dong <dongeg1@lenovo.com>"); 211 + MODULE_DESCRIPTION("Lenovo Super Hotkey Utility WMI extras driver"); 212 + MODULE_LICENSE("GPL");
+1 -1
drivers/platform/x86/lenovo-yoga-tab2-pro-1380-fastcharger.c
··· 219 219 return 0; 220 220 } 221 221 222 - struct serdev_device_driver yt2_1380_fc_serdev_driver = { 222 + static struct serdev_device_driver yt2_1380_fc_serdev_driver = { 223 223 .probe = yt2_1380_fc_serdev_probe, 224 224 .driver = { 225 225 .name = KBUILD_MODNAME,
+8 -9
drivers/platform/x86/mlx-platform.c drivers/platform/mellanox/mlx-platform.c
··· 145 145 #define MLXPLAT_CPLD_LPC_REG_WD3_TMR_OFFSET 0xd1 146 146 #define MLXPLAT_CPLD_LPC_REG_WD3_TLEFT_OFFSET 0xd2 147 147 #define MLXPLAT_CPLD_LPC_REG_WD3_ACT_OFFSET 0xd3 148 - #define MLXPLAT_CPLD_LPC_REG_DBG_CTRL_OFFSET 0xd9 148 + #define MLXPLAT_CPLD_LPC_REG_CPLD6_MVER_OFFSET 0xd9 149 149 #define MLXPLAT_CPLD_LPC_REG_I2C_CH1_OFFSET 0xdb 150 150 #define MLXPLAT_CPLD_LPC_REG_I2C_CH2_OFFSET 0xda 151 151 #define MLXPLAT_CPLD_LPC_REG_I2C_CH3_OFFSET 0xdc ··· 2247 2247 .mask_low = MLXPLAT_CPLD_LOW_AGGR_MASK_LOW, 2248 2248 }; 2249 2249 2250 - /* Platform hotplug for NVLink blade systems family data */ 2250 + /* Platform hotplug for NVLink blade systems family data */ 2251 2251 static struct mlxreg_core_data mlxplat_mlxcpld_global_wp_items_data[] = { 2252 2252 { 2253 2253 .label = "global_wp_grant", ··· 2279 2279 .mask_low = MLXPLAT_CPLD_LOW_AGGR_MASK_LOW, 2280 2280 }; 2281 2281 2282 - /* Platform hotplug for switch systems family data */ 2282 + /* Platform hotplug for switch systems family data */ 2283 2283 static struct mlxreg_core_data mlxplat_mlxcpld_erot_ap_items_data[] = { 2284 2284 { 2285 2285 .label = "erot1_ap", ··· 2387 2387 .user_handler = mlxplat_mlxcpld_l1_switch_pwr_events_handler, 2388 2388 }; 2389 2389 2390 - /* Platform hotplug for l1 switch systems family data */ 2390 + /* Platform hotplug for l1 switch systems family data */ 2391 2391 static struct mlxreg_core_data mlxplat_mlxcpld_l1_switch_pwr_events_items_data[] = { 2392 2392 { 2393 2393 .label = "power_button", ··· 4401 4401 .counter = ARRAY_SIZE(mlxplat_mlxcpld_modular_regs_io_data), 4402 4402 }; 4403 4403 4404 - /* Platform register access for chassis blade systems family data */ 4404 + /* Platform register access for chassis blade systems family data */ 4405 4405 static struct mlxreg_core_data mlxplat_mlxcpld_chassis_blade_regs_io_data[] = { 4406 4406 { 4407 4407 .label = "cpld1_version", ··· 5050 5050 case MLXPLAT_CPLD_LPC_REG_WD3_TMR_OFFSET: 5051 5051 case MLXPLAT_CPLD_LPC_REG_WD3_TLEFT_OFFSET: 5052 5052 case MLXPLAT_CPLD_LPC_REG_WD3_ACT_OFFSET: 5053 - case MLXPLAT_CPLD_LPC_REG_DBG_CTRL_OFFSET: 5054 5053 case MLXPLAT_CPLD_LPC_REG_I2C_CH1_OFFSET: 5055 5054 case MLXPLAT_CPLD_LPC_REG_I2C_CH2_OFFSET: 5056 5055 case MLXPLAT_CPLD_LPC_REG_I2C_CH3_OFFSET: ··· 5185 5186 case MLXPLAT_CPLD_LPC_REG_WD3_TMR_OFFSET: 5186 5187 case MLXPLAT_CPLD_LPC_REG_WD3_TLEFT_OFFSET: 5187 5188 case MLXPLAT_CPLD_LPC_REG_WD3_ACT_OFFSET: 5188 - case MLXPLAT_CPLD_LPC_REG_DBG_CTRL_OFFSET: 5189 + case MLXPLAT_CPLD_LPC_REG_CPLD6_MVER_OFFSET: 5189 5190 case MLXPLAT_CPLD_LPC_REG_I2C_CH1_OFFSET: 5190 5191 case MLXPLAT_CPLD_LPC_REG_I2C_CH2_OFFSET: 5191 5192 case MLXPLAT_CPLD_LPC_REG_I2C_CH3_OFFSET: ··· 5342 5343 case MLXPLAT_CPLD_LPC_REG_WD2_TLEFT_OFFSET: 5343 5344 case MLXPLAT_CPLD_LPC_REG_WD3_TMR_OFFSET: 5344 5345 case MLXPLAT_CPLD_LPC_REG_WD3_TLEFT_OFFSET: 5345 - case MLXPLAT_CPLD_LPC_REG_DBG_CTRL_OFFSET: 5346 + case MLXPLAT_CPLD_LPC_REG_CPLD6_MVER_OFFSET: 5346 5347 case MLXPLAT_CPLD_LPC_REG_I2C_CH1_OFFSET: 5347 5348 case MLXPLAT_CPLD_LPC_REG_I2C_CH2_OFFSET: 5348 5349 case MLXPLAT_CPLD_LPC_REG_I2C_CH3_OFFSET: ··· 6572 6573 } 6573 6574 6574 6575 /* Set default registers. */ 6575 - for (i = 0; i < mlxplat_regmap_config->num_reg_defaults; i++) { 6576 + for (i = 0; i < mlxplat_regmap_config->num_reg_defaults; i++) { 6576 6577 err = regmap_write(priv->regmap, 6577 6578 mlxplat_regmap_config->reg_defaults[i].reg, 6578 6579 mlxplat_regmap_config->reg_defaults[i].def);
+1425
drivers/platform/x86/samsung-galaxybook.c
··· 1 + // SPDX-License-Identifier: GPL-2.0-or-later 2 + /* 3 + * Samsung Galaxy Book driver 4 + * 5 + * Copyright (c) 2025 Joshua Grisham <josh@joshuagrisham.com> 6 + * 7 + * With contributions to the SCAI ACPI device interface: 8 + * Copyright (c) 2024 Giulio Girardi <giulio.girardi@protechgroup.it> 9 + * 10 + * Implementation inspired by existing x86 platform drivers. 11 + * Thank you to the authors! 12 + */ 13 + 14 + #include <linux/acpi.h> 15 + #include <linux/bits.h> 16 + #include <linux/err.h> 17 + #include <linux/i8042.h> 18 + #include <linux/init.h> 19 + #include <linux/input.h> 20 + #include <linux/kernel.h> 21 + #include <linux/leds.h> 22 + #include <linux/module.h> 23 + #include <linux/mutex.h> 24 + #include <linux/platform_device.h> 25 + #include <linux/platform_profile.h> 26 + #include <linux/serio.h> 27 + #include <linux/sysfs.h> 28 + #include <linux/uuid.h> 29 + #include <linux/workqueue.h> 30 + #include <acpi/battery.h> 31 + #include "firmware_attributes_class.h" 32 + 33 + #define DRIVER_NAME "samsung-galaxybook" 34 + 35 + struct samsung_galaxybook { 36 + struct platform_device *platform; 37 + struct acpi_device *acpi; 38 + 39 + struct device *fw_attrs_dev; 40 + struct kset *fw_attrs_kset; 41 + /* block in case firmware attributes are updated in multiple threads */ 42 + struct mutex fw_attr_lock; 43 + 44 + bool has_kbd_backlight; 45 + bool has_block_recording; 46 + bool has_performance_mode; 47 + 48 + struct led_classdev kbd_backlight; 49 + struct work_struct kbd_backlight_hotkey_work; 50 + /* block in case brightness updated using hotkey and another thread */ 51 + struct mutex kbd_backlight_lock; 52 + 53 + void *i8042_filter_ptr; 54 + 55 + struct work_struct block_recording_hotkey_work; 56 + struct input_dev *camera_lens_cover_switch; 57 + 58 + struct acpi_battery_hook battery_hook; 59 + 60 + u8 profile_performance_modes[PLATFORM_PROFILE_LAST]; 61 + }; 62 + 63 + enum galaxybook_fw_attr_id { 64 + GB_ATTR_POWER_ON_LID_OPEN, 65 + GB_ATTR_USB_CHARGING, 66 + GB_ATTR_BLOCK_RECORDING, 67 + }; 68 + 69 + static const char * const galaxybook_fw_attr_name[] = { 70 + [GB_ATTR_POWER_ON_LID_OPEN] = "power_on_lid_open", 71 + [GB_ATTR_USB_CHARGING] = "usb_charging", 72 + [GB_ATTR_BLOCK_RECORDING] = "block_recording", 73 + }; 74 + 75 + static const char * const galaxybook_fw_attr_desc[] = { 76 + [GB_ATTR_POWER_ON_LID_OPEN] = "Power On Lid Open", 77 + [GB_ATTR_USB_CHARGING] = "USB Charging", 78 + [GB_ATTR_BLOCK_RECORDING] = "Block Recording", 79 + }; 80 + 81 + #define GB_ATTR_LANGUAGE_CODE "en_US.UTF-8" 82 + 83 + struct galaxybook_fw_attr { 84 + struct samsung_galaxybook *galaxybook; 85 + enum galaxybook_fw_attr_id fw_attr_id; 86 + struct attribute_group attr_group; 87 + struct kobj_attribute display_name; 88 + struct kobj_attribute current_value; 89 + int (*get_value)(struct samsung_galaxybook *galaxybook, bool *value); 90 + int (*set_value)(struct samsung_galaxybook *galaxybook, const bool value); 91 + }; 92 + 93 + struct sawb { 94 + u16 safn; 95 + u16 sasb; 96 + u8 rflg; 97 + union { 98 + struct { 99 + u8 gunm; 100 + u8 guds[250]; 101 + } __packed; 102 + struct { 103 + u8 caid[16]; 104 + u8 fncn; 105 + u8 subn; 106 + u8 iob0; 107 + u8 iob1; 108 + u8 iob2; 109 + u8 iob3; 110 + u8 iob4; 111 + u8 iob5; 112 + u8 iob6; 113 + u8 iob7; 114 + u8 iob8; 115 + u8 iob9; 116 + } __packed; 117 + struct { 118 + u8 iob_prefix[18]; 119 + u8 iobs[10]; 120 + } __packed; 121 + } __packed; 122 + } __packed; 123 + 124 + #define GB_SAWB_LEN_SETTINGS 0x15 125 + #define GB_SAWB_LEN_PERFORMANCE_MODE 0x100 126 + 127 + #define GB_SAFN 0x5843 128 + 129 + #define GB_SASB_KBD_BACKLIGHT 0x78 130 + #define GB_SASB_POWER_MANAGEMENT 0x7a 131 + #define GB_SASB_USB_CHARGING_GET 0x67 132 + #define GB_SASB_USB_CHARGING_SET 0x68 133 + #define GB_SASB_NOTIFICATIONS 0x86 134 + #define GB_SASB_BLOCK_RECORDING 0x8a 135 + #define GB_SASB_PERFORMANCE_MODE 0x91 136 + 137 + #define GB_SAWB_RFLG_POS 4 138 + #define GB_SAWB_GB_GUNM_POS 5 139 + 140 + #define GB_RFLG_SUCCESS 0xaa 141 + #define GB_GUNM_FAIL 0xff 142 + 143 + #define GB_GUNM_FEATURE_ENABLE 0xbb 144 + #define GB_GUNM_FEATURE_ENABLE_SUCCESS 0xdd 145 + #define GB_GUDS_FEATURE_ENABLE 0xaa 146 + #define GB_GUDS_FEATURE_ENABLE_SUCCESS 0xcc 147 + 148 + #define GB_GUNM_GET 0x81 149 + #define GB_GUNM_SET 0x82 150 + 151 + #define GB_GUNM_POWER_MANAGEMENT 0x82 152 + 153 + #define GB_GUNM_USB_CHARGING_GET 0x80 154 + #define GB_GUNM_USB_CHARGING_ON 0x81 155 + #define GB_GUNM_USB_CHARGING_OFF 0x80 156 + #define GB_GUDS_POWER_ON_LID_OPEN 0xa3 157 + #define GB_GUDS_POWER_ON_LID_OPEN_GET 0x81 158 + #define GB_GUDS_POWER_ON_LID_OPEN_SET 0x80 159 + #define GB_GUDS_BATTERY_CHARGE_CONTROL 0xe9 160 + #define GB_GUDS_BATTERY_CHARGE_CONTROL_GET 0x91 161 + #define GB_GUDS_BATTERY_CHARGE_CONTROL_SET 0x90 162 + #define GB_GUNM_ACPI_NOTIFY_ENABLE 0x80 163 + #define GB_GUDS_ACPI_NOTIFY_ENABLE 0x02 164 + 165 + #define GB_BLOCK_RECORDING_ON 0x0 166 + #define GB_BLOCK_RECORDING_OFF 0x1 167 + 168 + #define GB_FNCN_PERFORMANCE_MODE 0x51 169 + #define GB_SUBN_PERFORMANCE_MODE_LIST 0x01 170 + #define GB_SUBN_PERFORMANCE_MODE_GET 0x02 171 + #define GB_SUBN_PERFORMANCE_MODE_SET 0x03 172 + 173 + /* guid 8246028d-8bca-4a55-ba0f-6f1e6b921b8f */ 174 + static const guid_t performance_mode_guid = 175 + GUID_INIT(0x8246028d, 0x8bca, 0x4a55, 0xba, 0x0f, 0x6f, 0x1e, 0x6b, 0x92, 0x1b, 0x8f); 176 + #define GB_PERFORMANCE_MODE_GUID performance_mode_guid 177 + 178 + #define GB_PERFORMANCE_MODE_FANOFF 0xb 179 + #define GB_PERFORMANCE_MODE_LOWNOISE 0xa 180 + #define GB_PERFORMANCE_MODE_OPTIMIZED 0x0 181 + #define GB_PERFORMANCE_MODE_OPTIMIZED_V2 0x2 182 + #define GB_PERFORMANCE_MODE_PERFORMANCE 0x1 183 + #define GB_PERFORMANCE_MODE_PERFORMANCE_V2 0x15 184 + #define GB_PERFORMANCE_MODE_ULTRA 0x16 185 + #define GB_PERFORMANCE_MODE_IGNORE1 0x14 186 + #define GB_PERFORMANCE_MODE_IGNORE2 0xc 187 + 188 + #define GB_ACPI_METHOD_ENABLE "SDLS" 189 + #define GB_ACPI_METHOD_ENABLE_ON 1 190 + #define GB_ACPI_METHOD_ENABLE_OFF 0 191 + #define GB_ACPI_METHOD_SETTINGS "CSFI" 192 + #define GB_ACPI_METHOD_PERFORMANCE_MODE "CSXI" 193 + 194 + #define GB_KBD_BACKLIGHT_MAX_BRIGHTNESS 3 195 + 196 + #define GB_ACPI_NOTIFY_BATTERY_STATE_CHANGED 0x61 197 + #define GB_ACPI_NOTIFY_DEVICE_ON_TABLE 0x6c 198 + #define GB_ACPI_NOTIFY_DEVICE_OFF_TABLE 0x6d 199 + #define GB_ACPI_NOTIFY_HOTKEY_PERFORMANCE_MODE 0x70 200 + 201 + #define GB_KEY_KBD_BACKLIGHT_KEYDOWN 0x2c 202 + #define GB_KEY_KBD_BACKLIGHT_KEYUP 0xac 203 + #define GB_KEY_BLOCK_RECORDING_KEYDOWN 0x1f 204 + #define GB_KEY_BLOCK_RECORDING_KEYUP 0x9f 205 + #define GB_KEY_BATTERY_NOTIFY_KEYUP 0xf 206 + #define GB_KEY_BATTERY_NOTIFY_KEYDOWN 0x8f 207 + 208 + /* 209 + * Optional features which have been determined as not supported on a particular 210 + * device will return GB_NOT_SUPPORTED from their init function. Positive 211 + * EOPNOTSUPP is used as the underlying value instead of negative to 212 + * differentiate this return code from valid upstream failures. 213 + */ 214 + #define GB_NOT_SUPPORTED EOPNOTSUPP /* Galaxy Book feature not supported */ 215 + 216 + /* 217 + * ACPI method handling 218 + */ 219 + 220 + static int galaxybook_acpi_method(struct samsung_galaxybook *galaxybook, acpi_string method, 221 + struct sawb *buf, size_t len) 222 + { 223 + struct acpi_buffer output = {ACPI_ALLOCATE_BUFFER, NULL}; 224 + union acpi_object in_obj, *out_obj; 225 + struct acpi_object_list input; 226 + acpi_status status; 227 + int err; 228 + 229 + in_obj.type = ACPI_TYPE_BUFFER; 230 + in_obj.buffer.length = len; 231 + in_obj.buffer.pointer = (u8 *)buf; 232 + 233 + input.count = 1; 234 + input.pointer = &in_obj; 235 + 236 + status = acpi_evaluate_object_typed(galaxybook->acpi->handle, method, &input, &output, 237 + ACPI_TYPE_BUFFER); 238 + 239 + if (ACPI_FAILURE(status)) { 240 + dev_err(&galaxybook->acpi->dev, "failed to execute method %s; got %s\n", 241 + method, acpi_format_exception(status)); 242 + return -EIO; 243 + } 244 + 245 + out_obj = output.pointer; 246 + 247 + if (out_obj->buffer.length != len || out_obj->buffer.length < GB_SAWB_GB_GUNM_POS + 1) { 248 + dev_err(&galaxybook->acpi->dev, 249 + "failed to execute %s; response length mismatch\n", 250 + method); 251 + err = -EPROTO; 252 + goto out_free; 253 + } 254 + if (out_obj->buffer.pointer[GB_SAWB_RFLG_POS] != GB_RFLG_SUCCESS) { 255 + dev_err(&galaxybook->acpi->dev, 256 + "failed to execute %s; device did not respond with success code 0x%x\n", 257 + method, GB_RFLG_SUCCESS); 258 + err = -ENXIO; 259 + goto out_free; 260 + } 261 + if (out_obj->buffer.pointer[GB_SAWB_GB_GUNM_POS] == GB_GUNM_FAIL) { 262 + dev_err(&galaxybook->acpi->dev, 263 + "failed to execute %s; device responded with failure code 0x%x\n", 264 + method, GB_GUNM_FAIL); 265 + err = -ENXIO; 266 + goto out_free; 267 + } 268 + 269 + memcpy(buf, out_obj->buffer.pointer, len); 270 + err = 0; 271 + 272 + out_free: 273 + kfree(out_obj); 274 + return err; 275 + } 276 + 277 + static int galaxybook_enable_acpi_feature(struct samsung_galaxybook *galaxybook, const u16 sasb) 278 + { 279 + struct sawb buf = {}; 280 + int err; 281 + 282 + buf.safn = GB_SAFN; 283 + buf.sasb = sasb; 284 + buf.gunm = GB_GUNM_FEATURE_ENABLE; 285 + buf.guds[0] = GB_GUDS_FEATURE_ENABLE; 286 + 287 + err = galaxybook_acpi_method(galaxybook, GB_ACPI_METHOD_SETTINGS, 288 + &buf, GB_SAWB_LEN_SETTINGS); 289 + if (err) 290 + return err; 291 + 292 + if (buf.gunm != GB_GUNM_FEATURE_ENABLE_SUCCESS && 293 + buf.guds[0] != GB_GUDS_FEATURE_ENABLE_SUCCESS) 294 + return -ENODEV; 295 + 296 + return 0; 297 + } 298 + 299 + /* 300 + * Keyboard Backlight 301 + */ 302 + 303 + static int kbd_backlight_acpi_get(struct samsung_galaxybook *galaxybook, 304 + enum led_brightness *brightness) 305 + { 306 + struct sawb buf = {}; 307 + int err; 308 + 309 + buf.safn = GB_SAFN; 310 + buf.sasb = GB_SASB_KBD_BACKLIGHT; 311 + buf.gunm = GB_GUNM_GET; 312 + 313 + err = galaxybook_acpi_method(galaxybook, GB_ACPI_METHOD_SETTINGS, 314 + &buf, GB_SAWB_LEN_SETTINGS); 315 + if (err) 316 + return err; 317 + 318 + *brightness = buf.gunm; 319 + 320 + return 0; 321 + } 322 + 323 + static int kbd_backlight_acpi_set(struct samsung_galaxybook *galaxybook, 324 + const enum led_brightness brightness) 325 + { 326 + struct sawb buf = {}; 327 + 328 + buf.safn = GB_SAFN; 329 + buf.sasb = GB_SASB_KBD_BACKLIGHT; 330 + buf.gunm = GB_GUNM_SET; 331 + 332 + buf.guds[0] = brightness; 333 + 334 + return galaxybook_acpi_method(galaxybook, GB_ACPI_METHOD_SETTINGS, 335 + &buf, GB_SAWB_LEN_SETTINGS); 336 + } 337 + 338 + static enum led_brightness kbd_backlight_show(struct led_classdev *led) 339 + { 340 + struct samsung_galaxybook *galaxybook = 341 + container_of(led, struct samsung_galaxybook, kbd_backlight); 342 + enum led_brightness brightness; 343 + int err; 344 + 345 + err = kbd_backlight_acpi_get(galaxybook, &brightness); 346 + if (err) 347 + return err; 348 + 349 + return brightness; 350 + } 351 + 352 + static int kbd_backlight_store(struct led_classdev *led, 353 + const enum led_brightness brightness) 354 + { 355 + struct samsung_galaxybook *galaxybook = 356 + container_of_const(led, struct samsung_galaxybook, kbd_backlight); 357 + 358 + return kbd_backlight_acpi_set(galaxybook, brightness); 359 + } 360 + 361 + static int galaxybook_kbd_backlight_init(struct samsung_galaxybook *galaxybook) 362 + { 363 + struct led_init_data init_data = {}; 364 + enum led_brightness brightness; 365 + int err; 366 + 367 + err = devm_mutex_init(&galaxybook->platform->dev, &galaxybook->kbd_backlight_lock); 368 + if (err) 369 + return err; 370 + 371 + err = galaxybook_enable_acpi_feature(galaxybook, GB_SASB_KBD_BACKLIGHT); 372 + if (err) { 373 + dev_dbg(&galaxybook->platform->dev, 374 + "failed to enable kbd_backlight feature, error %d\n", err); 375 + return GB_NOT_SUPPORTED; 376 + } 377 + 378 + err = kbd_backlight_acpi_get(galaxybook, &brightness); 379 + if (err) { 380 + dev_dbg(&galaxybook->platform->dev, 381 + "failed to get initial kbd_backlight brightness, error %d\n", err); 382 + return GB_NOT_SUPPORTED; 383 + } 384 + 385 + init_data.devicename = DRIVER_NAME; 386 + init_data.default_label = ":" LED_FUNCTION_KBD_BACKLIGHT; 387 + init_data.devname_mandatory = true; 388 + 389 + galaxybook->kbd_backlight.brightness_get = kbd_backlight_show; 390 + galaxybook->kbd_backlight.brightness_set_blocking = kbd_backlight_store; 391 + galaxybook->kbd_backlight.flags = LED_BRIGHT_HW_CHANGED; 392 + galaxybook->kbd_backlight.max_brightness = GB_KBD_BACKLIGHT_MAX_BRIGHTNESS; 393 + 394 + return devm_led_classdev_register_ext(&galaxybook->platform->dev, 395 + &galaxybook->kbd_backlight, &init_data); 396 + } 397 + 398 + /* 399 + * Battery Extension (adds charge_control_end_threshold to the battery device) 400 + */ 401 + 402 + static int charge_control_end_threshold_acpi_get(struct samsung_galaxybook *galaxybook, u8 *value) 403 + { 404 + struct sawb buf = {}; 405 + int err; 406 + 407 + buf.safn = GB_SAFN; 408 + buf.sasb = GB_SASB_POWER_MANAGEMENT; 409 + buf.gunm = GB_GUNM_POWER_MANAGEMENT; 410 + buf.guds[0] = GB_GUDS_BATTERY_CHARGE_CONTROL; 411 + buf.guds[1] = GB_GUDS_BATTERY_CHARGE_CONTROL_GET; 412 + 413 + err = galaxybook_acpi_method(galaxybook, GB_ACPI_METHOD_SETTINGS, 414 + &buf, GB_SAWB_LEN_SETTINGS); 415 + if (err) 416 + return err; 417 + 418 + *value = buf.guds[1]; 419 + 420 + return 0; 421 + } 422 + 423 + static int charge_control_end_threshold_acpi_set(struct samsung_galaxybook *galaxybook, u8 value) 424 + { 425 + struct sawb buf = {}; 426 + 427 + buf.safn = GB_SAFN; 428 + buf.sasb = GB_SASB_POWER_MANAGEMENT; 429 + buf.gunm = GB_GUNM_POWER_MANAGEMENT; 430 + buf.guds[0] = GB_GUDS_BATTERY_CHARGE_CONTROL; 431 + buf.guds[1] = GB_GUDS_BATTERY_CHARGE_CONTROL_SET; 432 + buf.guds[2] = value; 433 + 434 + return galaxybook_acpi_method(galaxybook, GB_ACPI_METHOD_SETTINGS, 435 + &buf, GB_SAWB_LEN_SETTINGS); 436 + } 437 + 438 + static int galaxybook_battery_ext_property_get(struct power_supply *psy, 439 + const struct power_supply_ext *ext, 440 + void *ext_data, 441 + enum power_supply_property psp, 442 + union power_supply_propval *val) 443 + { 444 + struct samsung_galaxybook *galaxybook = ext_data; 445 + int err; 446 + 447 + if (psp != POWER_SUPPLY_PROP_CHARGE_CONTROL_END_THRESHOLD) 448 + return -EINVAL; 449 + 450 + err = charge_control_end_threshold_acpi_get(galaxybook, (u8 *)&val->intval); 451 + if (err) 452 + return err; 453 + 454 + /* 455 + * device stores "no end threshold" as 0 instead of 100; 456 + * if device has 0, report 100 457 + */ 458 + if (val->intval == 0) 459 + val->intval = 100; 460 + 461 + return 0; 462 + } 463 + 464 + static int galaxybook_battery_ext_property_set(struct power_supply *psy, 465 + const struct power_supply_ext *ext, 466 + void *ext_data, 467 + enum power_supply_property psp, 468 + const union power_supply_propval *val) 469 + { 470 + struct samsung_galaxybook *galaxybook = ext_data; 471 + u8 value; 472 + 473 + if (psp != POWER_SUPPLY_PROP_CHARGE_CONTROL_END_THRESHOLD) 474 + return -EINVAL; 475 + 476 + value = val->intval; 477 + 478 + if (value < 1 || value > 100) 479 + return -EINVAL; 480 + 481 + /* 482 + * device stores "no end threshold" as 0 instead of 100; 483 + * if setting to 100, send 0 484 + */ 485 + if (value == 100) 486 + value = 0; 487 + 488 + return charge_control_end_threshold_acpi_set(galaxybook, value); 489 + } 490 + 491 + static int galaxybook_battery_ext_property_is_writeable(struct power_supply *psy, 492 + const struct power_supply_ext *ext, 493 + void *ext_data, 494 + enum power_supply_property psp) 495 + { 496 + if (psp == POWER_SUPPLY_PROP_CHARGE_CONTROL_END_THRESHOLD) 497 + return true; 498 + 499 + return false; 500 + } 501 + 502 + static const enum power_supply_property galaxybook_battery_properties[] = { 503 + POWER_SUPPLY_PROP_CHARGE_CONTROL_END_THRESHOLD, 504 + }; 505 + 506 + static const struct power_supply_ext galaxybook_battery_ext = { 507 + .name = DRIVER_NAME, 508 + .properties = galaxybook_battery_properties, 509 + .num_properties = ARRAY_SIZE(galaxybook_battery_properties), 510 + .get_property = galaxybook_battery_ext_property_get, 511 + .set_property = galaxybook_battery_ext_property_set, 512 + .property_is_writeable = galaxybook_battery_ext_property_is_writeable, 513 + }; 514 + 515 + static int galaxybook_battery_add(struct power_supply *battery, struct acpi_battery_hook *hook) 516 + { 517 + struct samsung_galaxybook *galaxybook = 518 + container_of(hook, struct samsung_galaxybook, battery_hook); 519 + 520 + return power_supply_register_extension(battery, &galaxybook_battery_ext, 521 + &battery->dev, galaxybook); 522 + } 523 + 524 + static int galaxybook_battery_remove(struct power_supply *battery, struct acpi_battery_hook *hook) 525 + { 526 + power_supply_unregister_extension(battery, &galaxybook_battery_ext); 527 + return 0; 528 + } 529 + 530 + static int galaxybook_battery_threshold_init(struct samsung_galaxybook *galaxybook) 531 + { 532 + u8 value; 533 + int err; 534 + 535 + err = charge_control_end_threshold_acpi_get(galaxybook, &value); 536 + if (err) { 537 + dev_dbg(&galaxybook->platform->dev, 538 + "failed to get initial battery charge end threshold, error %d\n", err); 539 + return 0; 540 + } 541 + 542 + galaxybook->battery_hook.add_battery = galaxybook_battery_add; 543 + galaxybook->battery_hook.remove_battery = galaxybook_battery_remove; 544 + galaxybook->battery_hook.name = "Samsung Galaxy Book Battery Extension"; 545 + 546 + return devm_battery_hook_register(&galaxybook->platform->dev, &galaxybook->battery_hook); 547 + } 548 + 549 + /* 550 + * Platform Profile / Performance mode 551 + */ 552 + 553 + static int performance_mode_acpi_get(struct samsung_galaxybook *galaxybook, u8 *performance_mode) 554 + { 555 + struct sawb buf = {}; 556 + int err; 557 + 558 + buf.safn = GB_SAFN; 559 + buf.sasb = GB_SASB_PERFORMANCE_MODE; 560 + export_guid(buf.caid, &GB_PERFORMANCE_MODE_GUID); 561 + buf.fncn = GB_FNCN_PERFORMANCE_MODE; 562 + buf.subn = GB_SUBN_PERFORMANCE_MODE_GET; 563 + 564 + err = galaxybook_acpi_method(galaxybook, GB_ACPI_METHOD_PERFORMANCE_MODE, 565 + &buf, GB_SAWB_LEN_PERFORMANCE_MODE); 566 + if (err) 567 + return err; 568 + 569 + *performance_mode = buf.iob0; 570 + 571 + return 0; 572 + } 573 + 574 + static int performance_mode_acpi_set(struct samsung_galaxybook *galaxybook, 575 + const u8 performance_mode) 576 + { 577 + struct sawb buf = {}; 578 + 579 + buf.safn = GB_SAFN; 580 + buf.sasb = GB_SASB_PERFORMANCE_MODE; 581 + export_guid(buf.caid, &GB_PERFORMANCE_MODE_GUID); 582 + buf.fncn = GB_FNCN_PERFORMANCE_MODE; 583 + buf.subn = GB_SUBN_PERFORMANCE_MODE_SET; 584 + buf.iob0 = performance_mode; 585 + 586 + return galaxybook_acpi_method(galaxybook, GB_ACPI_METHOD_PERFORMANCE_MODE, 587 + &buf, GB_SAWB_LEN_PERFORMANCE_MODE); 588 + } 589 + 590 + static int get_performance_mode_profile(struct samsung_galaxybook *galaxybook, 591 + const u8 performance_mode, 592 + enum platform_profile_option *profile) 593 + { 594 + switch (performance_mode) { 595 + case GB_PERFORMANCE_MODE_FANOFF: 596 + *profile = PLATFORM_PROFILE_LOW_POWER; 597 + break; 598 + case GB_PERFORMANCE_MODE_LOWNOISE: 599 + *profile = PLATFORM_PROFILE_QUIET; 600 + break; 601 + case GB_PERFORMANCE_MODE_OPTIMIZED: 602 + case GB_PERFORMANCE_MODE_OPTIMIZED_V2: 603 + *profile = PLATFORM_PROFILE_BALANCED; 604 + break; 605 + case GB_PERFORMANCE_MODE_PERFORMANCE: 606 + case GB_PERFORMANCE_MODE_PERFORMANCE_V2: 607 + case GB_PERFORMANCE_MODE_ULTRA: 608 + *profile = PLATFORM_PROFILE_PERFORMANCE; 609 + break; 610 + case GB_PERFORMANCE_MODE_IGNORE1: 611 + case GB_PERFORMANCE_MODE_IGNORE2: 612 + return -EOPNOTSUPP; 613 + default: 614 + dev_warn(&galaxybook->platform->dev, 615 + "unrecognized performance mode 0x%x\n", performance_mode); 616 + return -EOPNOTSUPP; 617 + } 618 + 619 + return 0; 620 + } 621 + 622 + static int galaxybook_platform_profile_get(struct device *dev, 623 + enum platform_profile_option *profile) 624 + { 625 + struct samsung_galaxybook *galaxybook = dev_get_drvdata(dev); 626 + u8 performance_mode; 627 + int err; 628 + 629 + err = performance_mode_acpi_get(galaxybook, &performance_mode); 630 + if (err) 631 + return err; 632 + 633 + return get_performance_mode_profile(galaxybook, performance_mode, profile); 634 + } 635 + 636 + static int galaxybook_platform_profile_set(struct device *dev, 637 + enum platform_profile_option profile) 638 + { 639 + struct samsung_galaxybook *galaxybook = dev_get_drvdata(dev); 640 + 641 + return performance_mode_acpi_set(galaxybook, 642 + galaxybook->profile_performance_modes[profile]); 643 + } 644 + 645 + static int galaxybook_platform_profile_probe(void *drvdata, unsigned long *choices) 646 + { 647 + struct samsung_galaxybook *galaxybook = drvdata; 648 + u8 *perfmodes = galaxybook->profile_performance_modes; 649 + enum platform_profile_option profile; 650 + struct sawb buf = {}; 651 + unsigned int i; 652 + int err; 653 + 654 + buf.safn = GB_SAFN; 655 + buf.sasb = GB_SASB_PERFORMANCE_MODE; 656 + export_guid(buf.caid, &GB_PERFORMANCE_MODE_GUID); 657 + buf.fncn = GB_FNCN_PERFORMANCE_MODE; 658 + buf.subn = GB_SUBN_PERFORMANCE_MODE_LIST; 659 + 660 + err = galaxybook_acpi_method(galaxybook, GB_ACPI_METHOD_PERFORMANCE_MODE, 661 + &buf, GB_SAWB_LEN_PERFORMANCE_MODE); 662 + if (err) { 663 + dev_dbg(&galaxybook->platform->dev, 664 + "failed to get supported performance modes, error %d\n", err); 665 + return err; 666 + } 667 + 668 + /* set initial default profile performance mode values */ 669 + perfmodes[PLATFORM_PROFILE_LOW_POWER] = GB_PERFORMANCE_MODE_FANOFF; 670 + perfmodes[PLATFORM_PROFILE_QUIET] = GB_PERFORMANCE_MODE_LOWNOISE; 671 + perfmodes[PLATFORM_PROFILE_BALANCED] = GB_PERFORMANCE_MODE_OPTIMIZED; 672 + perfmodes[PLATFORM_PROFILE_PERFORMANCE] = GB_PERFORMANCE_MODE_PERFORMANCE; 673 + 674 + /* 675 + * Value returned in iob0 will have the number of supported performance 676 + * modes per device. The performance mode values will then be given as a 677 + * list after this (iob1-iobX). Loop through the supported values and 678 + * enable their mapped platform_profile choice, overriding "legacy" 679 + * values along the way if a non-legacy value exists. 680 + */ 681 + for (i = 1; i <= buf.iob0; i++) { 682 + err = get_performance_mode_profile(galaxybook, buf.iobs[i], &profile); 683 + if (err) { 684 + dev_dbg(&galaxybook->platform->dev, 685 + "ignoring unmapped performance mode 0x%x\n", buf.iobs[i]); 686 + continue; 687 + } 688 + switch (buf.iobs[i]) { 689 + case GB_PERFORMANCE_MODE_OPTIMIZED_V2: 690 + perfmodes[profile] = GB_PERFORMANCE_MODE_OPTIMIZED_V2; 691 + break; 692 + case GB_PERFORMANCE_MODE_PERFORMANCE_V2: 693 + /* only update if not already overwritten by Ultra */ 694 + if (perfmodes[profile] != GB_PERFORMANCE_MODE_ULTRA) 695 + perfmodes[profile] = GB_PERFORMANCE_MODE_PERFORMANCE_V2; 696 + break; 697 + case GB_PERFORMANCE_MODE_ULTRA: 698 + perfmodes[profile] = GB_PERFORMANCE_MODE_ULTRA; 699 + break; 700 + default: 701 + break; 702 + } 703 + set_bit(profile, choices); 704 + dev_dbg(&galaxybook->platform->dev, 705 + "setting platform profile %d to use performance mode 0x%x\n", 706 + profile, perfmodes[profile]); 707 + } 708 + 709 + /* initialize performance_mode using balanced's mapped value */ 710 + if (test_bit(PLATFORM_PROFILE_BALANCED, choices)) 711 + return performance_mode_acpi_set(galaxybook, perfmodes[PLATFORM_PROFILE_BALANCED]); 712 + 713 + return 0; 714 + } 715 + 716 + static const struct platform_profile_ops galaxybook_platform_profile_ops = { 717 + .probe = galaxybook_platform_profile_probe, 718 + .profile_get = galaxybook_platform_profile_get, 719 + .profile_set = galaxybook_platform_profile_set, 720 + }; 721 + 722 + static int galaxybook_platform_profile_init(struct samsung_galaxybook *galaxybook) 723 + { 724 + struct device *platform_profile_dev; 725 + u8 performance_mode; 726 + int err; 727 + 728 + err = performance_mode_acpi_get(galaxybook, &performance_mode); 729 + if (err) { 730 + dev_dbg(&galaxybook->platform->dev, 731 + "failed to get initial performance mode, error %d\n", err); 732 + return GB_NOT_SUPPORTED; 733 + } 734 + 735 + platform_profile_dev = devm_platform_profile_register(&galaxybook->platform->dev, 736 + DRIVER_NAME, galaxybook, 737 + &galaxybook_platform_profile_ops); 738 + 739 + return PTR_ERR_OR_ZERO(platform_profile_dev); 740 + } 741 + 742 + /* 743 + * Firmware Attributes 744 + */ 745 + 746 + /* Power on lid open (device should power on when lid is opened) */ 747 + 748 + static int power_on_lid_open_acpi_get(struct samsung_galaxybook *galaxybook, bool *value) 749 + { 750 + struct sawb buf = {}; 751 + int err; 752 + 753 + buf.safn = GB_SAFN; 754 + buf.sasb = GB_SASB_POWER_MANAGEMENT; 755 + buf.gunm = GB_GUNM_POWER_MANAGEMENT; 756 + buf.guds[0] = GB_GUDS_POWER_ON_LID_OPEN; 757 + buf.guds[1] = GB_GUDS_POWER_ON_LID_OPEN_GET; 758 + 759 + err = galaxybook_acpi_method(galaxybook, GB_ACPI_METHOD_SETTINGS, 760 + &buf, GB_SAWB_LEN_SETTINGS); 761 + if (err) 762 + return err; 763 + 764 + *value = buf.guds[1]; 765 + 766 + return 0; 767 + } 768 + 769 + static int power_on_lid_open_acpi_set(struct samsung_galaxybook *galaxybook, const bool value) 770 + { 771 + struct sawb buf = {}; 772 + 773 + lockdep_assert_held(&galaxybook->fw_attr_lock); 774 + 775 + buf.safn = GB_SAFN; 776 + buf.sasb = GB_SASB_POWER_MANAGEMENT; 777 + buf.gunm = GB_GUNM_POWER_MANAGEMENT; 778 + buf.guds[0] = GB_GUDS_POWER_ON_LID_OPEN; 779 + buf.guds[1] = GB_GUDS_POWER_ON_LID_OPEN_SET; 780 + buf.guds[2] = value ? 1 : 0; 781 + 782 + return galaxybook_acpi_method(galaxybook, GB_ACPI_METHOD_SETTINGS, 783 + &buf, GB_SAWB_LEN_SETTINGS); 784 + } 785 + 786 + /* USB Charging (USB ports can provide power when device is powered off) */ 787 + 788 + static int usb_charging_acpi_get(struct samsung_galaxybook *galaxybook, bool *value) 789 + { 790 + struct sawb buf = {}; 791 + int err; 792 + 793 + buf.safn = GB_SAFN; 794 + buf.sasb = GB_SASB_USB_CHARGING_GET; 795 + buf.gunm = GB_GUNM_USB_CHARGING_GET; 796 + 797 + err = galaxybook_acpi_method(galaxybook, GB_ACPI_METHOD_SETTINGS, 798 + &buf, GB_SAWB_LEN_SETTINGS); 799 + if (err) 800 + return err; 801 + 802 + *value = buf.gunm == 1; 803 + 804 + return 0; 805 + } 806 + 807 + static int usb_charging_acpi_set(struct samsung_galaxybook *galaxybook, const bool value) 808 + { 809 + struct sawb buf = {}; 810 + 811 + lockdep_assert_held(&galaxybook->fw_attr_lock); 812 + 813 + buf.safn = GB_SAFN; 814 + buf.sasb = GB_SASB_USB_CHARGING_SET; 815 + buf.gunm = value ? GB_GUNM_USB_CHARGING_ON : GB_GUNM_USB_CHARGING_OFF; 816 + 817 + return galaxybook_acpi_method(galaxybook, GB_ACPI_METHOD_SETTINGS, 818 + &buf, GB_SAWB_LEN_SETTINGS); 819 + } 820 + 821 + /* Block recording (blocks access to camera and microphone) */ 822 + 823 + static int block_recording_acpi_get(struct samsung_galaxybook *galaxybook, bool *value) 824 + { 825 + struct sawb buf = {}; 826 + int err; 827 + 828 + buf.safn = GB_SAFN; 829 + buf.sasb = GB_SASB_BLOCK_RECORDING; 830 + buf.gunm = GB_GUNM_GET; 831 + 832 + err = galaxybook_acpi_method(galaxybook, GB_ACPI_METHOD_SETTINGS, 833 + &buf, GB_SAWB_LEN_SETTINGS); 834 + if (err) 835 + return err; 836 + 837 + *value = buf.gunm == GB_BLOCK_RECORDING_ON; 838 + 839 + return 0; 840 + } 841 + 842 + static int block_recording_acpi_set(struct samsung_galaxybook *galaxybook, const bool value) 843 + { 844 + struct sawb buf = {}; 845 + int err; 846 + 847 + lockdep_assert_held(&galaxybook->fw_attr_lock); 848 + 849 + buf.safn = GB_SAFN; 850 + buf.sasb = GB_SASB_BLOCK_RECORDING; 851 + buf.gunm = GB_GUNM_SET; 852 + buf.guds[0] = value ? GB_BLOCK_RECORDING_ON : GB_BLOCK_RECORDING_OFF; 853 + 854 + err = galaxybook_acpi_method(galaxybook, GB_ACPI_METHOD_SETTINGS, 855 + &buf, GB_SAWB_LEN_SETTINGS); 856 + if (err) 857 + return err; 858 + 859 + input_report_switch(galaxybook->camera_lens_cover_switch, 860 + SW_CAMERA_LENS_COVER, value ? 1 : 0); 861 + input_sync(galaxybook->camera_lens_cover_switch); 862 + 863 + return 0; 864 + } 865 + 866 + static int galaxybook_block_recording_init(struct samsung_galaxybook *galaxybook) 867 + { 868 + bool value; 869 + int err; 870 + 871 + err = galaxybook_enable_acpi_feature(galaxybook, GB_SASB_BLOCK_RECORDING); 872 + if (err) { 873 + dev_dbg(&galaxybook->platform->dev, 874 + "failed to initialize block_recording, error %d\n", err); 875 + return GB_NOT_SUPPORTED; 876 + } 877 + 878 + guard(mutex)(&galaxybook->fw_attr_lock); 879 + 880 + err = block_recording_acpi_get(galaxybook, &value); 881 + if (err) { 882 + dev_dbg(&galaxybook->platform->dev, 883 + "failed to get initial block_recording state, error %d\n", err); 884 + return GB_NOT_SUPPORTED; 885 + } 886 + 887 + galaxybook->camera_lens_cover_switch = 888 + devm_input_allocate_device(&galaxybook->platform->dev); 889 + if (!galaxybook->camera_lens_cover_switch) 890 + return -ENOMEM; 891 + 892 + galaxybook->camera_lens_cover_switch->name = "Samsung Galaxy Book Camera Lens Cover"; 893 + galaxybook->camera_lens_cover_switch->phys = DRIVER_NAME "/input0"; 894 + galaxybook->camera_lens_cover_switch->id.bustype = BUS_HOST; 895 + 896 + input_set_capability(galaxybook->camera_lens_cover_switch, EV_SW, SW_CAMERA_LENS_COVER); 897 + 898 + err = input_register_device(galaxybook->camera_lens_cover_switch); 899 + if (err) 900 + return err; 901 + 902 + input_report_switch(galaxybook->camera_lens_cover_switch, 903 + SW_CAMERA_LENS_COVER, value ? 1 : 0); 904 + input_sync(galaxybook->camera_lens_cover_switch); 905 + 906 + return 0; 907 + } 908 + 909 + /* Firmware Attributes setup */ 910 + 911 + static ssize_t type_show(struct kobject *kobj, struct kobj_attribute *attr, char *buf) 912 + { 913 + return sysfs_emit(buf, "enumeration\n"); 914 + } 915 + 916 + static struct kobj_attribute fw_attr_type = __ATTR_RO(type); 917 + 918 + static ssize_t default_value_show(struct kobject *kobj, struct kobj_attribute *attr, char *buf) 919 + { 920 + return sysfs_emit(buf, "0\n"); 921 + } 922 + 923 + static struct kobj_attribute fw_attr_default_value = __ATTR_RO(default_value); 924 + 925 + static ssize_t possible_values_show(struct kobject *kobj, struct kobj_attribute *attr, char *buf) 926 + { 927 + return sysfs_emit(buf, "0;1\n"); 928 + } 929 + 930 + static struct kobj_attribute fw_attr_possible_values = __ATTR_RO(possible_values); 931 + 932 + static ssize_t display_name_language_code_show(struct kobject *kobj, struct kobj_attribute *attr, 933 + char *buf) 934 + { 935 + return sysfs_emit(buf, "%s\n", GB_ATTR_LANGUAGE_CODE); 936 + } 937 + 938 + static struct kobj_attribute fw_attr_display_name_language_code = 939 + __ATTR_RO(display_name_language_code); 940 + 941 + static ssize_t display_name_show(struct kobject *kobj, struct kobj_attribute *attr, char *buf) 942 + { 943 + struct galaxybook_fw_attr *fw_attr = 944 + container_of(attr, struct galaxybook_fw_attr, display_name); 945 + 946 + return sysfs_emit(buf, "%s\n", galaxybook_fw_attr_desc[fw_attr->fw_attr_id]); 947 + } 948 + 949 + static ssize_t current_value_show(struct kobject *kobj, struct kobj_attribute *attr, char *buf) 950 + { 951 + struct galaxybook_fw_attr *fw_attr = 952 + container_of(attr, struct galaxybook_fw_attr, current_value); 953 + bool value; 954 + int err; 955 + 956 + err = fw_attr->get_value(fw_attr->galaxybook, &value); 957 + if (err) 958 + return err; 959 + 960 + return sysfs_emit(buf, "%u\n", value); 961 + } 962 + 963 + static ssize_t current_value_store(struct kobject *kobj, struct kobj_attribute *attr, 964 + const char *buf, size_t count) 965 + { 966 + struct galaxybook_fw_attr *fw_attr = 967 + container_of(attr, struct galaxybook_fw_attr, current_value); 968 + struct samsung_galaxybook *galaxybook = fw_attr->galaxybook; 969 + bool value; 970 + int err; 971 + 972 + if (!count) 973 + return -EINVAL; 974 + 975 + err = kstrtobool(buf, &value); 976 + if (err) 977 + return err; 978 + 979 + guard(mutex)(&galaxybook->fw_attr_lock); 980 + 981 + err = fw_attr->set_value(galaxybook, value); 982 + if (err) 983 + return err; 984 + 985 + return count; 986 + } 987 + 988 + #define NUM_FW_ATTR_ENUM_ATTRS 6 989 + 990 + static int galaxybook_fw_attr_init(struct samsung_galaxybook *galaxybook, 991 + const enum galaxybook_fw_attr_id fw_attr_id, 992 + int (*get_value)(struct samsung_galaxybook *galaxybook, 993 + bool *value), 994 + int (*set_value)(struct samsung_galaxybook *galaxybook, 995 + const bool value)) 996 + { 997 + struct galaxybook_fw_attr *fw_attr; 998 + struct attribute **attrs; 999 + 1000 + fw_attr = devm_kzalloc(&galaxybook->platform->dev, sizeof(*fw_attr), GFP_KERNEL); 1001 + if (!fw_attr) 1002 + return -ENOMEM; 1003 + 1004 + attrs = devm_kcalloc(&galaxybook->platform->dev, NUM_FW_ATTR_ENUM_ATTRS + 1, 1005 + sizeof(*attrs), GFP_KERNEL); 1006 + if (!attrs) 1007 + return -ENOMEM; 1008 + 1009 + attrs[0] = &fw_attr_type.attr; 1010 + attrs[1] = &fw_attr_default_value.attr; 1011 + attrs[2] = &fw_attr_possible_values.attr; 1012 + attrs[3] = &fw_attr_display_name_language_code.attr; 1013 + 1014 + sysfs_attr_init(&fw_attr->display_name.attr); 1015 + fw_attr->display_name.attr.name = "display_name"; 1016 + fw_attr->display_name.attr.mode = 0444; 1017 + fw_attr->display_name.show = display_name_show; 1018 + attrs[4] = &fw_attr->display_name.attr; 1019 + 1020 + sysfs_attr_init(&fw_attr->current_value.attr); 1021 + fw_attr->current_value.attr.name = "current_value"; 1022 + fw_attr->current_value.attr.mode = 0644; 1023 + fw_attr->current_value.show = current_value_show; 1024 + fw_attr->current_value.store = current_value_store; 1025 + attrs[5] = &fw_attr->current_value.attr; 1026 + 1027 + attrs[6] = NULL; 1028 + 1029 + fw_attr->galaxybook = galaxybook; 1030 + fw_attr->fw_attr_id = fw_attr_id; 1031 + fw_attr->attr_group.name = galaxybook_fw_attr_name[fw_attr_id]; 1032 + fw_attr->attr_group.attrs = attrs; 1033 + fw_attr->get_value = get_value; 1034 + fw_attr->set_value = set_value; 1035 + 1036 + return sysfs_create_group(&galaxybook->fw_attrs_kset->kobj, &fw_attr->attr_group); 1037 + } 1038 + 1039 + static void galaxybook_kset_unregister(void *data) 1040 + { 1041 + struct kset *kset = data; 1042 + 1043 + kset_unregister(kset); 1044 + } 1045 + 1046 + static void galaxybook_fw_attrs_dev_unregister(void *data) 1047 + { 1048 + struct device *fw_attrs_dev = data; 1049 + 1050 + device_unregister(fw_attrs_dev); 1051 + } 1052 + 1053 + static int galaxybook_fw_attrs_init(struct samsung_galaxybook *galaxybook) 1054 + { 1055 + bool value; 1056 + int err; 1057 + 1058 + err = devm_mutex_init(&galaxybook->platform->dev, &galaxybook->fw_attr_lock); 1059 + if (err) 1060 + return err; 1061 + 1062 + galaxybook->fw_attrs_dev = device_create(&firmware_attributes_class, NULL, MKDEV(0, 0), 1063 + NULL, "%s", DRIVER_NAME); 1064 + if (IS_ERR(galaxybook->fw_attrs_dev)) 1065 + return PTR_ERR(galaxybook->fw_attrs_dev); 1066 + 1067 + err = devm_add_action_or_reset(&galaxybook->platform->dev, 1068 + galaxybook_fw_attrs_dev_unregister, 1069 + galaxybook->fw_attrs_dev); 1070 + if (err) 1071 + return err; 1072 + 1073 + galaxybook->fw_attrs_kset = kset_create_and_add("attributes", NULL, 1074 + &galaxybook->fw_attrs_dev->kobj); 1075 + if (!galaxybook->fw_attrs_kset) 1076 + return -ENOMEM; 1077 + err = devm_add_action_or_reset(&galaxybook->platform->dev, 1078 + galaxybook_kset_unregister, galaxybook->fw_attrs_kset); 1079 + if (err) 1080 + return err; 1081 + 1082 + err = power_on_lid_open_acpi_get(galaxybook, &value); 1083 + if (!err) { 1084 + err = galaxybook_fw_attr_init(galaxybook, 1085 + GB_ATTR_POWER_ON_LID_OPEN, 1086 + &power_on_lid_open_acpi_get, 1087 + &power_on_lid_open_acpi_set); 1088 + if (err) 1089 + return err; 1090 + } 1091 + 1092 + err = usb_charging_acpi_get(galaxybook, &value); 1093 + if (!err) { 1094 + err = galaxybook_fw_attr_init(galaxybook, 1095 + GB_ATTR_USB_CHARGING, 1096 + &usb_charging_acpi_get, 1097 + &usb_charging_acpi_set); 1098 + if (err) 1099 + return err; 1100 + } 1101 + 1102 + err = galaxybook_block_recording_init(galaxybook); 1103 + if (err == GB_NOT_SUPPORTED) 1104 + return 0; 1105 + else if (err) 1106 + return err; 1107 + 1108 + galaxybook->has_block_recording = true; 1109 + 1110 + return galaxybook_fw_attr_init(galaxybook, 1111 + GB_ATTR_BLOCK_RECORDING, 1112 + &block_recording_acpi_get, 1113 + &block_recording_acpi_set); 1114 + } 1115 + 1116 + /* 1117 + * Hotkeys and notifications 1118 + */ 1119 + 1120 + static void galaxybook_kbd_backlight_hotkey_work(struct work_struct *work) 1121 + { 1122 + struct samsung_galaxybook *galaxybook = 1123 + from_work(galaxybook, work, kbd_backlight_hotkey_work); 1124 + int brightness; 1125 + int err; 1126 + 1127 + guard(mutex)(&galaxybook->kbd_backlight_lock); 1128 + 1129 + brightness = galaxybook->kbd_backlight.brightness; 1130 + if (brightness < galaxybook->kbd_backlight.max_brightness) 1131 + brightness++; 1132 + else 1133 + brightness = 0; 1134 + 1135 + err = led_set_brightness_sync(&galaxybook->kbd_backlight, brightness); 1136 + if (err) { 1137 + dev_err(&galaxybook->platform->dev, 1138 + "failed to set kbd_backlight brightness, error %d\n", err); 1139 + return; 1140 + } 1141 + 1142 + led_classdev_notify_brightness_hw_changed(&galaxybook->kbd_backlight, brightness); 1143 + } 1144 + 1145 + static void galaxybook_block_recording_hotkey_work(struct work_struct *work) 1146 + { 1147 + struct samsung_galaxybook *galaxybook = 1148 + from_work(galaxybook, work, block_recording_hotkey_work); 1149 + bool value; 1150 + int err; 1151 + 1152 + guard(mutex)(&galaxybook->fw_attr_lock); 1153 + 1154 + err = block_recording_acpi_get(galaxybook, &value); 1155 + if (err) { 1156 + dev_err(&galaxybook->platform->dev, 1157 + "failed to get block_recording, error %d\n", err); 1158 + return; 1159 + } 1160 + 1161 + err = block_recording_acpi_set(galaxybook, !value); 1162 + if (err) 1163 + dev_err(&galaxybook->platform->dev, 1164 + "failed to set block_recording, error %d\n", err); 1165 + } 1166 + 1167 + static bool galaxybook_i8042_filter(unsigned char data, unsigned char str, struct serio *port, 1168 + void *context) 1169 + { 1170 + struct samsung_galaxybook *galaxybook = context; 1171 + static bool extended; 1172 + 1173 + if (str & I8042_STR_AUXDATA) 1174 + return false; 1175 + 1176 + if (data == 0xe0) { 1177 + extended = true; 1178 + return true; 1179 + } else if (extended) { 1180 + extended = false; 1181 + switch (data) { 1182 + case GB_KEY_KBD_BACKLIGHT_KEYDOWN: 1183 + return true; 1184 + case GB_KEY_KBD_BACKLIGHT_KEYUP: 1185 + if (galaxybook->has_kbd_backlight) 1186 + schedule_work(&galaxybook->kbd_backlight_hotkey_work); 1187 + return true; 1188 + 1189 + case GB_KEY_BLOCK_RECORDING_KEYDOWN: 1190 + return true; 1191 + case GB_KEY_BLOCK_RECORDING_KEYUP: 1192 + if (galaxybook->has_block_recording) 1193 + schedule_work(&galaxybook->block_recording_hotkey_work); 1194 + return true; 1195 + 1196 + /* battery notification already sent to battery + SCAI device */ 1197 + case GB_KEY_BATTERY_NOTIFY_KEYUP: 1198 + case GB_KEY_BATTERY_NOTIFY_KEYDOWN: 1199 + return true; 1200 + 1201 + default: 1202 + /* 1203 + * Report the previously filtered e0 before continuing 1204 + * with the next non-filtered byte. 1205 + */ 1206 + serio_interrupt(port, 0xe0, 0); 1207 + return false; 1208 + } 1209 + } 1210 + 1211 + return false; 1212 + } 1213 + 1214 + static void galaxybook_i8042_filter_remove(void *data) 1215 + { 1216 + struct samsung_galaxybook *galaxybook = data; 1217 + 1218 + i8042_remove_filter(galaxybook_i8042_filter); 1219 + cancel_work_sync(&galaxybook->kbd_backlight_hotkey_work); 1220 + cancel_work_sync(&galaxybook->block_recording_hotkey_work); 1221 + } 1222 + 1223 + static int galaxybook_i8042_filter_install(struct samsung_galaxybook *galaxybook) 1224 + { 1225 + int err; 1226 + 1227 + if (!galaxybook->has_kbd_backlight && !galaxybook->has_block_recording) 1228 + return 0; 1229 + 1230 + INIT_WORK(&galaxybook->kbd_backlight_hotkey_work, 1231 + galaxybook_kbd_backlight_hotkey_work); 1232 + INIT_WORK(&galaxybook->block_recording_hotkey_work, 1233 + galaxybook_block_recording_hotkey_work); 1234 + 1235 + err = i8042_install_filter(galaxybook_i8042_filter, galaxybook); 1236 + if (err) 1237 + return err; 1238 + 1239 + return devm_add_action_or_reset(&galaxybook->platform->dev, 1240 + galaxybook_i8042_filter_remove, galaxybook); 1241 + } 1242 + 1243 + /* 1244 + * ACPI device setup 1245 + */ 1246 + 1247 + static void galaxybook_acpi_notify(acpi_handle handle, u32 event, void *data) 1248 + { 1249 + struct samsung_galaxybook *galaxybook = data; 1250 + 1251 + switch (event) { 1252 + case GB_ACPI_NOTIFY_BATTERY_STATE_CHANGED: 1253 + case GB_ACPI_NOTIFY_DEVICE_ON_TABLE: 1254 + case GB_ACPI_NOTIFY_DEVICE_OFF_TABLE: 1255 + break; 1256 + case GB_ACPI_NOTIFY_HOTKEY_PERFORMANCE_MODE: 1257 + if (galaxybook->has_performance_mode) 1258 + platform_profile_cycle(); 1259 + break; 1260 + default: 1261 + dev_warn(&galaxybook->platform->dev, 1262 + "unknown ACPI notification event: 0x%x\n", event); 1263 + } 1264 + 1265 + acpi_bus_generate_netlink_event(DRIVER_NAME, dev_name(&galaxybook->platform->dev), 1266 + event, 1); 1267 + } 1268 + 1269 + static int galaxybook_enable_acpi_notify(struct samsung_galaxybook *galaxybook) 1270 + { 1271 + struct sawb buf = {}; 1272 + int err; 1273 + 1274 + err = galaxybook_enable_acpi_feature(galaxybook, GB_SASB_NOTIFICATIONS); 1275 + if (err) 1276 + return err; 1277 + 1278 + buf.safn = GB_SAFN; 1279 + buf.sasb = GB_SASB_NOTIFICATIONS; 1280 + buf.gunm = GB_GUNM_ACPI_NOTIFY_ENABLE; 1281 + buf.guds[0] = GB_GUDS_ACPI_NOTIFY_ENABLE; 1282 + 1283 + return galaxybook_acpi_method(galaxybook, GB_ACPI_METHOD_SETTINGS, 1284 + &buf, GB_SAWB_LEN_SETTINGS); 1285 + } 1286 + 1287 + static void galaxybook_acpi_remove_notify_handler(void *data) 1288 + { 1289 + struct samsung_galaxybook *galaxybook = data; 1290 + 1291 + acpi_remove_notify_handler(galaxybook->acpi->handle, ACPI_ALL_NOTIFY, 1292 + galaxybook_acpi_notify); 1293 + } 1294 + 1295 + static void galaxybook_acpi_disable(void *data) 1296 + { 1297 + struct samsung_galaxybook *galaxybook = data; 1298 + 1299 + acpi_execute_simple_method(galaxybook->acpi->handle, 1300 + GB_ACPI_METHOD_ENABLE, GB_ACPI_METHOD_ENABLE_OFF); 1301 + } 1302 + 1303 + static int galaxybook_acpi_init(struct samsung_galaxybook *galaxybook) 1304 + { 1305 + acpi_status status; 1306 + int err; 1307 + 1308 + status = acpi_execute_simple_method(galaxybook->acpi->handle, GB_ACPI_METHOD_ENABLE, 1309 + GB_ACPI_METHOD_ENABLE_ON); 1310 + if (ACPI_FAILURE(status)) 1311 + return -EIO; 1312 + err = devm_add_action_or_reset(&galaxybook->platform->dev, 1313 + galaxybook_acpi_disable, galaxybook); 1314 + if (err) 1315 + return err; 1316 + 1317 + status = acpi_install_notify_handler(galaxybook->acpi->handle, ACPI_ALL_NOTIFY, 1318 + galaxybook_acpi_notify, galaxybook); 1319 + if (ACPI_FAILURE(status)) 1320 + return -EIO; 1321 + err = devm_add_action_or_reset(&galaxybook->platform->dev, 1322 + galaxybook_acpi_remove_notify_handler, galaxybook); 1323 + if (err) 1324 + return err; 1325 + 1326 + err = galaxybook_enable_acpi_notify(galaxybook); 1327 + if (err) 1328 + dev_dbg(&galaxybook->platform->dev, "failed to enable ACPI notifications; " 1329 + "some hotkeys will not be supported\n"); 1330 + 1331 + err = galaxybook_enable_acpi_feature(galaxybook, GB_SASB_POWER_MANAGEMENT); 1332 + if (err) 1333 + dev_dbg(&galaxybook->platform->dev, 1334 + "failed to initialize ACPI power management features; " 1335 + "many features of this driver will not be available\n"); 1336 + 1337 + return 0; 1338 + } 1339 + 1340 + /* 1341 + * Platform driver 1342 + */ 1343 + 1344 + static int galaxybook_probe(struct platform_device *pdev) 1345 + { 1346 + struct acpi_device *adev = ACPI_COMPANION(&pdev->dev); 1347 + struct samsung_galaxybook *galaxybook; 1348 + int err; 1349 + 1350 + if (!adev) 1351 + return -ENODEV; 1352 + 1353 + galaxybook = devm_kzalloc(&pdev->dev, sizeof(*galaxybook), GFP_KERNEL); 1354 + if (!galaxybook) 1355 + return -ENOMEM; 1356 + 1357 + galaxybook->platform = pdev; 1358 + galaxybook->acpi = adev; 1359 + 1360 + /* 1361 + * Features must be enabled and initialized in the following order to 1362 + * avoid failures seen on certain devices: 1363 + * - GB_SASB_POWER_MANAGEMENT (including performance mode) 1364 + * - GB_SASB_KBD_BACKLIGHT 1365 + * - GB_SASB_BLOCK_RECORDING (as part of fw_attrs init) 1366 + */ 1367 + 1368 + err = galaxybook_acpi_init(galaxybook); 1369 + if (err) 1370 + return dev_err_probe(&galaxybook->platform->dev, err, 1371 + "failed to initialize ACPI device\n"); 1372 + 1373 + err = galaxybook_platform_profile_init(galaxybook); 1374 + if (!err) 1375 + galaxybook->has_performance_mode = true; 1376 + else if (err != GB_NOT_SUPPORTED) 1377 + return dev_err_probe(&galaxybook->platform->dev, err, 1378 + "failed to initialize platform profile\n"); 1379 + 1380 + err = galaxybook_battery_threshold_init(galaxybook); 1381 + if (err) 1382 + return dev_err_probe(&galaxybook->platform->dev, err, 1383 + "failed to initialize battery threshold\n"); 1384 + 1385 + err = galaxybook_kbd_backlight_init(galaxybook); 1386 + if (!err) 1387 + galaxybook->has_kbd_backlight = true; 1388 + else if (err != GB_NOT_SUPPORTED) 1389 + return dev_err_probe(&galaxybook->platform->dev, err, 1390 + "failed to initialize kbd_backlight\n"); 1391 + 1392 + err = galaxybook_fw_attrs_init(galaxybook); 1393 + if (err) 1394 + return dev_err_probe(&galaxybook->platform->dev, err, 1395 + "failed to initialize firmware-attributes\n"); 1396 + 1397 + err = galaxybook_i8042_filter_install(galaxybook); 1398 + if (err) 1399 + return dev_err_probe(&galaxybook->platform->dev, err, 1400 + "failed to initialize i8042_filter\n"); 1401 + 1402 + return 0; 1403 + } 1404 + 1405 + static const struct acpi_device_id galaxybook_device_ids[] = { 1406 + { "SAM0427" }, 1407 + { "SAM0428" }, 1408 + { "SAM0429" }, 1409 + { "SAM0430" }, 1410 + {} 1411 + }; 1412 + MODULE_DEVICE_TABLE(acpi, galaxybook_device_ids); 1413 + 1414 + static struct platform_driver galaxybook_platform_driver = { 1415 + .driver = { 1416 + .name = DRIVER_NAME, 1417 + .acpi_match_table = galaxybook_device_ids, 1418 + }, 1419 + .probe = galaxybook_probe, 1420 + }; 1421 + module_platform_driver(galaxybook_platform_driver); 1422 + 1423 + MODULE_AUTHOR("Joshua Grisham <josh@joshuagrisham.com>"); 1424 + MODULE_DESCRIPTION("Samsung Galaxy Book driver"); 1425 + MODULE_LICENSE("GPL");
+24 -27
drivers/platform/x86/think-lmi.c
··· 262 262 return 0; 263 263 } 264 264 265 - /* Extract output string from WMI return buffer */ 266 - static int tlmi_extract_output_string(const struct acpi_buffer *output, 267 - char **string) 265 + /* Extract output string from WMI return value */ 266 + static int tlmi_extract_output_string(union acpi_object *obj, char **string) 268 267 { 269 - const union acpi_object *obj; 270 268 char *s; 271 269 272 - obj = output->pointer; 273 - if (!obj) 274 - return -ENOMEM; 275 270 if (obj->type != ACPI_TYPE_STRING || !obj->string.pointer) 276 271 return -EIO; 277 272 ··· 344 349 return ret; 345 350 } 346 351 347 - static int tlmi_setting(int item, char **value, const char *guid_string) 352 + static int tlmi_setting(struct wmi_device *wdev, int item, char **value) 348 353 { 349 - struct acpi_buffer output = { ACPI_ALLOCATE_BUFFER, NULL }; 350 - acpi_status status; 354 + union acpi_object *obj; 351 355 int ret; 352 356 353 - status = wmi_query_block(guid_string, item, &output); 354 - if (ACPI_FAILURE(status)) { 355 - kfree(output.pointer); 357 + obj = wmidev_block_query(wdev, item); 358 + if (!obj) 356 359 return -EIO; 357 - } 358 360 359 - ret = tlmi_extract_output_string(&output, value); 360 - kfree(output.pointer); 361 + ret = tlmi_extract_output_string(obj, value); 362 + kfree(obj); 363 + 361 364 return ret; 362 365 } 363 366 ··· 363 370 { 364 371 const struct acpi_buffer input = { strlen(item), (char *)item }; 365 372 struct acpi_buffer output = { ACPI_ALLOCATE_BUFFER, NULL }; 373 + union acpi_object *obj; 366 374 acpi_status status; 367 375 int ret; 368 376 369 377 status = wmi_evaluate_method(LENOVO_GET_BIOS_SELECTIONS_GUID, 370 378 0, 0, &input, &output); 371 - 372 - if (ACPI_FAILURE(status)) { 373 - kfree(output.pointer); 379 + if (ACPI_FAILURE(status)) 374 380 return -EIO; 375 - } 376 381 377 - ret = tlmi_extract_output_string(&output, value); 378 - kfree(output.pointer); 382 + obj = output.pointer; 383 + if (!obj) 384 + return -ENODATA; 385 + 386 + ret = tlmi_extract_output_string(obj, value); 387 + kfree(obj); 388 + 379 389 return ret; 380 390 } 381 391 ··· 989 993 char *item, *value; 990 994 int ret; 991 995 992 - ret = tlmi_setting(setting->index, &item, LENOVO_BIOS_SETTING_GUID); 996 + ret = tlmi_setting(setting->wdev, setting->index, &item); 993 997 if (ret) 994 998 return ret; 995 999 ··· 1582 1586 return new_pwd; 1583 1587 } 1584 1588 1585 - static int tlmi_analyze(void) 1589 + static int tlmi_analyze(struct wmi_device *wdev) 1586 1590 { 1587 1591 int i, ret; 1588 1592 ··· 1619 1623 char *item = NULL; 1620 1624 1621 1625 tlmi_priv.setting[i] = NULL; 1622 - ret = tlmi_setting(i, &item, LENOVO_BIOS_SETTING_GUID); 1626 + ret = tlmi_setting(wdev, i, &item); 1623 1627 if (ret) 1624 1628 break; 1625 1629 if (!item) ··· 1642 1646 kfree(item); 1643 1647 goto fail_clear_attr; 1644 1648 } 1649 + setting->wdev = wdev; 1645 1650 setting->index = i; 1646 1651 strscpy(setting->display_name, item); 1647 1652 /* If BIOS selections supported, load those */ ··· 1661 1664 */ 1662 1665 char *optitem, *optstart, *optend; 1663 1666 1664 - if (!tlmi_setting(setting->index, &optitem, LENOVO_BIOS_SETTING_GUID)) { 1667 + if (!tlmi_setting(setting->wdev, setting->index, &optitem)) { 1665 1668 optstart = strstr(optitem, "[Optional:"); 1666 1669 if (optstart) { 1667 1670 optstart += strlen("[Optional:"); ··· 1786 1789 { 1787 1790 int ret; 1788 1791 1789 - ret = tlmi_analyze(); 1792 + ret = tlmi_analyze(wdev); 1790 1793 if (ret) 1791 1794 return ret; 1792 1795
+2
drivers/platform/x86/think-lmi.h
··· 4 4 #define _THINK_LMI_H_ 5 5 6 6 #include <linux/types.h> 7 + #include <linux/wmi.h> 7 8 8 9 #define TLMI_SETTINGS_COUNT 256 9 10 #define TLMI_SETTINGS_MAXLEN 512 ··· 88 87 /* Attribute setting details */ 89 88 struct tlmi_attr_setting { 90 89 struct kobject kobj; 90 + struct wmi_device *wdev; 91 91 int index; 92 92 char display_name[TLMI_SETTINGS_MAXLEN]; 93 93 char *possible_values;
+82 -103
drivers/platform/x86/thinkpad_acpi.c
··· 39 39 #include <linux/bitops.h> 40 40 #include <linux/delay.h> 41 41 #include <linux/dmi.h> 42 - #include <linux/fb.h> 43 42 #include <linux/freezer.h> 44 43 #include <linux/hwmon.h> 45 44 #include <linux/hwmon-sysfs.h> ··· 367 368 u32 beep_needs_two_args:1; 368 369 u32 mixer_no_level_control:1; 369 370 u32 battery_force_primary:1; 370 - u32 input_device_registered:1; 371 - u32 platform_drv_registered:1; 372 - u32 sensors_pdrv_registered:1; 373 371 u32 hotkey_poll_active:1; 374 372 u32 has_adaptive_kbd:1; 375 373 u32 kbd_lang:1; ··· 8509 8513 if (fan_watchdog_maxinterval > 0 && 8510 8514 tpacpi_lifecycle != TPACPI_LIFE_EXITING) 8511 8515 mod_delayed_work(tpacpi_wq, &fan_watchdog_task, 8512 - msecs_to_jiffies(fan_watchdog_maxinterval * 1000)); 8516 + secs_to_jiffies(fan_watchdog_maxinterval)); 8513 8517 else 8514 8518 cancel_delayed_work(&fan_watchdog_task); 8515 8519 } ··· 11813 11817 11814 11818 static void thinkpad_acpi_module_exit(void) 11815 11819 { 11816 - struct ibm_struct *ibm, *itmp; 11817 - 11818 11820 tpacpi_lifecycle = TPACPI_LIFE_EXITING; 11819 11821 11820 - if (tpacpi_hwmon) 11821 - hwmon_device_unregister(tpacpi_hwmon); 11822 - if (tp_features.sensors_pdrv_registered) 11822 + if (tpacpi_sensors_pdev) { 11823 11823 platform_driver_unregister(&tpacpi_hwmon_pdriver); 11824 - if (tp_features.platform_drv_registered) 11825 - platform_driver_unregister(&tpacpi_pdriver); 11826 - 11827 - list_for_each_entry_safe_reverse(ibm, itmp, 11828 - &tpacpi_all_drivers, 11829 - all_drivers) { 11830 - ibm_exit(ibm); 11831 - } 11832 - 11833 - dbg_printk(TPACPI_DBG_INIT, "finished subdriver exit path...\n"); 11834 - 11835 - if (tpacpi_inputdev) { 11836 - if (tp_features.input_device_registered) 11837 - input_unregister_device(tpacpi_inputdev); 11838 - else 11839 - input_free_device(tpacpi_inputdev); 11840 - } 11841 - 11842 - if (tpacpi_sensors_pdev) 11843 11824 platform_device_unregister(tpacpi_sensors_pdev); 11844 - if (tpacpi_pdev) 11825 + } 11826 + 11827 + if (tpacpi_pdev) { 11828 + platform_driver_unregister(&tpacpi_pdriver); 11845 11829 platform_device_unregister(tpacpi_pdev); 11830 + } 11831 + 11846 11832 if (proc_dir) 11847 11833 remove_proc_entry(TPACPI_PROC_DIR, acpi_root_dir); 11848 11834 if (tpacpi_wq) ··· 11836 11858 kfree(thinkpad_id.nummodel_str); 11837 11859 } 11838 11860 11861 + static void tpacpi_subdrivers_release(void *data) 11862 + { 11863 + struct ibm_struct *ibm, *itmp; 11864 + 11865 + list_for_each_entry_safe_reverse(ibm, itmp, &tpacpi_all_drivers, all_drivers) 11866 + ibm_exit(ibm); 11867 + 11868 + dbg_printk(TPACPI_DBG_INIT, "finished subdriver exit path...\n"); 11869 + } 11870 + 11871 + static int __init tpacpi_pdriver_probe(struct platform_device *pdev) 11872 + { 11873 + int ret; 11874 + 11875 + ret = devm_mutex_init(&pdev->dev, &tpacpi_inputdev_send_mutex); 11876 + if (ret) 11877 + return ret; 11878 + 11879 + tpacpi_inputdev = devm_input_allocate_device(&pdev->dev); 11880 + if (!tpacpi_inputdev) 11881 + return -ENOMEM; 11882 + 11883 + tpacpi_inputdev->name = "ThinkPad Extra Buttons"; 11884 + tpacpi_inputdev->phys = TPACPI_DRVR_NAME "/input0"; 11885 + tpacpi_inputdev->id.bustype = BUS_HOST; 11886 + tpacpi_inputdev->id.vendor = thinkpad_id.vendor; 11887 + tpacpi_inputdev->id.product = TPACPI_HKEY_INPUT_PRODUCT; 11888 + tpacpi_inputdev->id.version = TPACPI_HKEY_INPUT_VERSION; 11889 + tpacpi_inputdev->dev.parent = &tpacpi_pdev->dev; 11890 + 11891 + /* Init subdriver dependencies */ 11892 + tpacpi_detect_brightness_capabilities(); 11893 + 11894 + /* Init subdrivers */ 11895 + for (unsigned int i = 0; i < ARRAY_SIZE(ibms_init); i++) { 11896 + ret = ibm_init(&ibms_init[i]); 11897 + if (ret >= 0 && *ibms_init[i].param) 11898 + ret = ibms_init[i].data->write(ibms_init[i].param); 11899 + if (ret < 0) { 11900 + tpacpi_subdrivers_release(NULL); 11901 + return ret; 11902 + } 11903 + } 11904 + 11905 + ret = devm_add_action_or_reset(&pdev->dev, tpacpi_subdrivers_release, NULL); 11906 + if (ret) 11907 + return ret; 11908 + 11909 + ret = input_register_device(tpacpi_inputdev); 11910 + if (ret < 0) 11911 + pr_err("unable to register input device\n"); 11912 + 11913 + return ret; 11914 + } 11915 + 11916 + static int __init tpacpi_hwmon_pdriver_probe(struct platform_device *pdev) 11917 + { 11918 + tpacpi_hwmon = devm_hwmon_device_register_with_groups( 11919 + &tpacpi_sensors_pdev->dev, TPACPI_NAME, NULL, tpacpi_hwmon_groups); 11920 + 11921 + if (IS_ERR(tpacpi_hwmon)) 11922 + pr_err("unable to register hwmon device\n"); 11923 + 11924 + return PTR_ERR_OR_ZERO(tpacpi_hwmon); 11925 + } 11839 11926 11840 11927 static int __init thinkpad_acpi_module_init(void) 11841 11928 { 11842 11929 const struct dmi_system_id *dmi_id; 11843 - int ret, i; 11930 + int ret; 11844 11931 acpi_object_type obj_type; 11845 11932 11846 11933 tpacpi_lifecycle = TPACPI_LIFE_INIT; ··· 11965 11922 tp_features.quirks = dmi_id->driver_data; 11966 11923 11967 11924 /* Device initialization */ 11968 - tpacpi_pdev = platform_device_register_simple(TPACPI_DRVR_NAME, PLATFORM_DEVID_NONE, 11969 - NULL, 0); 11925 + tpacpi_pdev = platform_create_bundle(&tpacpi_pdriver, tpacpi_pdriver_probe, 11926 + NULL, 0, NULL, 0); 11970 11927 if (IS_ERR(tpacpi_pdev)) { 11971 11928 ret = PTR_ERR(tpacpi_pdev); 11972 11929 tpacpi_pdev = NULL; 11973 - pr_err("unable to register platform device\n"); 11930 + pr_err("unable to register platform device/driver bundle\n"); 11974 11931 thinkpad_acpi_module_exit(); 11975 11932 return ret; 11976 11933 } 11977 - tpacpi_sensors_pdev = platform_device_register_simple( 11978 - TPACPI_HWMON_DRVR_NAME, 11979 - PLATFORM_DEVID_NONE, NULL, 0); 11934 + 11935 + tpacpi_sensors_pdev = platform_create_bundle(&tpacpi_hwmon_pdriver, 11936 + tpacpi_hwmon_pdriver_probe, 11937 + NULL, 0, NULL, 0); 11980 11938 if (IS_ERR(tpacpi_sensors_pdev)) { 11981 11939 ret = PTR_ERR(tpacpi_sensors_pdev); 11982 11940 tpacpi_sensors_pdev = NULL; 11983 - pr_err("unable to register hwmon platform device\n"); 11941 + pr_err("unable to register hwmon platform device/driver bundle\n"); 11984 11942 thinkpad_acpi_module_exit(); 11985 11943 return ret; 11986 - } 11987 - 11988 - mutex_init(&tpacpi_inputdev_send_mutex); 11989 - tpacpi_inputdev = input_allocate_device(); 11990 - if (!tpacpi_inputdev) { 11991 - thinkpad_acpi_module_exit(); 11992 - return -ENOMEM; 11993 - } else { 11994 - /* Prepare input device, but don't register */ 11995 - tpacpi_inputdev->name = "ThinkPad Extra Buttons"; 11996 - tpacpi_inputdev->phys = TPACPI_DRVR_NAME "/input0"; 11997 - tpacpi_inputdev->id.bustype = BUS_HOST; 11998 - tpacpi_inputdev->id.vendor = thinkpad_id.vendor; 11999 - tpacpi_inputdev->id.product = TPACPI_HKEY_INPUT_PRODUCT; 12000 - tpacpi_inputdev->id.version = TPACPI_HKEY_INPUT_VERSION; 12001 - tpacpi_inputdev->dev.parent = &tpacpi_pdev->dev; 12002 - } 12003 - 12004 - /* Init subdriver dependencies */ 12005 - tpacpi_detect_brightness_capabilities(); 12006 - 12007 - /* Init subdrivers */ 12008 - for (i = 0; i < ARRAY_SIZE(ibms_init); i++) { 12009 - ret = ibm_init(&ibms_init[i]); 12010 - if (ret >= 0 && *ibms_init[i].param) 12011 - ret = ibms_init[i].data->write(ibms_init[i].param); 12012 - if (ret < 0) { 12013 - thinkpad_acpi_module_exit(); 12014 - return ret; 12015 - } 12016 11944 } 12017 11945 12018 11946 tpacpi_lifecycle = TPACPI_LIFE_RUNNING; 12019 - 12020 - ret = platform_driver_register(&tpacpi_pdriver); 12021 - if (ret) { 12022 - pr_err("unable to register main platform driver\n"); 12023 - thinkpad_acpi_module_exit(); 12024 - return ret; 12025 - } 12026 - tp_features.platform_drv_registered = 1; 12027 - 12028 - ret = platform_driver_register(&tpacpi_hwmon_pdriver); 12029 - if (ret) { 12030 - pr_err("unable to register hwmon platform driver\n"); 12031 - thinkpad_acpi_module_exit(); 12032 - return ret; 12033 - } 12034 - tp_features.sensors_pdrv_registered = 1; 12035 - 12036 - tpacpi_hwmon = hwmon_device_register_with_groups( 12037 - &tpacpi_sensors_pdev->dev, TPACPI_NAME, NULL, tpacpi_hwmon_groups); 12038 - if (IS_ERR(tpacpi_hwmon)) { 12039 - ret = PTR_ERR(tpacpi_hwmon); 12040 - tpacpi_hwmon = NULL; 12041 - pr_err("unable to register hwmon device\n"); 12042 - thinkpad_acpi_module_exit(); 12043 - return ret; 12044 - } 12045 - 12046 - ret = input_register_device(tpacpi_inputdev); 12047 - if (ret < 0) { 12048 - pr_err("unable to register input device\n"); 12049 - thinkpad_acpi_module_exit(); 12050 - return ret; 12051 - } else { 12052 - tp_features.input_device_registered = 1; 12053 - } 12054 11947 12055 11948 return 0; 12056 11949 }
+78 -65
drivers/platform/x86/wmi.c
··· 123 123 return NULL; 124 124 } 125 125 126 - static acpi_status wmi_method_enable(struct wmi_block *wblock, bool enable) 127 - { 128 - struct guid_block *block; 129 - char method[5]; 130 - acpi_status status; 131 - acpi_handle handle; 132 - 133 - block = &wblock->gblock; 134 - handle = wblock->acpi_device->handle; 135 - 136 - snprintf(method, 5, "WE%02X", block->notify_id); 137 - status = acpi_execute_simple_method(handle, method, enable); 138 - if (status == AE_NOT_FOUND) 139 - return AE_OK; 140 - 141 - return status; 142 - } 143 - 144 126 #define WMI_ACPI_METHOD_NAME_SIZE 5 145 127 146 128 static inline void get_acpi_method_name(const struct wmi_block *wblock, ··· 165 183 } 166 184 167 185 static const struct bus_type wmi_bus_type; 186 + 187 + static const struct device_type wmi_type_event; 188 + 189 + static const struct device_type wmi_type_method; 190 + 191 + static int wmi_device_enable(struct wmi_device *wdev, bool enable) 192 + { 193 + struct wmi_block *wblock = container_of(wdev, struct wmi_block, dev); 194 + char method[WMI_ACPI_METHOD_NAME_SIZE]; 195 + acpi_handle handle; 196 + acpi_status status; 197 + 198 + if (!(wblock->gblock.flags & ACPI_WMI_EXPENSIVE)) 199 + return 0; 200 + 201 + if (wblock->dev.dev.type == &wmi_type_method) 202 + return 0; 203 + 204 + if (wblock->dev.dev.type == &wmi_type_event) 205 + snprintf(method, sizeof(method), "WE%02X", wblock->gblock.notify_id); 206 + else 207 + get_acpi_method_name(wblock, 'C', method); 208 + 209 + /* 210 + * Not all WMI devices marked as expensive actually implement the 211 + * necessary ACPI method. Ignore this missing ACPI method to match 212 + * the behaviour of the Windows driver. 213 + */ 214 + status = acpi_get_handle(wblock->acpi_device->handle, method, &handle); 215 + if (ACPI_FAILURE(status)) 216 + return 0; 217 + 218 + status = acpi_execute_simple_method(handle, NULL, enable); 219 + if (ACPI_FAILURE(status)) 220 + return -EIO; 221 + 222 + return 0; 223 + } 168 224 169 225 static struct wmi_device *wmi_find_device_by_guid(const char *guid_string) 170 226 { ··· 357 337 { 358 338 struct guid_block *block; 359 339 acpi_handle handle; 360 - acpi_status status, wc_status = AE_ERROR; 361 340 struct acpi_object_list input; 362 341 union acpi_object wq_params[1]; 363 - char wc_method[WMI_ACPI_METHOD_NAME_SIZE]; 364 342 char method[WMI_ACPI_METHOD_NAME_SIZE]; 365 343 366 344 if (!out) ··· 382 364 if (instance == 0 && test_bit(WMI_READ_TAKES_NO_ARGS, &wblock->flags)) 383 365 input.count = 0; 384 366 385 - /* 386 - * If ACPI_WMI_EXPENSIVE, call the relevant WCxx method first to 387 - * enable collection. 388 - */ 389 - if (block->flags & ACPI_WMI_EXPENSIVE) { 390 - get_acpi_method_name(wblock, 'C', wc_method); 391 - 392 - /* 393 - * Some GUIDs break the specification by declaring themselves 394 - * expensive, but have no corresponding WCxx method. So we 395 - * should not fail if this happens. 396 - */ 397 - wc_status = acpi_execute_simple_method(handle, wc_method, 1); 398 - } 399 - 400 367 get_acpi_method_name(wblock, 'Q', method); 401 - status = acpi_evaluate_object(handle, method, &input, out); 402 368 403 - /* 404 - * If ACPI_WMI_EXPENSIVE, call the relevant WCxx method, even if 405 - * the WQxx method failed - we should disable collection anyway. 406 - */ 407 - if ((block->flags & ACPI_WMI_EXPENSIVE) && ACPI_SUCCESS(wc_status)) { 408 - /* 409 - * Ignore whether this WCxx call succeeds or not since 410 - * the previously executed WQxx method call might have 411 - * succeeded, and returning the failing status code 412 - * of this call would throw away the result of the WQxx 413 - * call, potentially leaking memory. 414 - */ 415 - acpi_execute_simple_method(handle, wc_method, 0); 416 - } 417 - 418 - return status; 369 + return acpi_evaluate_object(handle, method, &input, out); 419 370 } 420 371 421 372 /** ··· 408 421 if (IS_ERR(wdev)) 409 422 return AE_ERROR; 410 423 424 + if (wmi_device_enable(wdev, true) < 0) 425 + dev_warn(&wdev->dev, "Failed to enable device\n"); 426 + 411 427 wblock = container_of(wdev, struct wmi_block, dev); 412 428 status = __query_block(wblock, instance, out); 429 + 430 + if (wmi_device_enable(wdev, false) < 0) 431 + dev_warn(&wdev->dev, "Failed to disable device\n"); 413 432 414 433 wmi_device_put(wdev); 415 434 ··· 463 470 if (IS_ERR(wdev)) 464 471 return AE_ERROR; 465 472 473 + if (wmi_device_enable(wdev, true) < 0) 474 + dev_warn(&wdev->dev, "Failed to enable device\n"); 475 + 466 476 status = wmidev_block_set(wdev, instance, in); 477 + 478 + if (wmi_device_enable(wdev, false) < 0) 479 + dev_warn(&wdev->dev, "Failed to disable device\n"); 480 + 467 481 wmi_device_put(wdev); 468 482 469 483 return status; ··· 551 551 wblock->handler = handler; 552 552 wblock->handler_data = data; 553 553 554 - if (ACPI_FAILURE(wmi_method_enable(wblock, true))) 554 + if (wmi_device_enable(wdev, true) < 0) 555 555 dev_warn(&wblock->dev.dev, "Failed to enable device\n"); 556 556 557 557 status = AE_OK; ··· 588 588 if (!wblock->handler) { 589 589 status = AE_NULL_ENTRY; 590 590 } else { 591 - if (ACPI_FAILURE(wmi_method_enable(wblock, false))) 591 + if (wmi_device_enable(wdev, false) < 0) 592 592 dev_warn(&wblock->dev.dev, "Failed to disable device\n"); 593 593 594 594 wblock->handler = NULL; ··· 821 821 return 0; 822 822 } 823 823 824 + static void wmi_dev_disable(void *data) 825 + { 826 + struct device *dev = data; 827 + 828 + if (wmi_device_enable(to_wmi_device(dev), false) < 0) 829 + dev_warn(dev, "Failed to disable device\n"); 830 + } 831 + 824 832 static int wmi_dev_probe(struct device *dev) 825 833 { 826 834 struct wmi_block *wblock = dev_to_wblock(dev); 827 835 struct wmi_driver *wdriver = to_wmi_driver(dev->driver); 828 - int ret = 0; 836 + int ret; 829 837 830 838 /* Some older WMI drivers will break if instantiated multiple times, 831 839 * so they are blocked from probing WMI devices with a duplicated GUID. ··· 852 844 return -ENODEV; 853 845 } 854 846 855 - if (ACPI_FAILURE(wmi_method_enable(wblock, true))) 847 + if (wmi_device_enable(to_wmi_device(dev), true) < 0) 856 848 dev_warn(dev, "failed to enable device -- probing anyway\n"); 849 + 850 + /* 851 + * We have to make sure that all devres-managed resources are released first because 852 + * some might still want to access the underlying WMI device. 853 + */ 854 + ret = devm_add_action_or_reset(dev, wmi_dev_disable, dev); 855 + if (ret < 0) 856 + return ret; 857 857 858 858 if (wdriver->probe) { 859 859 ret = wdriver->probe(to_wmi_device(dev), 860 860 find_guid_context(wblock, wdriver)); 861 - if (ret) { 862 - if (ACPI_FAILURE(wmi_method_enable(wblock, false))) 863 - dev_warn(dev, "Failed to disable device\n"); 864 - 861 + if (ret) 865 862 return ret; 866 - } 867 863 } 868 864 869 865 down_write(&wblock->notify_lock); ··· 888 876 889 877 if (wdriver->remove) 890 878 wdriver->remove(to_wmi_device(dev)); 891 - 892 - if (ACPI_FAILURE(wmi_method_enable(wblock, false))) 893 - dev_warn(dev, "failed to disable device\n"); 894 879 } 895 880 896 881 static void wmi_dev_shutdown(struct device *dev) ··· 911 902 if (wdriver->shutdown) 912 903 wdriver->shutdown(to_wmi_device(dev)); 913 904 914 - if (ACPI_FAILURE(wmi_method_enable(wblock, false))) 905 + /* 906 + * We still need to disable the WMI device here since devres-managed resources 907 + * like wmi_dev_disable() will not be release during shutdown. 908 + */ 909 + if (wmi_device_enable(to_wmi_device(dev), false) < 0) 915 910 dev_warn(dev, "Failed to disable device\n"); 916 911 } 917 912 }
+1
drivers/platform/x86/x86-android-tablets/Kconfig
··· 10 10 depends on ACPI && EFI && PCI 11 11 select NEW_LEDS 12 12 select LEDS_CLASS 13 + select POWER_SUPPLY 13 14 help 14 15 X86 tablets which ship with Android as (part of) the factory image 15 16 typically have various problems with their DSDTs. The factory kernels
+79
include/linux/platform_data/huawei-gaokun-ec.h
··· 1 + // SPDX-License-Identifier: GPL-2.0-only 2 + /* 3 + * Huawei Matebook E Go Embedded Controller 4 + * 5 + * Copyright (C) 2024-2025 Pengyu Luo <mitltlatltl@gmail.com> 6 + */ 7 + 8 + #ifndef __HUAWEI_GAOKUN_EC_H__ 9 + #define __HUAWEI_GAOKUN_EC_H__ 10 + 11 + #define GAOKUN_UCSI_CCI_SIZE 4 12 + #define GAOKUN_UCSI_MSGI_SIZE 16 13 + #define GAOKUN_UCSI_READ_SIZE (GAOKUN_UCSI_CCI_SIZE + GAOKUN_UCSI_MSGI_SIZE) 14 + #define GAOKUN_UCSI_WRITE_SIZE 24 /* 8B CTRL, 16B MSGO */ 15 + 16 + #define GAOKUN_UCSI_NO_PORT_UPDATE (-1) 17 + 18 + #define GAOKUN_SMART_CHARGE_DATA_SIZE 4 /* mode, delay, start, end */ 19 + 20 + /* -------------------------------------------------------------------------- */ 21 + 22 + struct gaokun_ec; 23 + struct gaokun_ucsi_reg; 24 + struct notifier_block; 25 + 26 + #define GAOKUN_MOD_NAME "huawei_gaokun_ec" 27 + #define GAOKUN_DEV_PSY "psy" 28 + #define GAOKUN_DEV_UCSI "ucsi" 29 + 30 + /* -------------------------------------------------------------------------- */ 31 + /* Common API */ 32 + 33 + int gaokun_ec_register_notify(struct gaokun_ec *ec, 34 + struct notifier_block *nb); 35 + void gaokun_ec_unregister_notify(struct gaokun_ec *ec, 36 + struct notifier_block *nb); 37 + 38 + int gaokun_ec_read(struct gaokun_ec *ec, const u8 *req, 39 + size_t resp_len, u8 *resp); 40 + int gaokun_ec_write(struct gaokun_ec *ec, const u8 *req); 41 + int gaokun_ec_read_byte(struct gaokun_ec *ec, const u8 *req, u8 *byte); 42 + 43 + /* -------------------------------------------------------------------------- */ 44 + /* API for PSY */ 45 + 46 + int gaokun_ec_psy_multi_read(struct gaokun_ec *ec, u8 reg, 47 + size_t resp_len, u8 *resp); 48 + 49 + static inline int gaokun_ec_psy_read_byte(struct gaokun_ec *ec, 50 + u8 reg, u8 *byte) 51 + { 52 + return gaokun_ec_psy_multi_read(ec, reg, sizeof(*byte), byte); 53 + } 54 + 55 + static inline int gaokun_ec_psy_read_word(struct gaokun_ec *ec, 56 + u8 reg, u16 *word) 57 + { 58 + return gaokun_ec_psy_multi_read(ec, reg, sizeof(*word), (u8 *)word); 59 + } 60 + 61 + int gaokun_ec_psy_get_smart_charge(struct gaokun_ec *ec, 62 + u8 resp[GAOKUN_SMART_CHARGE_DATA_SIZE]); 63 + int gaokun_ec_psy_set_smart_charge(struct gaokun_ec *ec, 64 + const u8 req[GAOKUN_SMART_CHARGE_DATA_SIZE]); 65 + 66 + int gaokun_ec_psy_get_smart_charge_enable(struct gaokun_ec *ec, bool *on); 67 + int gaokun_ec_psy_set_smart_charge_enable(struct gaokun_ec *ec, bool on); 68 + 69 + /* -------------------------------------------------------------------------- */ 70 + /* API for UCSI */ 71 + 72 + int gaokun_ec_ucsi_read(struct gaokun_ec *ec, u8 resp[GAOKUN_UCSI_READ_SIZE]); 73 + int gaokun_ec_ucsi_write(struct gaokun_ec *ec, 74 + const u8 req[GAOKUN_UCSI_WRITE_SIZE]); 75 + 76 + int gaokun_ec_ucsi_get_reg(struct gaokun_ec *ec, struct gaokun_ucsi_reg *ureg); 77 + int gaokun_ec_ucsi_pan_ack(struct gaokun_ec *ec, int port_id); 78 + 79 + #endif /* __HUAWEI_GAOKUN_EC_H__ */
+1 -1
tools/power/x86/intel-speed-select/Makefile
··· 13 13 # Do not use make's built-in rules 14 14 # (this improves performance and avoids hard-to-debug behaviour); 15 15 MAKEFLAGS += -r 16 - override CFLAGS += -O2 -Wall -g -D_GNU_SOURCE -I$(OUTPUT)include -I/usr/include/libnl3 16 + override CFLAGS += -O2 -Wall -g -D_GNU_SOURCE -I$(OUTPUT)include -I$(shell $(CC) -print-sysroot)/usr/include/libnl3 17 17 override LDFLAGS += -lnl-genl-3 -lnl-3 18 18 19 19 ALL_TARGETS := intel-speed-select
+15 -7
tools/power/x86/intel-speed-select/isst-config.c
··· 16 16 int arg; 17 17 }; 18 18 19 - static const char *version_str = "v1.21"; 19 + static const char *version_str = "v1.22"; 20 20 21 21 static const int supported_api_ver = 3; 22 22 static struct isst_if_platform_info isst_platform_info; ··· 46 46 static int auto_mode; 47 47 static int fact_enable_fail; 48 48 static int cgroupv2; 49 + static int max_pkg_id; 49 50 static int max_die_id; 50 - static int max_punit_id; 51 + static int max_die_id_package_0; 51 52 52 53 /* clos related */ 53 54 static int current_clos = -1; ··· 558 557 if (id.pkg < 0 || id.die < 0 || id.punit < 0) 559 558 continue; 560 559 560 + id.die = id.die % (max_die_id_package_0 + 1); 561 + 561 562 valid_mask[id.pkg][id.die] = 1; 562 563 563 564 if (cpus[id.pkg][id.die][id.punit] == -1) ··· 567 564 } 568 565 569 566 for (i = 0; i < MAX_PACKAGE_COUNT; i++) { 570 - if (max_die_id == max_punit_id) { 567 + if (max_die_id > max_pkg_id) { 571 568 for (k = 0; k < MAX_PUNIT_PER_DIE && k < MAX_DIE_PER_PACKAGE; k++) { 572 569 id.cpu = cpus[i][k][k]; 573 570 id.pkg = i; 574 - id.die = k; 571 + id.die = get_physical_die_id(id.cpu); 575 572 id.punit = k; 576 573 if (isst_is_punit_valid(&id)) 577 574 callback(&id, arg1, arg2, arg3, arg4); ··· 589 586 for (k = 0; k < MAX_PUNIT_PER_DIE; k++) { 590 587 id.cpu = cpus[i][j][k]; 591 588 id.pkg = i; 592 - id.die = j; 589 + if (id.cpu >= 0) 590 + id.die = get_physical_die_id(id.cpu); 591 + else 592 + id.die = id.pkg; 593 593 id.punit = k; 594 594 if (isst_is_punit_valid(&id)) 595 595 callback(&id, arg1, arg2, arg3, arg4); ··· 794 788 cpu_map[i].die_id = die_id; 795 789 cpu_map[i].core_id = core_id; 796 790 791 + if (max_pkg_id < pkg_id) 792 + max_pkg_id = pkg_id; 797 793 798 794 punit_id = 0; 799 795 ··· 820 812 if (max_die_id < die_id) 821 813 max_die_id = die_id; 822 814 823 - if (max_punit_id < cpu_map[i].punit_id) 824 - max_punit_id = cpu_map[i].punit_id; 815 + if (!pkg_id && max_die_id_package_0 < die_id) 816 + max_die_id_package_0 = die_id; 825 817 826 818 debug_printf( 827 819 "map logical_cpu:%d core: %d die:%d pkg:%d punit:%d punit_cpu:%d punit_core:%d\n",
+9 -2
tools/power/x86/intel-speed-select/isst-display.c
··· 173 173 174 174 if (out_format_is_json()) { 175 175 if (api_version() > 1) { 176 - if (id->cpu < 0) 176 + if (id->die < 0 && id->cpu < 0) 177 + snprintf(header, sizeof(header), 178 + "package-%d:die-IO:powerdomain-%d:cpu-None", 179 + id->pkg, id->punit); 180 + else if (id->cpu < 0) 177 181 snprintf(header, sizeof(header), 178 182 "package-%d:die-%d:powerdomain-%d:cpu-None", 179 183 id->pkg, id->die, id->punit); ··· 194 190 } 195 191 snprintf(header, sizeof(header), "package-%d", id->pkg); 196 192 format_and_print(outf, level++, header, NULL); 197 - snprintf(header, sizeof(header), "die-%d", id->die); 193 + if (id->die < 0) 194 + snprintf(header, sizeof(header), "die-IO"); 195 + else 196 + snprintf(header, sizeof(header), "die-%d", id->die); 198 197 format_and_print(outf, level++, header, NULL); 199 198 if (api_version() > 1) { 200 199 snprintf(header, sizeof(header), "powerdomain-%d", id->punit);